使用MultiBinding
:
我想要的是:点击任一复选框都应该切换所有其他人。
问题:点击A
不会更改B
,点击B
不会更改A
。 Result
有效。
问题:如何在使用MultiBinding
时解决问题?
P.S。:这是尝试解决更复杂的problem,请在提供将所有复选框绑定到单个属性之前参考它。
下面是mcve。
XAML:
<StackPanel>
<CheckBox Content="A" IsChecked="{Binding A}" />
<CheckBox Content="B" IsChecked="{Binding B}" />
<CheckBox Content="Result">
<CheckBox.IsChecked>
<MultiBinding Converter="{local:MultiBindingConverter}">
<Binding Path="A" />
<Binding Path="B" />
</MultiBinding>
</CheckBox.IsChecked>
</CheckBox>
</StackPanel>
CS:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new ViewModel();
}
}
视图模型:
public class ViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged([CallerMemberName] string property = "") => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(property));
bool _a;
public bool A
{
get { return _a; }
set { _a = value; OnPropertyChanged(); }
}
bool _b;
public bool B
{
get { return _b; }
set { _b = value; OnPropertyChanged(); }
}
}
转换器:
public class MultiBindingConverter : MarkupExtension, IMultiValueConverter
{
public MultiBindingConverter() { }
public override object ProvideValue(IServiceProvider serviceProvider) => this;
object[] _old;
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
// first time init
if (_old == null)
_old = values.ToArray();
// find if any value is changed and return value
for (int i = 0; i < values.Length; i++)
if (values[i] != _old[i])
{
_old = values.ToArray();
return values[i];
}
// if no changes return first value
return values[0];
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) =>
Enumerable.Repeat(value, targetTypes.Length).ToArray();
}
答案 0 :(得分:0)
我认为你的转换器应该是这样的
public class MultiBindingConverter : MarkupExtension, IMultiValueConverter
{
public MultiBindingConverter() { }
public override object ProvideValue(IServiceProvider serviceProvider) => this;
object[] _old;
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
return ((bool)values[0] /*A */) || ((bool)values[1]/* B */);
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
return new object[] { (bool)value, (bool)value};
}
}
然后
public class ViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged([CallerMemberName] string property = "") => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(property));
bool _a;
public bool A
{
get { return _a || _b; }
set {
if (_a == value) return;
_a = value;
OnPropertyChanged("A");
OnPropertyChanged("B");
}
}
bool _b;
public bool B
{
get { return _b || _a; }
set {
if (_b == value) return;
_b = value;
OnPropertyChanged("B");
OnPropertyChanged("A");
}
}
}
答案 1 :(得分:0)
原因很简单,当您点击ConvertBack()
A 时,永远不会调用CheckBox
方法。
考虑以下原因:
Checkbox
检查。
<Binding />
调用Property-Setter A 。
Property-Setter A 被调用。
Property-Setter A 调用OnPropertyChanged("A")
。
PropertyChanged-Event由<MultiBinding />
结果的CheckBox
收到。
正在调用Property-Getters A 和 B (仍未更改)。
绑定调用 MultiBindingConverter.Convert()
方法。
<MultiBinding />
更新了视图中的CheckBox
结果 IsChecked
状态。
在不触及CheckBox
B且只调用属性 B 的获取者的情况下完成变更处理。
如果所有MultiBinding
都有CheckBox
,则会调用所有适当的设置器。如果每个CheckBox
的更改行为应该不同,则可能需要实现不同的转换器。
这也是原因,为什么更改这样的东西应该 - 如果可能的话 - 最好在ViewModel中完成,因为所有这些绑定和转换器使得它有点难以跟踪。