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
How to bind an object's boolean property to a CheckBox's IsChecked property?
提问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.
我在这里发布了另一个例子。

