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

WPF/C# entirely programmatically binding an array of objects to a static ObservableCollection

请假设整个问题都涉及代码,没有任何 XAML。

我有一个名为 myStaticList 的静态 ObservableCollection。它是名为 myClass.

的非静态 class 的一部分
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 属性 将绑定到 myStaticList's CheckBoxStructure, and similarly so between the text of the textboxes inthe checkboxes' 内容的 IsSelected 属性 和 myStaticListCheckBoxStructureDescription 属性 ].

此外,我想避免使用循环,因为这两个列表最好在大小发生变化时相互更新。

这怎么可能?

谢谢!

使用XAML,一个简单的方法是为其声明一个ItemsControl和一个DataTemplate,这样你就可以有一个UserControlCheckBoxTextBox inside) 其 DataContextCheckBoxStructure。这样,绑定在 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();
    }