WPF动态绑定到属性

时间:2016-07-04 10:53:31

标签: wpf xaml binding itemscontrol

我有一个ItemsControl,它应该显示一个对象的某些属性的值。

ItemsControl的ItemsSource是一个具有两个属性的对象:实例 PropertyName

我要做的是显示 Instance 对象的所有属性值,但是我找不到设置绑定路径到 PropertyName 价值:

<ItemsControl ItemsSource={Binding Path=InstanceProperties}>
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <StackPanel Orientation="Horizontal">
                <TextBlock Text="{Binding Path=PropertyName, Mode=OneWay}"/>
                <TextBlock Text=": "/>
                <TextBlock Text="{Binding Source=??{Binding Path=Instance}??, Path=??PropertyName??, Mode=OneWay}"/>
            </StackPanel>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

问号是我不知道如何创建绑定的点。

我最初尝试使用MultiValueConverter:

<TextBlock Grid.Column="1" Text="{Binding}">
    <TextBlock.DataContext>
        <MultiBinding Converter="{StaticResource getPropertyValue}">
            <Binding Path="Instance" Mode="OneWay"/>
            <Binding Path="PropertyName" Mode="OneWay"/>
        </MultiBinding>
    </TextBlock.DataContext>
</TextBlock>

MultiValueConverter使用Reflection查看 Instance 并返回属性的值。

但是如果属性值发生变化,则不会通知此更改,并且显示的值保持不变。

我正在寻找一种方法只使用XAML,如果可能的话,如果不是,我将不得不为ItemsSource集合的项目编写一个包装类,我知道如何做,但是,因为它将是我项目中的一项重复任务,它将非常昂贵。

编辑:

对于那些提问者, InstanceProperties 是ViewModel上的一个属性,它公开了这样的对象集合:

public class InstanceProperty : INotifyPropertyChanged
{
    //[.... INotifyPropertyChanged implementation ....]

    public INotifyPropertyChanged Instance { get; set; }

    public string PropertyName { get; set; }

}

显然,两个属性通知他们的值正在通过INotifyPropertyChanged进行更改,为简单起见,我没有包含OnPropertyChanged事件处理。

该集合中填充了一组有限的属性,我必须向用户提供这些属性,我无法使用PropertyGrid,因为我需要过滤我必须显示的属性,并且必须显示这些属性以图形丰富的方式。

由于

2 个答案:

答案 0 :(得分:1)

好的,感谢@GazTheDestroyer评论:

  

@GazTheDestroyer 写道:我想不出任何方法只能在XAML中动态迭代和绑定到任意对象的属性。您需要编写VM或行为来执行此操作,以便您可以查看更改通知,但是使用反射以通用方式执行此操作,您可以在整个项目中重复使用

我找到了一个解决方案:像这样编辑ViewModel类 InstanceProperty

  1. 添加了 PropertyValue 属性
  2. 实例上收听PropertyChanged事件,当触发 PropertyName 值更改时,在 PropertyValue 上提升PropertyChanged
  3. 实例 PropertyName 更改时,保存对 PropertyValue 将用于读取值的Reflection的PropertyInfo的引用
  4. 这是新的,完整的ViewModel类:

    public class InstanceProperty : INotifyPropertyChanged
    {
    
        #region Properties and events
    
        public event PropertyChangedEventHandler PropertyChanged;
    
        private INotifyPropertyChanged FInstance = null;
        public INotifyPropertyChanged Instance
        {
            get { return this.FInstance; }
            set
            {
                if (this.FInstance != null) this.FInstance.PropertyChanged -= Instance_PropertyChanged;
                this.FInstance = value;
                if (this.FInstance != null) this.FInstance.PropertyChanged += Instance_PropertyChanged;
                this.CheckProperty();
            }
        }
    
        private string FPropertyName = null;
        public string PropertyName
        {
            get { return this.FPropertyName; }
            set
            {
                this.FPropertyName = value;
                this.CheckProperty();
            }
        }
    
        private System.Reflection.PropertyInfo Property = null;
    
        public object PropertyValue
        {
            get { return this.Property?.GetValue(this.Instance, null); }
        }
    
        #endregion
    
        #region Private methods
    
        private void CheckProperty()
        {
            if (this.Instance == null || string.IsNullOrEmpty(this.PropertyName))
            {
                this.Property = null;
            }
            else
            {
                this.Property = this.Instance.GetType().GetProperty(this.PropertyName);
            }
            this.RaisePropertyChanged(nameof(PropertyValue));
        }
    
        private void Instance_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == this.PropertyName)
            {
                this.RaisePropertyChanged(nameof(PropertyValue));
            }
        }
    
        private void RaisePropertyChanged(string propertyname)
        {
            this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyname));
        }
    
        #endregion
    
    }
    

    这是XAML:

    <ItemsControl ItemsSource={Binding Path=InstanceProperties}>
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <StackPanel Orientation="Horizontal">
                    <TextBlock Text="{Binding Path=PropertyName, Mode=OneWay}"/>
                    <TextBlock Text=": "/>
                    <TextBlock Text="{Binding Path=PropertyValue, Mode=OneWay}"/>
                </StackPanel>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
    

答案 1 :(得分:0)

无法绑定到Instance.PropertyName吗?