【问题标题】:Toggle Button Two Way Binding Not Working (Universal Windows Platform)切换按钮两种方式绑定不起作用(通用 Windows 平台)
【发布时间】:2015-11-04 22:17:44
【问题描述】:

我正在尝试将 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));
            }
        }
    }
}

【问题讨论】:

  • 尝试将class ModelView 设为公开课程
  • class ModelView 设为公共类仍然无法正确绑定。 :/ ToggleButton 仍然会变成“Checked”。
  • 你的set 正在做_isEnabled = false;....
  • 应该是_isEnabled = value;
  • 这并不能解决绑定问题。我尝试添加另一个具有相同绑定的 ToggltButton,它们会显示不同的状态。

标签: c# wpf windows xaml win-universal-app


【解决方案1】:

试试这个,它对我有用: 1、Xaml代码改动:

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

问候,

【讨论】:

  • 确实,它也对我有用。你知道为什么吗?
【解决方案2】:

在您的班级ModelView 中,将IsEnabled 从这里更改为:

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

到这里:

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

编辑:如果我按照您的建议使用_isEnabled = !value;,它仍然有效,按钮和状态现在显示相反的值:

编辑 2:现在,如果您想正确测试您的绑定,那么您可以添加一个额外的常规按钮并执行以下操作:

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

这样您就可以在每次单击Test Button 时看到您的ToggleButtontruefalse 之间切换。请注意Test Button 不绑定任何东西,它只是用于测试目的。见底部对应的 XAML。

问题在于你这样做的方式,“强制”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;
    }

【讨论】:

  • 谢谢,但这不是我要解决的问题。我试图弄清楚为什么 ToggleButton 显示的状态与“ModelView.IsEnabled”不同。如果我将IsEnabled 更改为set{ _isEnabled = !value; OnPropertyChanged("IsEnabled"); },ToggleButton 将处于“ModelView.IsEnabled”的相反状态。这意味着 ToggleButton 上的绑定没有反映 IsEnabled 的值。
  • 请参阅我的帖子中的EDIT 2,了解如何正确测试ToggleButton 的绑定。你这样做的方式是完全错误的。你实际上是在破坏你自己的代码......:O)
  • 感谢您的编辑。如果我错了,请纠正我。所以每次点击后ToggleButton总是必须从true To falsefalse To true去?
  • 不是您的ToggleButton 本身。每当单击 Test Button 时,您的 myModelView.IsEnabled 会在 truefalse 之间切换值。 ToggleButton 只对它做出反应,因为它绑定到 myModelView.IsEnabled
【解决方案3】:

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

在您的情况下,您希望更改视图模型中的 IsChecked 属性并立即将其反映在用户界面中(因此始终不要选中)。你想要那个的原因绝对不重要。

问题在于,使用 UWP 时,当您单击 ToggleButton 时,您的属性的 getter 会像您期望的那样被调用。 ToggleButton 的正常操作是从未选中更改为选中(反之亦然),这就是您的情况。但随后您期望 NotifyPropetyChanged 向 UI 中的控件发出信号。这就是它出错的地方。执行 setter 时永远不会调用 getter(包括 NotifyPropertyChanged),因此 UI 不会反映您在 setter 中所做的事情。 这与 TwoWay Binding 过去所做的(在 WPF 中仍然如此)非常不同。所以你的代码没有问题,但似乎绑定机制已经改变,尽管微软声称它没有。如果您使用x:Bind,它可以正常工作,所以帽子可能会解决您的问题。

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

如果你使用调试器,你可以明白我的意思。 因此,您的问题可以通过使用 x:Bind 或通过找出另一种更新 UI 的方法来解决,如果 Binding 仍然像以前那样工作,您就不必这样做。也许微软已经实施了某种优化,现在破坏了经典的 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();
        }
    }
}

【讨论】:

  • 对于所提出的问题,这似乎是一个很长的答案。可以对其进行编辑以提供更简洁的答案吗?
  • 对不起,如果您认为解释太长但显然问题并不清楚,所以除了提到“使用 x:bind”之外,还试图澄清和解释发生了什么。这是一个比 ToggleButton 更普遍的问题。
  • 谢谢,这个回复终于帮我解决了一个困扰我2个多小时的问题。
【解决方案4】:

IsEnabled 属性表示用户是否可以与控件交互IsPressed 是只读属性。所以 IsChecked 可能就是您所需要的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-08-15
    • 2017-04-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-07
    • 1970-01-01
    相关资源
    最近更新 更多