wpf 如何将对象的布尔属性绑定到 CheckBox 的 IsChecked 属性?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/13590785/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-13 06:23:12  来源:igfitidea点击:

How to bind an object's boolean property to a CheckBox's IsChecked property?

wpfxamlbindingcheckbox

提问by Alex Kapustian

I have an ObservableCollection of objects that have a boolean property.

我有一个具有布尔属性的对象的 ObservableCollection。

In the GUI, I have a CheckBox from which I want to bind its IsChecked property to each object's boolean property.

在 GUI 中,我有一个 CheckBox,我想从中将其 IsChecked 属性绑定到每个对象的布尔属性。

Is it possible using XAML only? How?

是否可以仅使用 XAML?如何?

I want to do it only with binding cause biding is faster than loop

我只想用绑定来做,因为投标比循环快

回答by acrilige

Try this:

尝试这个:

<ListBox ItemsSource={Binding path}>
  <ListBox.ItemTemplate>
    <DataTemplate>
      <CheckBox IsChecked="{Binding yourBoolPropertyName, Mode = TwoWay}" />
    </DataTemplate>
  </ListBox.ItemTemplate>
</ListBox>

This will create list of checkboxes that will bind to your collection. Of course, you must properly set paths for binding.

这将创建将绑定到您的集合的复选框列表。当然,您必须正确设置绑定路径。

回答by Rohit Vats

Create a bool property on your ViewModel which will loop through all Objectsof your ObservableCollection to see property is true for every object -

在您的 ViewModel 上创建一个 bool 属性,它将循环遍历Objects您的所有ObservableCollection 以查看每个对象的属性是否为真 -

public bool AllTrue
{
   get
   {
      return Objects.All(o => o.Selected);
   }
}

Here Objectsis instance of your ObservableCollectionand Selectedis a bool property in an object.

Objects是您的实例,ObservableCollection并且Selected是对象中的 bool 属性。

XAML

XAML

<CheckBox IsChecked="{Binding AllTrue}"/>

回答by Arthur Nunes

I have created a behavior to allow a property in a control to be bound to a property of a collection of items, in a way that:

我创建了一个行为,允许将控件中的属性绑定到项目集合的属性,方式如下:

  • If you change the property in the control, all of the items are updated.
  • If you change the property in a item, if all the items have the same property the control will reflect it. If not, the property of the control will be given a fallback value (like null).

    public class CollectionPropertyBehavior : Behavior<DependencyObject>
    {
    
    private IEnumerable<ValueProxy> proxies;
    private bool syncking;
    
    public string SourcePropertyPath
    {
        get { return (string)GetValue(SourcePropertyPathProperty); }
        set { SetValue(SourcePropertyPathProperty, value); }
    }
    public static readonly DependencyProperty SourcePropertyPathProperty =
        DependencyProperty.Register("SourcePropertyPath", typeof(string), typeof(CollectionPropertyBehavior), new PropertyMetadata(null));
    
    public string CollectionPropertyPath
    {
        get { return (string)GetValue(CollectionPropertyPathProperty); }
        set { SetValue(CollectionPropertyPathProperty, value); }
    }
    public static readonly DependencyProperty CollectionPropertyPathProperty =
        DependencyProperty.Register("CollectionPropertyPath", typeof(string), typeof(CollectionPropertyBehavior), new PropertyMetadata(null));
    
    
    private IEnumerable<object> Items { get { return  this.ItemsSource == null ? null : this.ItemsSource.OfType<object>(); } }
    public IEnumerable ItemsSource
    {
        get { return (IEnumerable)GetValue(ItemsSourceProperty); }
        set { SetValue(ItemsSourceProperty, value); }
    }
    public static readonly DependencyProperty ItemsSourceProperty =
        DependencyProperty.Register("ItemsSource", typeof(IEnumerable), typeof(CollectionPropertyBehavior), new PropertyMetadata(null, ItemsSourceChanged));
    
    
    private object Value
    {
        get { return (object)GetValue(ValueProperty); }
        set { SetValue(ValueProperty, value); }
    }
    private static readonly DependencyProperty ValueProperty =
        DependencyProperty.Register("Value", typeof(object), typeof(CollectionPropertyBehavior), new PropertyMetadata(null, ValueChanged));
    
    
    public object DefaultValue
    {
        get { return (object)GetValue(DefaultValueProperty); }
        set { SetValue(DefaultValueProperty, value); }
    }
    public static readonly DependencyProperty DefaultValueProperty =
        DependencyProperty.Register("DefaultValue", typeof(object), typeof(CollectionPropertyBehavior), new PropertyMetadata(null));
    
    
    
    private static void ValueChanged(object sender, DependencyPropertyChangedEventArgs args)
    {
        var element = sender as CollectionPropertyBehavior;
        if (element == null || element.ItemsSource == null) return;
    
        element.UpdateCollection();
    }
    
    private static void ItemsSourceChanged(object sender, DependencyPropertyChangedEventArgs args)
    {
        var element = sender as CollectionPropertyBehavior;
        if (element == null || element.ItemsSource == null) return;
        element.ItemsSourceChanged();
    }
    
    private void ItemsSourceChanged()
    {
        this.proxies = null;
    
        if (this.Items == null || !this.Items.Any() || this.CollectionPropertyPath == null) return;
    
        // Cria os proxies
        this.proxies = this.Items.Select(o =>
        {
            var proxy = new ValueProxy();
            proxy.Bind(o, this.CollectionPropertyPath);
            proxy.ValueChanged += (s, e) => this.UpdateSource();
            return proxy;
        }).ToArray();
    
        this.UpdateSource();
    }
    
    private void UpdateSource()
    {
        if (this.syncking) return;
    
        // Atualiza o valor 
        using (new SynckingScope(this))
        {
            object value = this.proxies.First().Value;
            foreach (var proxy in this.proxies.Skip(1))
            {
                value = object.Equals(proxy.Value, value) ? value : this.DefaultValue;
            }
    
            this.Value = value;
        }
    }
    
    private void UpdateCollection()
    {
        // Se o valor estiver mudando em fun??o da atualiza??o de algum 
        // elemento da cole??o, n?o faz nada
        if (this.syncking) return;
    
        using (new SynckingScope(this))
        {
            // Atualiza todos os elementos da cole??o,
            // atrávés dos proxies
            if (this.proxies != null)
                foreach (var proxy in this.proxies)
                    proxy.Value = this.Value;
        }
    }
    
    protected override void OnAttached()
    {
        base.OnAttached();
    
    
        // Bind da propriedade do objeto fonte para o behavior
        var binding = new Binding(this.SourcePropertyPath);
        binding.Source = this.AssociatedObject;
        binding.Mode = BindingMode.TwoWay;
        BindingOperations.SetBinding(this, ValueProperty, binding);
    }
    
    protected override void OnDetaching()
    {
        base.OnDetaching();
    
        // Limpa o binding de value para a propriedade do objeto associado
        this.ClearValue(ValueProperty);
    }
    
    internal class SynckingScope : IDisposable
    {
        private readonly CollectionPropertyBehavior parent;
    
        public SynckingScope(CollectionPropertyBehavior parent)
        {
            this.parent = parent;
            this.parent.syncking = true;
        }
    
        public void Dispose()
        {
            this.parent.syncking = false;
        }
    }
    
    internal class ValueProxy : DependencyObject
    {
        public event EventHandler ValueChanged;
    
        public object Value
        {
            get { return (object)GetValue(ValueProperty); }
            set { SetValue(ValueProperty, value); }
        }
        public static readonly DependencyProperty ValueProperty =
            DependencyProperty.Register("Value", typeof(object), typeof(ValueProxy), new PropertyMetadata(null, OnValueChanged));
    
    
        private static void OnValueChanged(object sender, DependencyPropertyChangedEventArgs args)
        {
            var element = sender as ValueProxy;
            if (element == null || element.ValueChanged == null) return;
    
            element.ValueChanged(element, EventArgs.Empty);
        }
    
        public void Bind(object source, string path)
        {
            // Realiza o binding de value com o objeto desejado
            var binding = new Binding(path);
            binding.Source = source;
            binding.Mode = BindingMode.TwoWay;
    
            BindingOperations.SetBinding(this, ValueProperty, binding);
        }
    }
    }
    
  • 如果更改控件中的属性,则会更新所有项目。
  • 如果更改项目中的属性,如果所有项目都具有相同的属性,则控件将反映它。如果没有,控件的属性将被赋予一个回退值(如 null)。

    public class CollectionPropertyBehavior : Behavior<DependencyObject>
    {
    
    private IEnumerable<ValueProxy> proxies;
    private bool syncking;
    
    public string SourcePropertyPath
    {
        get { return (string)GetValue(SourcePropertyPathProperty); }
        set { SetValue(SourcePropertyPathProperty, value); }
    }
    public static readonly DependencyProperty SourcePropertyPathProperty =
        DependencyProperty.Register("SourcePropertyPath", typeof(string), typeof(CollectionPropertyBehavior), new PropertyMetadata(null));
    
    public string CollectionPropertyPath
    {
        get { return (string)GetValue(CollectionPropertyPathProperty); }
        set { SetValue(CollectionPropertyPathProperty, value); }
    }
    public static readonly DependencyProperty CollectionPropertyPathProperty =
        DependencyProperty.Register("CollectionPropertyPath", typeof(string), typeof(CollectionPropertyBehavior), new PropertyMetadata(null));
    
    
    private IEnumerable<object> Items { get { return  this.ItemsSource == null ? null : this.ItemsSource.OfType<object>(); } }
    public IEnumerable ItemsSource
    {
        get { return (IEnumerable)GetValue(ItemsSourceProperty); }
        set { SetValue(ItemsSourceProperty, value); }
    }
    public static readonly DependencyProperty ItemsSourceProperty =
        DependencyProperty.Register("ItemsSource", typeof(IEnumerable), typeof(CollectionPropertyBehavior), new PropertyMetadata(null, ItemsSourceChanged));
    
    
    private object Value
    {
        get { return (object)GetValue(ValueProperty); }
        set { SetValue(ValueProperty, value); }
    }
    private static readonly DependencyProperty ValueProperty =
        DependencyProperty.Register("Value", typeof(object), typeof(CollectionPropertyBehavior), new PropertyMetadata(null, ValueChanged));
    
    
    public object DefaultValue
    {
        get { return (object)GetValue(DefaultValueProperty); }
        set { SetValue(DefaultValueProperty, value); }
    }
    public static readonly DependencyProperty DefaultValueProperty =
        DependencyProperty.Register("DefaultValue", typeof(object), typeof(CollectionPropertyBehavior), new PropertyMetadata(null));
    
    
    
    private static void ValueChanged(object sender, DependencyPropertyChangedEventArgs args)
    {
        var element = sender as CollectionPropertyBehavior;
        if (element == null || element.ItemsSource == null) return;
    
        element.UpdateCollection();
    }
    
    private static void ItemsSourceChanged(object sender, DependencyPropertyChangedEventArgs args)
    {
        var element = sender as CollectionPropertyBehavior;
        if (element == null || element.ItemsSource == null) return;
        element.ItemsSourceChanged();
    }
    
    private void ItemsSourceChanged()
    {
        this.proxies = null;
    
        if (this.Items == null || !this.Items.Any() || this.CollectionPropertyPath == null) return;
    
        // Cria os proxies
        this.proxies = this.Items.Select(o =>
        {
            var proxy = new ValueProxy();
            proxy.Bind(o, this.CollectionPropertyPath);
            proxy.ValueChanged += (s, e) => this.UpdateSource();
            return proxy;
        }).ToArray();
    
        this.UpdateSource();
    }
    
    private void UpdateSource()
    {
        if (this.syncking) return;
    
        // Atualiza o valor 
        using (new SynckingScope(this))
        {
            object value = this.proxies.First().Value;
            foreach (var proxy in this.proxies.Skip(1))
            {
                value = object.Equals(proxy.Value, value) ? value : this.DefaultValue;
            }
    
            this.Value = value;
        }
    }
    
    private void UpdateCollection()
    {
        // Se o valor estiver mudando em fun??o da atualiza??o de algum 
        // elemento da cole??o, n?o faz nada
        if (this.syncking) return;
    
        using (new SynckingScope(this))
        {
            // Atualiza todos os elementos da cole??o,
            // atrávés dos proxies
            if (this.proxies != null)
                foreach (var proxy in this.proxies)
                    proxy.Value = this.Value;
        }
    }
    
    protected override void OnAttached()
    {
        base.OnAttached();
    
    
        // Bind da propriedade do objeto fonte para o behavior
        var binding = new Binding(this.SourcePropertyPath);
        binding.Source = this.AssociatedObject;
        binding.Mode = BindingMode.TwoWay;
        BindingOperations.SetBinding(this, ValueProperty, binding);
    }
    
    protected override void OnDetaching()
    {
        base.OnDetaching();
    
        // Limpa o binding de value para a propriedade do objeto associado
        this.ClearValue(ValueProperty);
    }
    
    internal class SynckingScope : IDisposable
    {
        private readonly CollectionPropertyBehavior parent;
    
        public SynckingScope(CollectionPropertyBehavior parent)
        {
            this.parent = parent;
            this.parent.syncking = true;
        }
    
        public void Dispose()
        {
            this.parent.syncking = false;
        }
    }
    
    internal class ValueProxy : DependencyObject
    {
        public event EventHandler ValueChanged;
    
        public object Value
        {
            get { return (object)GetValue(ValueProperty); }
            set { SetValue(ValueProperty, value); }
        }
        public static readonly DependencyProperty ValueProperty =
            DependencyProperty.Register("Value", typeof(object), typeof(ValueProxy), new PropertyMetadata(null, OnValueChanged));
    
    
        private static void OnValueChanged(object sender, DependencyPropertyChangedEventArgs args)
        {
            var element = sender as ValueProxy;
            if (element == null || element.ValueChanged == null) return;
    
            element.ValueChanged(element, EventArgs.Empty);
        }
    
        public void Bind(object source, string path)
        {
            // Realiza o binding de value com o objeto desejado
            var binding = new Binding(path);
            binding.Source = source;
            binding.Mode = BindingMode.TwoWay;
    
            BindingOperations.SetBinding(this, ValueProperty, binding);
        }
    }
    }
    

You can use it like this:

你可以这样使用它:

<CheckBox>
    <i:Interaction.Behaviors>
        <local:CollectionPropertyBehavior CollectionPropertyPath="MyBooleanProperty" SourcePropertyPath="IsChecked" ItemsSource="{Binding CollectionInViewModel}"/>
    </i:Interaction.Behaviors>
</CheckBox>

It doesn't support collection changes yet (just collection swap), but I believe it can be easily modified to to that. If you want to use it out of the box, you can just add a handler to the CollectionChanged event of your ObservableCollection so it will trigger the ItemsSource update:

它还不支持集合更改(只是集合交换),但我相信它可以轻松修改为。如果您想开箱即用,只需向 ObservableCollection 的 CollectionChanged 事件添加一个处理程序,它就会触发 ItemsSource 更新:

observableCollection.CollectionChanged += (s,e) => this.OnPropertyChanged("ItemsSource);

I've posted another example here.

我在这里发布了另一个例子。