【问题标题】:Execute a function within DependencyProperty在 DependencyProperty 中执行一个函数
【发布时间】:2014-01-14 22:45:46
【问题描述】:

,当我更新 observableCollection "MyCollection" 中的项目时,我希望我的自定义 TextBlock ( 执行函数并修改其文本。我想我应该调用函数 OnMYDataChanged:

<ListBox ItemsSource="{Binding MyCollection}" ItemTemplate="{StaticResource MyTemplate}" >

<DataTemplate x:Key="MyTemplate"  >
  <Grid >...
    <local:MyTextBlock Path="{Binding MyText}"  />

在哪里

public class MyTextBlock : TextBlock
 {
    public string Path
    {  get {return (string)GetValue(PathProperty);}
       set { SetValue(PathProperty, value); }
    }
    public static readonly DependencyProperty PathProperty =
       DependencyProperty.Register("Path", typeof(string), typeof(MyTextBlock), new PropertyMetadata(OnMyDataChanged));

    static void OnMyDataChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args) {
      Text = DoSomethingWithText(); //Does not work                   
    }

当我更改一项时,会调用 OnMyDataChanged,但是 我在那里得到错误: 非静态字段、方法或属性需要对象引用

【问题讨论】:

    标签: c# wpf inotifypropertychanged


    【解决方案1】:

    要为DependencyProperty 的执行添加逻辑,您可以为每个DependencyProperty 定义一个DependencyPropertyDescriptor,并在您的自定义类的构造函数中添加一个带有必要逻辑的AddValueChanged 调用。如果您有一个名为 DefinableGrid 且具有 Columns 属性的自定义 Grid 类,则结果是(使用 C# 6 的空条件运算符 ?.):

        public int Columns
        {
            get { return (int) GetValue(ColumnsDependencyProperty); }
            set { SetValue(ColumnsDependencyProperty, value); }
        }
        public static readonly DependencyProperty ColumnsDependencyProperty =
            DependencyProperty.Register(nameof(Columns), typeof(int), typeof(DefinableGrid), new PropertyMetadata(0));
    
        DependencyPropertyDescriptor ColumnsPropertyDescriptor = DependencyPropertyDescriptor.FromProperty(ColumnsDependencyProperty, typeof(DefinableGrid));
    
        public GridEx()
        {
            ColumnsPropertyDescriptor?.AddValueChanged(this, delegate
            {
                ColumnDefinitions.Clear();
                for (int i = 0; i < Columns; i++)
                    ColumnDefinitions.Add(new ColumnDefinition());
            });
        }
    

    【讨论】:

      【解决方案2】:

      文本属性不可访问,因为回调函数是静态的。

      您需要将 obj 参数转换为“MyTextBlock”,并通过该指针您可以访问对象的属性。

      【讨论】:

      • 解决了问题!谢谢!您会认为这种方法更合适,还是 IMultiValueConverter 绑定 MyText 和 containerSize 会更好?
      • 我认为这是一个很好的解决方案。我不喜欢复杂的绑定。
      【解决方案3】:

      您的源对象需要实现 INotifyPropertyChanged 才能使其工作(具有“MyText”属性的对象)。

      MSDN 上有一个很好的示例实现。

      顺便说一句,您的数据模板可以包含在 ListBox 中,而不是作为静态资源(如果这是您想要使用该数据模板的唯一位置,则可能不会那么混乱):

      <ListBox>
         <ListBox.ItemTemplate>
             <DataTemplate>
             </DataTemplate>
         </ListBox.ItemTemplate>
      </ListBox>
      

      【讨论】:

      • 它实现了 INotifyPropertyChanged。请查看其他数据。
      • 刚刚注意到其他事情,您正在绑定“MyTextBlock”类的“Path”属性而不是“Text”属性。这是故意的吗?
      • 这是故意的,因为如果我绑定文本,我将无法更改它。
      • 我强烈怀疑这是你的问题。 “无法改变”是什么意思?如果您进行单向绑定,则不会更改源。顺便说一句,您的后期处理在做什么?将绑定的“StringFormat”属性与普通文本块一起使用可能会更好......
      • 使用 IValueConverter 将是解决问题的另一种方法,您可以将大小用作转换器参数。要从 OnMyDataChanged 访问实例,只需将“obj”变量转换为 MyTextBlockClass 并更改那里的属性。
      【解决方案4】:

      你想在这种情况下使用 ObservableCollection.CollectionChanged 事件

      【讨论】:

      • 这仅在 INotifyPropertyChanged 由聚合对象类型实现时才有效,并且会在更改任何项目时触发,而不仅仅是 TextBlock 绑定到的项目。
      • 我想我不明白他们在追求什么:(
      • 是不是说如果我改变一项,ListBox中的所有TextBlocks都会运行这个函数?
      • 是的,假设您首先可以从 TextBlock 类获取可观察集合。
      • 这不是最优的。如果我有 10K 项并更改一项,我不希望所有 TextBlocks 都执行功能。
      猜你喜欢
      • 1970-01-01
      • 2011-07-04
      • 1970-01-01
      • 2016-06-18
      • 1970-01-01
      • 2020-04-22
      • 2020-04-11
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多