【问题标题】:WPF dynamic binding to propertyWPF 动态绑定到属性
【发布时间】:2016-07-04 10:53:30
【问题描述】:

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

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

我想要做的是显示 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 使用反射来查看 Instance 并返回属性的值。

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

我正在寻找一种仅使用 XAML 的方法,如果可能的话,如果没有,我将不得不为 ItemsSource 集合的项目编写一个包装类,并且我知道该怎么做,但是,因为它在我的项目中将是一个经常性的任务,它会非常昂贵。

编辑:

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

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

    public INotifyPropertyChanged Instance { get; set; }

    public string PropertyName { get; set; }

}

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

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

谢谢

【问题讨论】:

  • 请展示 ViewModel/CodeBehind 让我们看看你的数据结构是怎样的
  • 我想不出任何方法来动态迭代和绑定到 XAML 中的任意对象的属性。您需要编写一个虚拟机或行为来执行此操作,以便您可以观察更改通知,但使用反射以通用方式执行此操作,您可以在整个项目中重复使用它。
  • 您不是在寻找PropertyGrid
  • 我编辑了帖子以提供您所要求的信息,btw 感谢 cmets
  • @GazTheDestroyer 感谢您的建议,我可以修改 InstanceProperty 类以提供“值”属性并通过 INotifyPropertyChanged 接收值更改通知,如果您想回答我可以将您的帖子标记为已接受回答

标签: wpf xaml binding itemscontrol


【解决方案1】:

好的,感谢@GazTheDestroyer 评论:

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

我找到了解决方案:像这样编辑 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>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-10-05
    • 1970-01-01
    • 1970-01-01
    • 2015-10-15
    • 2019-07-11
    • 2011-03-07
    • 2011-02-01
    相关资源
    最近更新 更多