WPF/ c#完全以编程方式将对象数组绑定到静态ObservableCollection上

本文关键字:绑定 数组 对象 静态 ObservableCollection 方式 编程 WPF | 更新日期: 2023-09-27 18:06:07

请假设这整个问题都是用代码处理的,没有任何XAML。

我有一个静态的ObservableCollection命名为myStaticList。它是一个名为myClass的非静态类的一部分。

public class myClass
{
    public static ObservableCollection<CheckBoxStructure> myStaticList { get; set; }
    static myClass()
    {
        myStaticList = new ObservableCollection<CheckBoxStructure>();
    }
}

CheckBoxStructure的定义:

public class CheckBoxStructure
{
    public string Description { get; set; }
    public bool IsSelected { get; set; }
}

此外,还有一个名为checkBoxArray[]的复选框数组,包含3个元素。每个复选框的内容都是一个文本框。

我想做的是以编程方式绑定(双向)这两者,以这样的方式,checkBoxArray[]数组中复选框的IsChecked属性将绑定到myStaticListCheckBoxStructureIsSelected属性,同样地,在复选框内容中的文本框的文本和myStaticListCheckBoxStructureDescription属性之间。

此外,我希望避免使用循环,因为如果这两个列表的大小发生了变化,它们会相互更新。

这怎么可能?

谢谢!

WPF/ c#完全以编程方式将对象数组绑定到静态ObservableCollection上

使用XAML,一个简单的方法是为它声明一个ItemsControl和一个DataTemplate,这样你就可以有一个UserControl (CheckBoxTextBox在里面),它的DataContext是一个CheckBoxStructure。这样,绑定在CheckBox.IsCheckedIsSelected属性之间以及TextBox.TextDescription属性之间工作。如果你只需要在代码中这样做,那么你将不得不创建相同的行为(ItemsControlDataTemplate)。你至少有2个选项

1。

DataTemplate template = new DataTemplate();
FrameworkElementFactory factory = new FrameworkElementFactory(typeof(StackPanel));
template.VisualTree = factory;
FrameworkElementFactory childFactory = new FrameworkElementFactory(typeof(CheckBox));
childFactory.SetBinding(CheckBox.IsChecked, new Binding("IsSelected"));
factory.AppendChild(childFactory);
childFactory = new FrameworkElementFactory(typeof(TextBox));
childFactory.SetBinding(Label.ContentProperty, new Binding("Description"));
factory.AppendChild(childFactory);

2。

MemoryStream sr = null;
ParserContext pc = null;
string xaml = string.Empty;
xaml = "<DataTemplate><StackPanel><TextBlock Text="{Binding Description"/><CheckBox IsChecked="{Binding IsSelected"/></StackPanel></DataTemplate>";
sr = new MemoryStream(Encoding.ASCII.GetBytes(xaml));
pc = new ParserContext();
pc.XmlnsDictionary.Add("", "http://schemas.microsoft.com/winfx/2006/xaml/presentation");
pc.XmlnsDictionary.Add("x", "http://schemas.microsoft.com/winfx/2006/xaml");
DataTemplate datatemplate = (DataTemplate)XamlReader.Load(sr, pc);
this.Resources.Add("dt", datatemplate);

以后编辑,讨论后从评注;本例仅适用于一种绑定方式,但很容易将其变成两种方式。请注意,这只是一个微不足道的概念示例,并不完整:您需要修改列表类以适应您希望对象配对的方式,您可能需要为角落情况添加更多保护,您可能需要使其线程安全等等…

首先是基本的绑定对象:
class Binder
{
    public Binder()
    {
        _bindings = new Dictionary<string, List<string>>();
    }
    private INotifyPropertyChanged _dataContext;
    public INotifyPropertyChanged DataContext
    {
        get { return _dataContext; }
        set
        {
            if (_dataContext != null)
            {
                _dataContext.PropertyChanged -= _dataContext_PropertyChanged;
            }
            _dataContext = value;
            _dataContext.PropertyChanged += _dataContext_PropertyChanged;
        }
    }
    void _dataContext_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        if (_bindings.ContainsKey(e.PropertyName))
        {
            var bindableType = _dataContext.GetType();
            var bindableProp = bindableType.GetProperty(e.PropertyName);
            if (bindableProp == null)
            {
                return;
            }
            var binderType = this.GetType();
            foreach (var binderPropName in _bindings[e.PropertyName])
            {
                var binderProp = binderType.GetProperty(binderPropName);
                if (binderProp == null)
                {
                    continue;
                }
                var value = bindableProp.GetValue(_dataContext);
                binderProp.SetValue(this, value);
            }
        }
    }
    Dictionary<string, List<string>> _bindings;
    public void AddBinding(string binderPropertyName, string bindablePropertyName)
    {
        if (!_bindings.ContainsKey(bindablePropertyName))
        {
            _bindings.Add(bindablePropertyName, new List<string>());
        }
        _bindings[bindablePropertyName].Add(bindablePropertyName);
    }
}
class Bindable : INotifyPropertyChanged
{
    protected void NotifyPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
    public event PropertyChangedEventHandler PropertyChanged;
}

然后是他们的等待列表:

class BindableList<T> : List<T> where T : Bindable
{
    public event Action<T> ItemAdded;
    public new void Add(T item)
    {
        base.Add(item);
        NotifyItemAdded(item);
    }
    private void NotifyItemAdded(T item)
    {
        if (ItemAdded != null)
        {
            ItemAdded(item);
        }
    }
}
class BinderList<T> : List<T> where T : Binder
{
    public BinderList()
    {
        _bindingRules = new Dictionary<string, string>();
    }
    private BindableList<Bindable> _dataContextList;
    public BindableList<Bindable> DataContextList
    {
        get { return _dataContextList; }
        set
        {
            if (_dataContextList != null)
            {
                _dataContextList.ItemAdded -= _dataContextList_ItemAdded;
            }
            _dataContextList = value;
            _dataContextList.ItemAdded += _dataContextList_ItemAdded;
        }
    }
    void _dataContextList_ItemAdded(Bindable obj)
    {
        foreach (var pair in _bindingRules)
        {
            this[Count-1].AddBinding(pair.Key, pair.Value);
            this[Count - 1].DataContext = obj;
        }
    }
    private Dictionary<string, string> _bindingRules;
    public void AddBindingRule(string binderPropertyName, string bindablePropertyName)
    {
        _bindingRules.Add(binderPropertyName, bindablePropertyName);
    }
}

现在是具有属性的实际类:

class BinderElement : Binder
{
    private string _description;
    public string Description
    {
        get { return _description; }
        set { _description = value; }
    }
}
class BindableElement : Bindable
{
    private string _description;
    public string Description
    {
        get
        {
            return _description;
        }
        set
        {
            _description = value;
            NotifyPropertyChanged("Description");
        }
    }
}

和一个使用它们的例子:

static void Main(string[] args)
    {
        var bindableList = new BindableList<Bindable>();
        var binderList = new BinderList<BinderElement>()
        {
            new BinderElement(),
            new BinderElement()
        };
        binderList.DataContextList = bindableList;
        binderList.AddBindingRule("Description", "Description");
        bindableList.Add(new BindableElement());
        bindableList.Add(new BindableElement());
        ((BindableElement)bindableList[1]).Description = "This should arrive in BinderElement Description property";
        Console.WriteLine(binderList[1].Description);
        Console.ReadLine();
    }