2015-11-04 10 views
2

Я пытаюсь связать свойство IsChecked с ToggleButton с «ModelView.IsEnabled».
«ModelView.IsEnabled» всегда «false»
, но как-то ToggleButton все еще может отображаться как «Проверено».
Есть ли что-то не так с привязкой?
enter image description hereToggle Button Двухсторонняя привязка не работает (универсальная платформа Windows)

XAML

... 
<Page.Resources> 
    <ModelView:ModelView x:Key="ModelView"/> 
</Page.Resources> 
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> 
    <ToggleButton IsChecked="{Binding Source={StaticResource ModelView}, Path=IsEnabled, Mode=TwoWay}"> 
     <TextBlock >UWP Toggle Button</TextBlock> 
    </ToggleButton> 
</Grid> 
... 

ModelView.cs

using... 

namespace App2 
{ 
    class ModelView : INotifyPropertyChanged 
    { 
     public event PropertyChangedEventHandler PropertyChanged; 
     public event EventHandler CanExecuteChanged; 

     private bool _isEnabled; 

     public bool IsEnabled 
     { 
      get { 
       return _isEnabled; 
      } 
      set 
      { 
       _isEnabled = false; 
       OnPropertyChanged("IsEnabled"); 
      } 
     } 

     protected void OnPropertyChanged(string name) 
     { 
      PropertyChangedEventHandler handler = PropertyChanged; 
      if (handler != null) 
      { 
       handler(this, new PropertyChangedEventArgs(name)); 
      } 
     } 
    } 
} 
+0

попробовать сделать класс 'ModelView 'public class – thumbmunkeys

+0

Создание класса ClassView в общедоступном классе по-прежнему не является обязательным.:/ ToggleButton все равно переключится на «Проверено». – user3863376

+0

ваш 'set' делает' _isEnabled = false; '.... – jsanalytics

ответ

1

В классе ModelView, изменяющие IsEnabled из этого:

public bool IsEnabled 
    { 
     get { 
      return _isEnabled; 
     } 
     set 
     { 
      _isEnabled = false; 
      OnPropertyChanged("IsEnabled"); 
     } 
    } 

к этому:

public bool IsEnabled 
    { 
     get { 
      return _isEnabled; 
     } 
     set 
     { 
      _isEnabled = value; 
      OnPropertyChanged("IsEnabled"); 
     } 
    } 

enter image description here

EDIT: Если я использую _isEnabled = !value; как вы предложили, он все еще работает, с кнопкой и состояние теперь показывает противоположные значения:

enter image description here

EDIT 2: Теперь, если вы хотите, чтобы должным образом проверить свои привязки, то вы можете добавить дополнительные регулярные кнопки и сделать это:

private void button1_Click(object sender, RoutedEventArgs e) 
    { 
     myModelView.IsEnabled = !myModelView.IsEnabled; 
    } 

так что вы можете смотреть ToggleButton переключаться между true и false каждый раз, когда вы нажимаете Test Button. Обратите внимание, что Test Button не привязан ни к чему, это просто для целей тестирования. См. Соответствующий XAML внизу.

enter image description here

Проблема в том, что так, как вы это делаете, «заставляя» IsEnabled быть всегда false, вы на самом деле саботирует свой собственный код ...: O)

И, наконец, , это не ясно из вашего кода, когда/где вы назначаете свой DataContext. См. Ниже, как это сделать.

XAML:

<Page.DataContext> 
    <local:MyModelView/> 
</Page.DataContext> 

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> 
    <ToggleButton x:Name="toggleButton1" Content="ToggleButton" IsChecked="{Binding IsEnabled, Mode=TwoWay}" HorizontalAlignment="Center"/> 
    <TextBlock x:Name="textBlock1" Text="{Binding IsEnabled}" VerticalAlignment="Bottom" HorizontalAlignment="Center" Margin="126,0,201,286" /> 
    <Button x:Name="button1" Click="button1_Click" Margin="127,400,0,220" Content="Test Button" Height="35" /> 
</Grid> 

Code-за:

private void Page_Loaded(object sender, RoutedEventArgs e) 
    { 
     myModelView = new MyModelView(); 
     this.DataContext = myModelView; 
    } 
+0

Спасибо, но это не проблема, которую я пытаюсь решить. Я пытаюсь понять, почему ToggleButton показывает другое состояние, а затем «ModelView.IsEnabled». Если я изменяю 'IsEnabled' на' set {_isEnabled =! Value; OnPropertyChanged ("IsEnabled"); } 'ToggleButton будет находиться в противоположном состоянии« ModelView.IsEnabled ». Это означает, что привязка к ToggleButton не отражает значение IsEnabled. – user3863376

+0

Пожалуйста, см. Мой «EDIT 2» в своем посте о том, как правильно проверить привязку для «ToggleButton». То, как вы это делаете, просто неверно. Вы на самом деле саботируете свой собственный код ...: O) – jsanalytics

+0

Спасибо за ваши изменения. Пожалуйста, поправьте меня, если я ошибаюсь. Таким образом, 'ToggleButton' всегда должен перейти от' true To false' или 'false To true' после каждого клинка? – user3863376

2

Попробуйте это, он работал со мной: 1.изменения кода XAML:

<Grid> 
    <Grid.DataContext> 
     <soHelpProject:MainViewModel/> 
    </Grid.DataContext> 
    <ToggleButton IsChecked="{Binding IsToggled, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"> 
     <TextBlock >UWP Toggle Button</TextBlock> 
    </ToggleButton> 
</Grid> 

пожеланиями,

+0

Действительно, это также сработало для меня. У вас есть идея, почему? – mamuesstack

0

IsEnabled свойство, указывающее, может ли пользователь взаимодействовать с контролем. IsPressed - свойство readonly. Таким образом, IsChecked, вероятно, то, что вам нужно.

0

Я столкнулся с той же проблемой, будь то не с ToggleButton, а с TextBox, где я хотел отформатировать текст, который пользователь ввел.

В вашем случае вы хотите изменить свойство IsChecked в своей модели просмотра и сразу же отобразить его в пользовательском интерфейсе (так что всегда не снимайте флажок). Причина, по которой вы этого хотите, абсолютно не имеет значения.

Проблема в том, что с UWP получатель получает ваше имя, как вы ожидаете, когда вы нажимаете ToggleButton. Обычным действием для ToggleButton является изменение с непроверенного на проверенное (и наоборот), и это то, что происходит в вашем случае. Но тогда вы ожидаете, что NotifyPropetyChanged сигнализирует управление в пользовательском интерфейсе. И тут все пошло не так. Геттер никогда не вызывается при запуске сеттера (включая NotifyPropertyChanged), поэтому пользовательский интерфейс не отражает то, что вы сделали в своем сеттере. Это сильно отличается от того, что делало TwoWay Binding (и все еще делает это в WPF). Таким образом, в вашем коде нет ничего плохого, но кажется, что механизм привязки изменился, хотя Microsoft утверждает, что это не так. Если вы используете x:Bind, он отлично работает, поэтому шляпа может решить вашу проблему.

Чтобы прояснить ситуацию, я привел ваш пример и немного изменил его, чтобы показать проблему. Я поставил ToggleButton на странице с привязкой TwoWay к viewmodel, точно так же, как вы. Нажатие на ToggleButton переключит свое состояние с отмеченного на непроверенное и наоборот, хотя установщик в моей модели просмотра всегда устанавливает для свойства значение false (поэтому не установлен). Но я также добавил обычную кнопку, которую я привязал к команде, которая также изменяет свойство, к которому привязан ToggleButton. Нажатие этой кнопки вызывает установщика в свойстве, к которому привязан ToggleButton. Конечно, сеттер вызывает одно и то же, но после этого вызывается привязка к ToggleButton, поэтому NotifyPropertyChanged в этом случае вызывает обновление пользовательского интерфейса.

Если вы используете отладчик, вы можете точно видеть, что я имею в виду. Итак, ваша проблема может быть решена с помощью x: Bind или путем выяснения другого способа обновления пользовательского интерфейса, который вам не нужно делать, если Binding все еще работает так, как раньше. Возможно, Microsoft реализовала какую-то оптимизацию, которая теперь уничтожает классическое Binding.

Никаких особых вещей, просто MainPage и viewmodel.

Мой код MainPage.xaml

<Page x:Class="App10.MainPage" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
     xmlns:local="using:App10" 
     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
     mc:Ignorable="d"> 
    <Page.Resources> 
     <local:ViewModel x:Key="viewModel" /> 
    </Page.Resources> 

    <Grid x:Name="mainGrid" Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> 
     <StackPanel Margin="10,20,10,0"> 
      <Button 
       x:Name="Button" 
       Content="UWP Normal button" 
       Command="{Binding Source={StaticResource viewModel}, Path=SwitchIschecked}" 
       HorizontalAlignment="Stretch" /> 
      <ToggleButton 
       x:Name="toggleButton" 
       Margin="0,10,0,0" 
       HorizontalAlignment="Stretch" 
       VerticalAlignment="Top" 
       IsChecked="{Binding Source={StaticResource viewModel}, Path=IsChecked, 
              Mode=TwoWay}"> 
       <TextBlock>UWP Toggle Button</TextBlock> 

      </ToggleButton> 
     </StackPanel> 
    </Grid> 
</Page> 

Код для MainPage.xaml.cs

using Windows.UI.Xaml.Controls; 

// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x409 

namespace App10 
{ 
    /// <summary> 
    /// An empty page that can be used on its own or navigated to within a Frame. 
    /// </summary> 
    public sealed partial class MainPage : Page 
    { 
     public MainPage() 
     { 
      this.InitializeComponent();  
     }  
    } 
} 

И код для ViewModel.cs

using System; 
using System.ComponentModel; 
using System.Runtime.CompilerServices; 
using System.Windows.Input; 

namespace App10 
{ 
    public class ViewModel : INotifyPropertyChanged 
    { 
     private bool _isChecked; 

     // property for TwoWay binding with ToggleButton 
     public bool IsChecked 
     { 
      get 
      { 
       return _isChecked; 
      } 
      set 
      { 
       // extra var just to check 'value' 
       var _value = value; 
       // now always set it to false 
       _isChecked = false; 
       // Try to pass value of _isChecked to user interface 
       // because there is no check whether the value really 
       // has changed 
       // But this only works if the setter is not being called 
       // directly from the control the property is bound to 
       OnPropertyChanged(); 
      } 
     } 

     private ICommand _switchChecked; 

     // ICommand for normal button, binding to Command 
     // calls method to set Property for ToggleButton 
     public ICommand SwitchIschecked 
     { 
      get 
      { 
       if (_switchChecked == null) 
        _switchChecked = new ChangeChecked(new Action(ChangeVar)); 
       return _switchChecked; 
      } 
      set 
      { 
       _switchChecked = value; 
      } 
     } 

     // This will set the property for the ToggleButton 
     private void ChangeVar() 
     { 
      IsChecked = !IsChecked; 
     } 


     public event PropertyChangedEventHandler PropertyChanged; 

     protected void OnPropertyChanged([CallerMemberName] string propertyName = null) 
     { 
      var handler = PropertyChanged; 
      handler?.Invoke(this, new PropertyChangedEventArgs(propertyName)); 
     } 


    } 


    /// <summary> 
    /// Quick class to implement ICommand 
    /// </summary> 
    class ChangeChecked : ICommand 
    { 
     Action _execute; 
     public ChangeChecked(Action execute) 
     { 
      _execute = execute; 
     } 

     public event EventHandler CanExecuteChanged; 

     public bool CanExecute(object parameter) 
     { 
      return true; 
     } 

     public void Execute(object parameter) 
     { 
      _execute(); 
     } 
    } 
} 
+0

Это кажется длинным ответом на поставленный вопрос. Можно ли его отредактировать, чтобы предоставить более сжатый ответ? – Toby

+0

Извините, если вы считаете, что объяснение слишком длинное, но, очевидно, проблема была неясной, поэтому попытался прояснить и объяснить, что происходит, кроме как просто упомянуть «use x: bind». Это гораздо более общая проблема, чем просто с ToggleButton. – P59

Смежные вопросы