我正在尝试将ToggleButton上的“IsChecked”属性绑定到“ModelView.IsEnabled”。
“ModelView.IsEnabled”总是“假”
但不知何故,ToggleButton仍然可以显示为“已检查”
绑定有什么问题吗?
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 :(得分: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>
的问候,
答案 1 :(得分:1)
在您的班级buildPrattParser table termP = parser precs where
precs = reverse table
prefixP = choice prefixPs <|> termP where
prefixPs = do
precsR@(ops:_) <- tails precs
Prefix opP <- ops
return $ opP <*> parser precsR
infixP precs lhs = choice infixPs <|> pure lhs where
infixPs = do
precsR@(ops:precsL) <- tails precs
op <- ops
p <- case op of
Infix opP assoc -> do
let p precs = opP <*> pure lhs <*> parser precs
return $ case assoc of
AssocNone -> error "Non associative operators are not supported"
AssocLeft -> p precsL
AssocRight -> p precsR
Postfix opP ->
return $ opP <*> pure lhs
Prefix _ -> mzero
return $ p >>= infixP precs
parser precs = prefixP >>= infixP precs
中,从此处更改ModelView
:
IsEnabled
到此:
public bool IsEnabled
{
get {
return _isEnabled;
}
set
{
_isEnabled = false;
OnPropertyChanged("IsEnabled");
}
}
编辑:如果我按照您的建议使用 public bool IsEnabled
{
get {
return _isEnabled;
}
set
{
_isEnabled = value;
OnPropertyChanged("IsEnabled");
}
}
,它仍然有效,按钮和状态现在显示相反的值:
编辑2 :现在,如果您想正确测试绑定,那么您可以添加一个额外的常规按钮并执行此操作:
_isEnabled = !value;
因此,每次点击 private void button1_Click(object sender, RoutedEventArgs e)
{
myModelView.IsEnabled = !myModelView.IsEnabled;
}
时,您都可以在ToggleButton
和true
之间切换false
。请注意Test Button
不受任何约束,仅用于测试目的。请参阅底部的相应XAML。
问题在于你的方式,“强迫”Test Button
总是IsEnabled
,你实际上在破坏自己的代码...:O)
最后,您的代码在何时/何地分配您的false
时并不清楚。请看下面的操作方法。
XAML:
DataContext
代码隐藏:
<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>
答案 2 :(得分:0)
IsEnabled
属性指示用户是否可以与控件进行交互。 IsPressed
只读属性。所以 IsChecked
可能就是您所需要的。
答案 3 :(得分:0)
我遇到了同样的问题,不管是ToggleButton
,还是TextBox
,我想要格式化用户输入的文字。
在您的情况下,您希望更改视图模型中的IsChecked
属性并立即将其反映在用户界面中(因此始终取消选中)。你想要的原因绝对不重要。
问题在于,使用UWP时,您单击ToggleButton
时会调用属性的getter。 ToggleButton
的正常操作是从未选中更改为已选中(反之亦然),这就是您的情况。但是,您希望NotifyPropetyChanged
表示UI中的控件。那就是出错的地方。执行setter时,getter永远不会被调用(包括NotifyPropertyChanged
),因此UI不能反映你在setter中所做的事情。
这与TwoWay Binding过去做的非常不同(在WPF中仍然如此)。所以你的代码没有任何问题,但似乎绑定机制发生了变化,尽管微软声称它没有。如果你使用x:Bind
,它可以正常工作,所以帽子可以解决你的问题。
为了澄清事情,我已经采取了你的例子并稍微修改了它,以显示问题。
我已经在页面上放置了一个ToggleButton
,其中包含与视图模型的TwoWay绑定,就像您一样。单击ToggleButton
将其状态从已检查切换为未选中,反之亦然,即使我的viewmodel中的setter始终将属性设置为false(因此未选中)。
但是我还添加了一个普通按钮,我已经绑定了一个命令,该命令也修改了ToggleButton
绑定的属性。单击此按钮可调用ToggleButton
绑定的属性上的setter。当然,setter的调用方式是相同的,但之后会调用ToggleButton
的绑定,因此在这种情况下NotifyPropertyChanged
会导致UI更新。
如果你使用调试器,你可以看到我的意思。 所以你的问题可以通过使用x:Bind来解决,或者通过找出另一种更新UI的方法来解决,如果Binding仍然像以前一样工作,你不应该这样做。也许微软已经实现了某种优化,现在破坏了经典的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();
}
}
}