【问题标题】:Wrap property with dependency property用依赖属性包装属性
【发布时间】:2017-10-20 11:11:12
【问题描述】:

我对我的 MVVM 样式项目中的外部库中有用的用户控件 Monitor 感兴趣。 一切看起来都很好......但是这个控件有一个简单的(不是依赖)只读属性(IList<ILogSource>),我需要填写它。 经过一番思考,我决定将这个 Monitor 控件与其他控件 MonitorWrap 包装起来:

<UserControl
    x:Class="Prj.CustomControls.MonitorWrap"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:catel="http://catel.codeplex.com"
    xmlns:uc="clr-namespace:UsefulControll;assembly=UsefulControll">

    <uc:Monitor x:Name="Monitor" />
</UserControl>

在代码后面我创建依赖属性:

public partial class MonitorWrap : UserControl
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="MonitorWrap"/> class.
        /// </summary>
        public MonitorWrap()
        {
            InitializeComponent();

            DataContextChanged += (sender, args) =>
            {
                //correct ViewModel sets to DataContext
            };
        }

        public IList<ILogSource> LogSources
        {
            get { return (IList<ILogSource>)GetValue(LogSourcesProperty); }
            set { SetValue(LogSourcesProperty, value); }
        }

        // Using a DependencyProperty as the backing store for MyProperty.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty LogSourcesProperty =
            DependencyProperty.Register("LogSources", typeof(IList<ILogSource>), typeof(MonitorWrap), new PropertyMetadata(null,ChangeCallback));

        private static void ChangeCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var logControlPanelView = d as MonitorWrap;

            //add elements from LogSources to readonly collection property.
        }
    }

父 xml 的下一步:

<customControls:MonitorWrap LogSources="{Binding Sources}"/>

我希望我会在 Change Callback 方法中填充集合,但它不起作用。

所以问题:

  1. 我是否以正确的方式填充只读集合?
  2. 怎么了?为什么ChangeCallback 方法不起作用。

附: 我正在使用 MVVM 框架并且 DataContext 设置正确(MonitorWrap 构造函数中的 lambda 表达式工作正常)。

ViewModel 实现INotifyPropertyChanged 和代码

protected override void OnPropertyChanged(AdvancedPropertyChangedEventArgs e)
        {
            base.OnPropertyChanged(e);
            if (e.PropertyName == "Sources")
            {
                //works fine on property changed
            }
        }

也很好用。

【问题讨论】:

  • 那么您的期望是当您将项目添加到 Sources 视图模型属性时,应该调用 ChangeCallback?
  • 你每次都是添加物品还是推送全新的收藏?
  • 没有。当LogSources 将其值从null(默认)更改为typeof(Sources) 集合时,我希望看到ChangeCallback 的调用。
  • 什么是OnPropertyChanged,它是在哪里定义的?请分享 viewmodel 属性Sources 以及您如何设置它。我想知道它的类型是否可以分配给IList&lt;ILogSource&gt;
  • @EdPlunkett,tnx!用户控件中的依赖属性有typeof(IList&lt;ILogSource&gt;)。 ViewModel 中的属性Sources 具有typeof(ObservableCollection&lt;ILogSource_inherited_Class&gt;) 并且似乎绑定系统无法将一个转换为另一个。如果我将用户控件依赖属性更改为typeof(IList&lt;ILogSource_inherited_Class&gt;) 一切正常。我怎样才能让它在不改变类型的情况下工作?)

标签: c# wpf mvvm binding dependency-properties


【解决方案1】:

IList&lt;ILogSource&gt; 在我看来很可疑,就像您可能要求的 C# 对协方差的支持比您得到的要多。

viewmodel 属性的类型必须可分配给IList&lt;ILogSource&gt;,并且其规则相当严格。

从根本上说,ObservableCollection&lt;ILogSource&gt;IList&lt;ILogSource&gt;,但不是 IList&lt;ILogSource_inherited_Class&gt;。不能做到这一点的不仅仅是绑定。您可以将项目从一个复制到另一个,但不能投射。你想做的只是复制,但类型系统不知道——它只是看到你试图做任务。

应该做的是使类型为IEnumerable&lt;ILogSource&gt; (see fiddle) 的依赖属性。您需要做的就是从中复制项目,这样就足够了。不要告诉编译器你需要IList&lt;ILogSource&gt; 能做的一切,如果你只需要IEnumerable&lt;ILogSource&gt;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-07
    • 2013-05-10
    • 2023-04-06
    • 2015-04-23
    • 2014-05-23
    相关资源
    最近更新 更多