WPF 动态绑定(bind)到属性

标签 wpf xaml binding itemscontrol

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

ItemsControl 的 ItemsSource 是一个具有两个属性的对象:InstancePropertyName

我想要做的是显示Instance对象的所有属性值,但我找不到将绑定(bind)的路径设置为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>

问号是我不知道如何创建绑定(bind)的地方。

我最初尝试使用 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 使用反射来查看实例并返回属性的值。

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

我正在寻找一种仅使用 XAML 来完成此操作的方法,如果可能的话,如果没有,我将不得不为 ItemsSource 集合的项目编写一个包装类,并且我知道如何做到这一点,但是,因为它将是我的项目中的一项重复任务,这将是相当昂贵的。

编辑:

对于那些询问的人,InstanceProperties 是 ViewModel 上的一个属性,它公开了如下所示的对象集合:

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

    public INotifyPropertyChanged Instance { get; set; }

    public string PropertyName { get; set; }

}

显然,这两个属性通过 INotifyPropertyChanged 通知它们的值正在更改,为简单起见,我不包括 OnPropertyChanged 事件处理。

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

谢谢

最佳答案

好的,感谢@GazTheDestroyer 评论:

@GazTheDestroyer wrote: I cannot think of any way to dynamically iterate and bind to an arbitrary object's properties in XAML only. You need to write a VM or behaviour to do this so you can watch for change notifications, but do it in a generic way using reflection you can just reuse it throughout your project

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

  1. 添加了 PropertyValue 属性
  2. 监听Instance上的PropertyChanged事件,并在PropertyName值发生更改时触发,引发PropertyValue上的PropertyChanged
  3. InstancePropertyName更改时,保存对Reflection的PropertyInfo的引用,PropertyValue将使用该引用来读取值

这是新的、完整的 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>

关于WPF 动态绑定(bind)到属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38182945/

相关文章:

c# - MultiTrigger:条件绑定(bind)到 DependencyProperty 不起作用

c# - ReactiveUI 同步 ReactiveCommand 调用导致 System.InvalidOperationException

xaml - 如何制作可执行的 Metro 风格应用程序?

c# - 如何使用新属性正确扩展 XAML 控件?

c# - 使用没有导航 View 的 MVVM 模式的 WPF 切换 View

c# - WPF。未从另一个应用程序(服务)关闭 wpf 应用程序

c# - WPF 4 : PropertyChanged not updating Binding

c# - ActivityIndi​​cator 没有进入正确的位置

optimization - OpenGL - glBindTexture - 过早优化?

android - 启用 viewBinding 功能失败(Android Studio 3.6)