2

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

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

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

我只想通过绑定来执行此操作,因为出价比循环快

4

3 回答 3

6

尝试这个:

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

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

于 2012-11-27T18:42:00.000 回答
0

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

  • 如果更改控件中的属性,则会更新所有项。
  • 如果您更改项目中的属性,如果所有项目都具有相同的属性,则控件将反映它。如果没有,控件的属性将被赋予一个后备值(如 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);
        }
    }
    }
    

你可以像这样使用它:

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

它还不支持集合更改(只是集合交换),但我相信它可以很容易地修改为。如果你想开箱即用,你可以在 ObservableCollection 的 CollectionChanged 事件中添加一个处理程序,这样它就会触发 ItemsSource 更新:

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

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

于 2012-11-27T19:13:01.040 回答
0

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

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

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

XAML

<CheckBox IsChecked="{Binding AllTrue}"/>
于 2012-11-27T19:01:11.140 回答