TwoWay MultiBinding

时间:2016-03-17 15:05:12

标签: c# wpf multibinding two-way-binding

使用MultiBinding

我想要的是:点击任一复选框都应该切换所有其他人。

问题:点击A不会更改B,点击B不会更改AResult有效。

问题:如何在使用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();
}

2 个答案:

答案 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中完成,因为所有这些绑定和转换器使得它有点难以跟踪。