WPF动态绑定

Jak*_*son 3 c# data-binding wpf

今天,我正在研究一个WPF UserControl来显示一些变量的当前值.我想知道是否有办法在WPF中创建一个超级简单的属性网格.问题出在下面的XAML的主角上. 如何将字符串绑定到具有ItemTemplate的属性,就像我在下面设置的那样? 为了更清楚,我可以将绑定嵌入到彼此内部{Binding Path={Binding Value}}.

这是班级:

public class Food
{
    public string Apple { get; set; }
    public string Orange { get; set; }
    public IEnumerable<KeyValuePair<string, string>> Fields
    {
        get
        {
            yield return new KeyValuePair<string, string>("Apple Label", "Apple");
            yield return new KeyValuePair<string, string>("Orange Label", "Orange");
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这是XAML:

<UserControl x:Class="MAAD.Plugins.FRACTIL.Simulation.SimulationStateView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Height="331" Width="553">
 <ListView ItemSource="{Binding Fields}">
  <ListView.ItemTemplate>
   <DataTemplate>
    <StackPanel Orientation="Horizontal">
     <TextBlock Text="{Binding Key}" />
     **<TextBlock Text="{Binding Path={Binding Value}}" />**
    </StackPanel>
   </DataTemplate>
  </ListView.ItemTemplate>
 </ListView>
</UserControl>
Run Code Online (Sandbox Code Playgroud)

Ray*_*rns 5

问题的实质是您不仅需要字段描述和名称列表,还需要具有这些字段和名称的实际对象.

您可以使用像这样的转换器向字段对象添加目标引用,并提供值访问器,如下所示:

  public class PropertyValueAccessConverter : IMultiValueConverter
  {
    object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
      var target = values[0];
      var fieldList = values[1] as IEnumerable<KeyValuePair<string,string>>;
      return
        from pair in fieldList
        select new PropertyAccessor
        {
          Name = pair.Name,
          Target = target,
          Value = target.GetType().GetProperty(target.Value),
        };
    }

    object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
    {
      throw new InvalidOperationException();
    }

    public class PropertyAccessor
    {
      public string Name
      public object Target;
      public PropertyInfo Property;

      public object Value
      {
        get { return Property.GetValue(Target, null); }
        set { Property.SetValue(Target, value, null); }
      }
    }

    public static PropertyValueAccessConverter Instance = new PropertyValueAccessConverter();
  }
Run Code Online (Sandbox Code Playgroud)

使用此转换器,您可以像这样绑定ItemsSource:

  <ListView>
    <ListView.ItemsSource>
      <MultiBinding Converter="{x:Static local:PropertyValueAccessConverter.Instance}">
        <Binding />
        <Binding Path="Fields" />
      </MultiBinding>
    </ListView.ItemsSource>
  </ListView>
Run Code Online (Sandbox Code Playgroud)

顺便说一下,实现Fields属性的一种更有效的方法是:

  public IEnumerable<KeyValuePair<string, string>> Fields
  {
    get
    {
      return new KeyValuePair<string, string>[]
      {
        new KeyValuePair<string, string>("Apple Label", "Apple");
        new KeyValuePair<string, string>("Orange Label", "Orange");
      }
    }
  }
Run Code Online (Sandbox Code Playgroud)

虽然坦率地说我会在各个属性上使用描述属性以及反射而不是对列表进行硬编码.这也将首先消除对MultiBinding的需求.