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 可枚举.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");
            }
    }
}

原因很简单,单击
复选框
A时,将永远不会调用
ConvertBack()
方法

考虑以下理由:

复选框
选中一个

调用属性设置程序A

调用属性设置程序A

属性设置程序A调用
OnPropertyChanged(“A”)

属性更改事件由
复选框的
接收

正在调用属性getterAB(仍保持不变)

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");
            }
    }
}