RadioButtons绑定阻止通过命令更改属性

本文关键字:命令 属性 绑定 RadioButtons | 更新日期: 2023-09-27 18:20:54

我的代码的问题是RadioButton的绑定,不允许委托修改属性。委托它更改,绑定后,它将更改为旧值。我需要能够通过命令和RadioButton s更改属性。

<Window.InputBindings>
    <KeyBinding Key="F1" Command="{Binding SomeCommand}"/>
</Window.InputBindings>
<StackPanel>
    <TextBlock Text="{Binding Path=SomeProperty}"/>
    <RadioButton IsChecked="{Binding Path=SomeProperty, Mode=TwoWay, Converter={StaticResource ETBConverter}, ConverterParameter=State1}" Content="State1"/>
    <RadioButton IsChecked="{Binding Path=SomeProperty, Mode=TwoWay, Converter={StaticResource ETBConverter}, ConverterParameter=State2}" Content="State2"/>
</StackPanel>
public enum TestEnum
{
    State1,
    State2,
}
public class TestViewModel : BaseViewModel
{
    private TestEnum _someProperty;
    public TestEnum SomeProperty
    {
        get { return _someProperty; }
        set
        {
            if (_someProperty != value)
            {
                _someProperty = value;
                OnPropertyChanged();
            }
        }
    }
    public Command SomeCommand { get; private set; }
    public TestViewModel()
    {
        _someProperty = TestEnum.State2;
        SomeCommand = new Command(SomeCommand_Execute);
    }
    private void SomeCommand_Execute(object obj)
    {
        SomeProperty = SomeProperty == TestEnum.State1 ? TestEnum.State2 : TestEnum.State1;
    }
}

更新1:

[Localizability(LocalizationCategory.NeverLocalize)]
public class EnumToBooleanConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        string parameterString = parameter as string;
        if (parameterString == null)
            return false;
        if (Enum.IsDefined(value.GetType(), value) == false)
            return false;
        object parameterValue = Enum.Parse(value.GetType(), parameterString);
        return parameterValue.Equals(value);
    }
    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        string parameterString = parameter as string;
        if (parameterString == null)
            return DependencyProperty.UnsetValue;
        return Enum.Parse(targetType, parameterString);
    }
}
public abstract class BaseViewModel : NotifyPropertyChanged
{
    protected Dispatcher UIDispatcher;
    public BaseViewModel()
    {
        UIDispatcher = Dispatcher.CurrentDispatcher;
    }
    protected void InvokeInUIThread(Action action)
    {
        if (Thread.CurrentThread == UIDispatcher.Thread)
            action();
        else
            UIDispatcher.InvokeAsync(action, DispatcherPriority.Send);
    }
}
public abstract class NotifyPropertyChanged : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged([CallerMemberName] String propertyName = "")
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}
public class Command : ICommand
{
    #region Fields
    readonly Action<object> _execute;
    readonly Predicate<object> _canExecute;
    #endregion // Fields
    #region Constructors
    public Command(Action<object> execute)
        : this(execute, null)
    {
    }
    public Command(Action<object> execute, Predicate<object> canExecute)
    {
        if (execute == null)
            throw new ArgumentNullException("execute");
        _execute = execute;
        _canExecute = canExecute;
    }
    #endregion // Constructors
    #region ICommand Members
    public event EventHandler CanExecuteChanged
    {
        add { CommandManager.RequerySuggested += value; }
        remove { CommandManager.RequerySuggested -= value; }
    }
    public bool CanExecute(object parameter)
    {
        return _canExecute == null ? true : _canExecute(parameter);
    }
    public void Execute(object parameter)
    {
        _execute(parameter);
    }
    public void OnCanExecutedChanged()
    {
        CommandManager.InvalidateRequerySuggested();
    }
    #endregion // ICommand Members
}

RadioButtons绑定阻止通过命令更改属性

使用单选按钮列表,它必须比使用转换器更简单,并且可以随心所欲。看看这个答案

我根据您发布的代码创建了下面的应用程序,它运行良好。按F1将TextBlock的Text更改为State1。你可以按原样使用代码。

注意:我没有使用您的ETBConverter,因为我没有代码。我相信这是某种枚举到布尔的转换器。你可以看到我的代码,如果这不能解决你的问题。告诉我你的ETBConverter,我会照顾它。此外,我没有你的BaseViewModel代码,所以我实现了INotifyPropertyChanged接口。

主窗口.xaml

<Window x:Class="WpfCommands.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Window.InputBindings>
        <KeyBinding Key="F1" Command="{Binding SomeCommand}"/>
    </Window.InputBindings>
    <Window.Resources>
    </Window.Resources>
    <StackPanel>
        <TextBlock Text="{Binding Path=SomeProperty}"/>
        <RadioButton IsChecked="{Binding Path=SomeProperty, Mode=TwoWay}" Content="State1"/>
        <RadioButton IsChecked="{Binding Path=SomeProperty, Mode=TwoWay}" Content="State2"/>
    </StackPanel>
</Window>

主窗口.xaml.cs

using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
namespace WpfCommands
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            this.DataContext = new TestViewModel();
        }
    }
    public enum TestEnum
    {
        State1,
        State2,
    }
    public class TestViewModel : INotifyPropertyChanged
    {
        private TestEnum _someProperty;
        public TestEnum SomeProperty
        {
            get { return _someProperty; }
            set
            {
                if (_someProperty != value)
                {
                    _someProperty = value;
                    OnPropertyChanged("SomeProperty");
                }
            }
        }
        public Command SomeCommand { get; private set; }
        public TestViewModel()
        {
            _someProperty = TestEnum.State2;
            SomeCommand = new Command(SomeCommand_Execute);
        }
        private void SomeCommand_Execute(object obj)
        {
            SomeProperty = SomeProperty == TestEnum.State1 ? TestEnum.State2 : TestEnum.State1;
            System.Diagnostics.Debug.WriteLine("------------- executed ---------------");
        }
        public event PropertyChangedEventHandler PropertyChanged;
        public void OnPropertyChanged(string propname)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propname));
        }
    }
    public class Command : ICommand
    {
        public delegate void CommandExecuteHandler(object obj);
        CommandExecuteHandler handler;
        public Command(CommandExecuteHandler callback)
        {
            handler = callback;
        }
        public bool CanExecute(object parameter)
        {
            return true;
        }
        public event EventHandler CanExecuteChanged;
        public void Execute(object parameter)
        {
            handler(parameter);
        }
    }
}

EnumToBooleanCoverter.ConvertBack().中出现错误

public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
    if ((bool)value)
    {
        string parameterString = parameter as string;
        if (parameterString == null)
            return DependencyProperty.UnsetValue;
        return Enum.Parse(targetType, parameterString);
    }
    else
        return DependencyProperty.UnsetValue;
}

使用扩展会更好

public class TestEnumExtension : TypedValueExtension<TestEnum>
{
    public TestEnumExtension(TestEnum value) : base(value) { }
}
public class TypedValueExtension<T> : MarkupExtension
{
    public TypedValueExtension(T value) { Value = value; }
    public T Value { get; set; }
    public override object ProvideValue(IServiceProvider sp) { return Value; }
}

新的EnumToBolleanConverter

public class EnumToBooleanConverter : IValueConverter
{
    public object Convert(
        object value, Type targetType, object parameter, CultureInfo culture)
    {
        return (TestEnum)value == (TestEnum)parameter;
    }
    public object ConvertBack(
        object value, Type targetType, object parameter, CultureInfo culture)
    {
        if ((bool)value)
            return parameter;
        else
            return DependencyProperty.UnsetValue;
    }
}

和XAML

<RadioButton IsChecked="{Binding Path=SomeProperty, Mode=TwoWay, 
    Converter={StaticResource ETBConverter}, ConverterParameter={exten:TestEnum State1}}"
             Content="State1"/>
<RadioButton IsChecked="{Binding Path=SomeProperty, Mode=TwoWay, 
    Converter={StaticResource ETBConverter}, ConverterParameter={exten:TestEnum State2}}"
             Content="State2"/>