好的,在GridView中顯示嵌套字典...這可能需要一些時間和相當多的文本,所以你可能會自己煮一些新鮮的熱咖啡。準備?好吧,讓我們開始吧。
A GridView基本上只是一個ListView控件的視圖模式。 ListView控件可視化對象/值的集合(或列表)(不管這些對象可能是什麼)。 這與將要顯示的字典相關的內容將在一分鐘內解釋。
如前所述,要顯示的數據存儲在嵌套字典中。具體詞典日期類型被指定爲如下:
Dictionary< string, Dictionary<string, int > >
(外)字典的鍵表示一個文件名和應在GridView的「文件名」列中顯示。 與每個文件名關聯的(內部)字典將包含第二列和其他列的值。
如上面指定的字典是一個實現這個接口
ICollection< KeyValuePair< string, Dictionary<string, int > > >
的這實際上是需要的正是ListView控件 - 元素的集合。這個集合中的每個元素是這種類型的:
KeyValuePair< string, Dictionary<string, int > >
在KeyValuePair的關鍵是文件名。 KeyValuePair的值是包含第二個和更多列的鍵/值對的(內部)字典。 這意味着,每個KeyValuePair元素都包含恰好一個完整行的數據。
現在,更難的部分開始。對於每一列,都需要訪問來自KeyValuePair的適當數據。 不幸的是,它不適用於每一列的簡單綁定。
但是,KeyValuePair本身可以綁定到每一列,並且藉助定製的IValueConverter可以從KeyValuePair提取所需的信息。我們將不得不做出決定。我們可以使用靜態數量的不可修改列的相對簡單的方法。 或者,如果我們的目的是使動態設置,添加或刪除列變得容易,我們會投入更多的編碼工作。 下面將給出有關這兩種方法的概述。
1.簡單但靜態且不靈活的方式。
要訪問KeyValuePair(文件名)的鍵,則不需要值轉換器。對密鑰屬性的簡單綁定就足夠了。
要訪問存儲在KeyValuePair(內部)字典中的值,將使用自定義IValueConverter。 值轉換器將需要知道要提取的值的關鍵。這是作爲一個公共財產DictionaryKey實施的,它允許在XAML中指定密鑰。
[ValueConversion(typeof(KeyValuePair<string, Dictionary<string, int>>), typeof(string))]
public class GetInnerDictionaryValueConverter : IValueConverter
{
public string DictionaryKey { get; set; }
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (!(value is KeyValuePair<string, Dictionary<string, int>>))
throw new NotSupportedException();
Dictionary<string, int> innerDict = ((KeyValuePair<string, Dictionary<string, int>>) value).Value;
int dictValue;
return (innerDict.TryGetValue(DictionaryKey, out dictValue)) ? (object) dictValue : string.Empty;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
的XAML ListView控件可能再看看類似如下。假設要顯示的列是「FileName」,「A1」,「A2」,「A3」(後三個是內部字典中的鍵)。 還要注意三個自定義GetInnerDictionaryValueConverter實例,它們被創建爲靜態資源並且正在被相應的綁定使用。
<ListView x:Name="MyListGridView">
<ListView.Resources>
<My:GetInnerDictionaryValueConverter x:Key="ConverterColum_A1" DictionaryKey="A1" />
<My:GetInnerDictionaryValueConverter x:Key="ConverterColum_A2" DictionaryKey="A2" />
<My:GetInnerDictionaryValueConverter x:Key="ConverterColum_A3" DictionaryKey="A3" />
</ListView.Resources>
<ListView.View>
<GridView AllowsColumnReorder="true">
<GridViewColumn Header="FileName" DisplayMemberBinding="{Binding Key}" />
<GridViewColumn Header="A1" DisplayMemberBinding="{Binding Converter={StaticResource ConverterColum_A1}}" />
<GridViewColumn Header="A2" DisplayMemberBinding="{Binding Converter={StaticResource ConverterColum_A2}}" />
<GridViewColumn Header="A3" DisplayMemberBinding="{Binding Converter={StaticResource ConverterColum_A3}}" />
</GridView>
</ListView.View>
</ListView>
所有剩下要做的就是分配的實際字典的數據到ListView控件的的ItemsSource財產。這可以通過XAML中的數據綁定或代碼隱藏完成。
如前所述,這種方法相當直接且易於實現。缺點是列的數量是固定的,因爲列數據綁定所需的值轉換器被聲明爲靜態資源。 如果需要動態設置,添加或刪除任意DictionaryKeys的列,我們需要取消那些靜態轉換器。這導致我們採用第二種方法...
2。多一點點複雜,但允許動態容易設置/添加/刪除列
允許動態設置,添加,刪除任意DictionaryKeys列,自定義GetInnerDictionaryValueConverter可能被使用之前出臺,但是代碼 - 後面可能會變得有些複雜。 更好的方法是定義自定義的GridViewColumn類型,它也可以實現任何所需的IValueConverter邏輯並負責設置綁定。 不再需要單獨的自定義值轉換器類型,這將簡化對這些列的處理。
關於我們的示例,只需要兩個自定義列。第一個自定義列是文件名,它看起來很簡單:
public class GridViewColumnFileName : GridViewColumn
{
public GridViewColumnFileName()
{
DisplayMemberBinding = new Binding("Key")
{
Mode = BindingMode.OneWay
};
}
}
它所做的只是在代碼隱藏中設置綁定。 您可能會指出,我們也可以像前面的示例一樣使用「{綁定鍵}」綁定來保留簡單的GridViewColumn - 並且您完全正確。 我只在這裏展示這個實現來說明可能的方法。
表示來自內部詞典的值的列的自定義列類型稍微複雜一些。 作爲之前的自定義值轉換器,此自定義列需要知道正在顯示的值的鍵。 通過將此接口作爲此自定義列類型的一部分實現,此列類型可將其自身用作綁定的值轉換器。
[ValueConversion(typeof(KeyValuePair<string, Dictionary<string, int>>), typeof(string))]
public class GridViewColumnInnerDictionaryValue : GridViewColumn, IValueConverter
{
public string InnerDictionaryKey
{
get { return _key; }
set
{
if (_key == value) return;
_key = value;
if (string.IsNullOrWhiteSpace(value))
{
DisplayMemberBinding = null;
}
else if (DisplayMemberBinding == null)
{
DisplayMemberBinding = new Binding()
{
Mode = BindingMode.OneWay,
Converter = this
};
}
}
}
private string _key = null;
#region IValueConverter
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value is KeyValuePair<string, Dictionary<string, int>>)
{
Dictionary<string, int> innerDict = ((KeyValuePair<string, Dictionary<string, int>>) value).Value;
int dictValue;
return (innerDict.TryGetValue(InnerDictionaryKey, out dictValue)) ? (object) dictValue : string.Empty;
}
throw new NotSupportedException();
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
#endregion IValueConverter
}
IValueConverter接口的實現與以前完全相同。 當然,從之前GetInnerDictionaryValueConverter類型可以被用來代替執行其邏輯GridViewColumnInnerDictionaryValue, 的一部分,但再次,我想證明不同的可能性。
使用自定義字段類型看起來像這樣在創建XAML ListView控件:
<ListView x:Name="MyListGridView">
<ListView.View>
<GridView AllowsColumnReorder="true">
<My:GridViewColumnFileName Header="FileName" />
<My:GridViewColumnInnerDictionaryValue Header="A1" InnerDictionaryKey="A1" />
<My:GridViewColumnInnerDictionaryValue Header="A2" InnerDictionaryKey="A2" />
<My:GridViewColumnInnerDictionaryValue Header="A3" InnerDictionaryKey="A3" />
</GridView>
</ListView.View>
</ListView>
相反的聲明在XAML列,添加和從GridView.Columns列移除到/財產也可以在代碼隱藏中輕鬆完成。 再次,不要忘記通過XAML中的數據綁定或代碼隱藏來將ListView的ItemsSource屬性設置爲字典。
1.爲什麼哦爲什麼你想要在代碼中做到這一點? XAML有什麼問題?那麼,你的問題是什麼?有什麼異常?任何投訴?更具體的... – Noctis
我只想將內部字典的值綁定到一列,我無法這樣做,因爲在如何引用內部字典的值(結果[xyz] .values()。value ) – shivank
你能簡化你的問題嗎?目前還不清楚你想要什麼。你是否想爲字典中的每個鍵創建一個列(目前存儲的字典無關緊要)?那麼每個**行的值是多少? – elgonzo