wpf 将数据绑定到集合/字典的非XAML方式

tzcvj98z  于 2023-05-13  发布在  其他
关注(0)|答案(1)|浏览(144)

我有一个动态加载图的需求(XAML,包括自定义UserControl,ScrewControl)。
我正在研究从ViewModel类绑定ScrewControl的依赖属性(Status)的方法。挑战在于,一个图可能包含不同数量的ScrewControl,每个ScrewControl都需要绑定到ViewModel中的字典或集合。
我已经解决了使用XamlReader动态加载XAML的第一个挑战,但不确定如何将ScrewControl与ViewModel中的Collection/dictionary绑定。
视图模型类

public class AssemblyViewModel
{
    public Dictionary<int, ScrewStatus> Screws { get; set; }
    public FrameworkElement Image { get; set; }

    ...
}

视图类

public partial class AssemblyView : UserControl
{
    private AssemblyViewModel viewModel;

    public AssemblyView(AssemblyViewModel viewModel)
    {
        InitializeComponent();
        DataContext = this.viewModel = viewModel;

        Loaded += OnLoaded;
    }

    public FrameworkElement XamlContent
    {
        get { return (FrameworkElement)GetValue(XamlContentProperty); }
        set { SetValue(XamlContentProperty, value); }
    }

    // Using a DependencyProperty as the backing store for Content.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty XamlContentProperty =
        DependencyProperty.Register("XamlContent", typeof(FrameworkElement), typeof(AssemblyView), new PropertyMetadata(null, OnXamlChanged));

    private static void OnXamlChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs args)
    {
        var view = dependencyObject as AssemblyView;
        var element = args.NewValue as FrameworkElement;
        if (null != element)
        {
            view.ContentControl.Children.RemoveRange(0, 1);
            view.ContentControl.Children.Add(element);

            var screws = element.FindChildren<Screw>();

            try
            {
                foreach (var screw in screws)
                {
                    // The ScrewControl has a name properties like "Screw_1", 1 is used as the key of the dictionary and Status as the Value
                    var parts = screw.Name.Split(new char[] { '_' }, StringSplitOptions.RemoveEmptyEntries);
                    if (2 == parts.Length)
                    {
                        BindingOperations.SetBinding(
                            screw,
                            Screw.ScrewStatusProperty,
                            new Binding(/*not sure what goes here*/)
                            {
                                Source = view.viewModel.Screws,
                            });
                    }
                }
            }
            catch (Exception e)
            {
                throw;
            }
        }
    }

    private void OnLoaded(object sender, RoutedEventArgs e)
    {

        // This works and loads the diagram 
        BindingOperations.SetBinding(
            this,
            XamlContentProperty,
            new Binding("Image")
            {
                Source = this.viewModel
            });
    }
nvbavucw

nvbavucw1#

你就快成功了。这应该可以工作:

foreach (var screw in screws)
{
    // The ScrewControl has a name properties like "Screw_1", 1 is used as the key of the dictionary and Status as the Value
    var parts = screw.Name.Split(new char[] { '_' }, StringSplitOptions.RemoveEmptyEntries);
    if (2 == parts.Length)
    {
        BindingOperations.SetBinding(
            screw,
            Screw.ScrewStatusProperty,
            new Binding() // No need for a path as we're going to bind directly to the source value 
            {
                // The source of the databinding is the value of the Screws dictionary keyed by screw id (parsed from the screw name)
                Source = view.viewModel.Screws[(int)parts[1]],
            });
    }
}

虽然从XAML加载的Screw控件可能更像WPF,但它是一个公共属性,并将其绑定为ItemsControl的ItemsSource。然后,您可以将ItemTemplate设置为ContentControl,其中Content属性绑定到ScrewStatus,ContentTemplate绑定到当前项(即从XAML加载的screw用户控件),这将提供一种更自然的方式将视图和模型绑定在一起。

相关问题