双向多绑定
TwoWay MultiBinding
和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();
}
我认为你的转换器应该是这样的
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");
}
}
}
原因很简单,当你点击CheckBox
A.
时,ConvertBack()
方法永远不会被调用
考虑以下推理:
Checkbox
A 得到 检查.
<Binding />
调用 属性-Setter A.
属性-Setter A 被调用。
属性-Setter A 调用 OnPropertyChanged("A")
.
属性Changed-Event 由 CheckBox
的 <MultiBinding />
接收 Result.
属性-Getters A 和 B(仍未改变)被调用。
MultiBindingConverter.Convert()
方法被绑定调用。
<MultiBinding />
更新视图中的 CheckBox
Result IsChecked
状态。
更改处理无需触及 CheckBox
B,仅调用 属性 B.[=25= 的 getter ]
如果您在所有 CheckBox
上都有一个 MultiBinding
,那么将调用所有适当的设置器。但是,如果每个 CheckBox
的更改行为应该不同,您可能需要实现不同的转换器。
这也是为什么更改此类内容应该 - 最好 - 如果可能的话在 ViewModel 中完成的原因,因为所有这些绑定和转换器使其有点难以跟踪。
和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();
}
我认为你的转换器应该是这样的
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");
}
}
}
原因很简单,当你点击CheckBox
A.
ConvertBack()
方法永远不会被调用
考虑以下推理:
Checkbox
A 得到 检查.
<Binding />
调用 属性-Setter A.
属性-Setter A 被调用。
属性-Setter A 调用 OnPropertyChanged("A")
.
属性Changed-Event 由 CheckBox
的 <MultiBinding />
接收 Result.
属性-Getters A 和 B(仍未改变)被调用。
MultiBindingConverter.Convert()
方法被绑定调用。
<MultiBinding />
更新视图中的 CheckBox
Result IsChecked
状态。
更改处理无需触及 CheckBox
B,仅调用 属性 B.[=25= 的 getter ]
如果您在所有 CheckBox
上都有一个 MultiBinding
,那么将调用所有适当的设置器。但是,如果每个 CheckBox
的更改行为应该不同,您可能需要实现不同的转换器。
这也是为什么更改此类内容应该 - 最好 - 如果可能的话在 ViewModel 中完成的原因,因为所有这些绑定和转换器使其有点难以跟踪。