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
}
使用单选按钮列表,它必须比使用转换器更简单,并且可以随心所欲。看看这个答案
我根据您发布的代码创建了下面的应用程序,它运行良好。按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"/>