2015-11-04 62 views
2

我正试图将ToggleButton上的“IsChecked”属性绑定到“ModelView.IsEnabled”。
“ModelView.IsEnabled”始终为“false”
但按某种方式,ToggleButton仍然可以显示为“已选中”。
绑定有什么问题吗?
enter image description here切换按钮双向绑定不起作用(通用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

尝试使代码'类模型视图代码'public class – thumbmunkeys

+0

使'class ModelView'成为一个公共类仍然没有正确绑定。:/ 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

编辑:如果我使用_isEnabled = !value;如你所说,它仍然有效,使用按钮和状态现在显示相反的价值观:

enter image description here

编辑2:现在,如果你要正确地测试你的绑定,那么你可以添加一个额外的普通按钮,这样做:

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

所以你可以单击Test Button观看每次truefalse之间的ToggleButton开关。请注意,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> 

代码隐藏:

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

请在我的帖子中查看我的编辑2,了解如何正确测试您的“ToggleButton”的绑定。你这样做的方式显然是错误的。你实际上是在破坏你自己的代码...:O) – jsanalytics

+0

谢谢你的编辑。如果我错了,请纠正我。那么在每次clilck之后,'ToggleButton'总是必须从'true到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是只读属性。所以IsChecked可能是你需要的。

0

我遇到了同样的问题,不是ToggleButton,而是TextBox,我想要格式化用户输入的文本。

在你的情况下,你想改变你的viewmodel中的IsChecked属性,并立即反映在用户界面中(所以总是被取消选中)。你想要的原因绝对不重要。

问题是,如果您点击ToggleButton,UWP会调用您的属性的获取方法,就像您期望的那样。 ToggleButton的正常操作是从未检查变为检查(反之亦然),这就是你的情况。但是,你期望NotifyPropetyChanged表示UI中的控件。这就是它出错的地方。当setter执行时(包括NotifyPropertyChanged),getter不会被调用,所以UI并不反映你在setter中做了什么。 这与TwoWay Binding用来做什么(并且仍然在WPF中)完全不同。所以你的代码没有问题,但似乎绑定机制已经改变了,尽管微软声称它没有改变。如果你使用x:Bind,它可以正常工作,所以帽子可以解决你的问题。

为了更清楚地说明一些事情,我已将您的示例稍作修改,以显示问题。 我已经把页面上的一个ToggleButton与TwoWay绑定到视图模型,完全一样。点击ToggleButton会将其状态从已选中状态切换为未选中状态,反之亦然,即使我的viewmodel中的setter始终将该属性设置为false(因此未选中)。 但我还添加了一个普通按钮,我已经绑定到一个命令,该命令还修改了ToggleButton绑定的属性。点击此按钮将调用ToggleButton所绑定的属性上的setter。当然,setter被调用的方式是一样的,但在此之后绑定到ToggleButton被调用,因此在这种情况下NotifyPropertyChanged确实会导致UI更新。

如果你使用调试器,你可以看到我的意思。 所以你的问题可以通过使用x:Bind来解决,或者通过另一种方法来更新UI,如果Binding仍然像以前一样工作,你不应该这么做。也许微软已经实施了一些现在破坏了经典绑定的优化。

没有特别的事情,只是一个MainPage和一个视图模型。

我对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

对不起,如果你认为解释太长,但显然问题不明确,所以试图澄清和解释除了只提到“使用x:绑定”之外正在发生的事情。这是一个非常普遍的问题,而不仅仅是使用ToggleButton。 – P59