2009-11-02 225 views
3

今天,我正在WPF UserControl上顯示一些變量的當前值。我想知道是否有辦法在WPF中創建一個超級簡單的屬性網格。問題出在下面的XAML的星號上。 如何將一個字符串綁定到ItemTemplate屬性,就像我在下面設置的那樣?爲了更清楚我可以在另一個{Binding Path={Binding Value}}中嵌入綁定。WPF動態綁定

這裏是類:

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"); 
     } 
    } 
} 

這裏是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> 

回答

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(); 
    } 

有了這個轉換器,你可以在你的ItemsSource綁定是這樣的:

<ListView> 
    <ListView.ItemsSource> 
     <MultiBinding Converter="{x:Static local:PropertyValueAccessConverter.Instance}"> 
     <Binding /> 
     <Binding Path="Fields" /> 
     </MultiBinding> 
    </ListView.ItemsSource> 
    </ListView> 

順便說一句,一個更有效的方式來實現你的字段屬性是:

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"); 
     } 
    } 
    } 

雖然坦率地說,我會使用各個屬性的描述屬性以及反射而不是硬編碼列表。這也將消除首先對MultiBinding的需求。

1

那麼,它應該僅僅是:

<TextBlock Text="{Binding Path=Value}" /> 

不過,我想我明白了什麼你正在努力。問題是KeyValuePair不是一個INotifyPropertyChange子類型(理所當然,所以不會進入),所以如果字典中的值發生更改,您將永遠不會收到通知。此外,KeyValuePair實際上是一個結構。因此,更改綁定副本上的值不會更新實際的數據源,因爲它是數據的副本。

如果您使用的模型實際上是KeyValuePair,則需要創建更具體的View-Model類來啓用此數據綁定方案。這需要是某種包裝Key的類,並且引用了基礎源(可能是Dictionary?),並且實際上會調用基礎源的值,以更新其屬性。也就是說,您仍然不會從Dictionary中獲取通知(再次假設這是您的源代碼),因爲它不會觸發任何通知,因此您將無法提供轉發通知。

+0

感謝您的帖子,但我不想綁定到價值,但對價值持有的名稱屬性。從上面的例子中,其中一個對綁定到Orange屬性的值,另一個綁定到Apple屬性。 – 2009-11-02 18:47:03

+0

Ahhhhhhhhhhhh,我明白你在說什麼。是的,那是不可能的。讓我考慮一下並修改我的答案。 – 2009-11-02 18:54:32