C# 双向多重绑定
玩多重绑定: 我想要的是:单击任一复选框应切换所有其他复选框 问题:单击C# 双向多重绑定,c#,wpf,multibinding,two-way-binding,C#,Wpf,Multibinding,Two Way Binding,玩多重绑定: 我想要的是:单击任一复选框应切换所有其他复选框 问题:单击A不会更改B,单击B不会更改A结果有效 问题:如果仍然使用多绑定,我将如何修复它 注:这是一个解决更复杂问题的尝试,请在提供将所有复选框绑定到单个属性之前参考它 下面是一个例子 xaml: 视图模型: public class ViewModel : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged;
A
不会更改B
,单击B
不会更改A
<代码>结果有效
问题:如果仍然使用多绑定
,我将如何修复它
注:这是一个解决更复杂问题的尝试,请在提供将所有复选框绑定到单个属性之前参考它
下面是一个例子 xaml: 视图模型:
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();
}
公共类MultiBindingConverter:MarkupExtension,IMultiValueConverter
{
公共多绑定转换器(){}
公共覆盖对象ProviderValue(IServiceProviderServiceProvider)=>此;
对象[]旧;
公共对象转换(对象[]值,类型targetType,对象参数,CultureInfo区域性)
{
//首次初始化
如果(_old==null)
_old=values.ToArray();
//查找是否更改了任何值并返回值
for(int i=0;i我认为您的转换器应该是这样的
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");
}
}
}
原因很简单,单击
复选框A时,将永远不会调用ConvertBack()
方法
考虑以下理由:
复选框
选中一个
调用属性设置程序A
调用属性设置程序A
属性设置程序A调用OnPropertyChanged(“A”)
属性更改事件由复选框的
接收
正在调用属性getterA和B(仍保持不变)
MultiBindingConverter.Convert()
方法由绑定调用
更新视图中的复选框
结果已选中
状态
更改的处理是在不触摸复选框的情况下完成的,并且只调用属性B的getter
如果在所有复选框上都有多重绑定
,则将调用所有适当的设置程序。但是,如果每个复选框的更改行为不同,则可能需要实现不同的转换器
这也是为什么如果可能的话,像这样的更改最好在ViewModel中完成的原因,因为所有这些绑定和转换器都会使跟踪变得有点困难。为什么不使用返回a | | b的属性结果并在更新a或b时引发属性更改?@Boo,因为你没有读过P.S.
;)其中一个属性(例如,A
)在ViewModel中不可用。我的两分钱:您错过了一个ViewModel。@ArnaudWeil,按control
+F
,键入ViewModel
,然后按Enter
。好笑。说真的,您所称的ViewModel不是ViewModel,因为它不会为每个输入公开属性。您的多重绑定用于隐藏它不是read ViewModel的事实。此转换器存在相同的问题:单击a
不会更改B
(只会更改a
和结果
)@Sinatr对vm的更改增加了对ViewModel的更改使A
和B
过于依赖,并使多绑定
无效。正如我在评论中提到的,A
在ViewModel中不可用(它将是视图中的附加属性),因此这种解决方案对我没有用处,对此表示抱歉。我试图使mcve
尽可能简单,因此没有将A
和B
分开足够多(这样你就不能在ViewModel中使用它们了)。在这种情况下,只需添加一个返回A | | B的属性结果,我看不出问题。我花了一些时间来记住这些内容,感谢你表现出的兴趣。“如果可能,在ViewModel中”-不幸的是,这是不可能的,VM不知道有关附加属性的信息,也不知道有关VM的附加属性(请参阅以了解问题的根源,其中多绑定是一种尝试性的解决方案)。解释很清楚,我接受“不”作为答案。
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");
}
}
}