2011-03-15 61 views
7

我試圖建立一個用戶控件,將顯示一個字典的內容C#通用用戶控件WPF

問題是我不知道用戶控件中的鍵和值的類型,我就知道在我創建用戶控制,但C#似乎並不想讓我創建一個通用的用戶控件,它可以讓我把它們放入一個託管字典點

public class MyCtrl<TKey,TValue> : UserControl 
{ 
    private Dictionary<TKey,TValue> 
} 

因爲它引用。\ Obj \ Debug \ MyCtrl.gics中的生成文件 這是隻讀

向我展示自己的唯一解決方案是從頭開始創建類,而不讓設計人員處理任何格式是否有更好的可能性?

給我的代碼約8-10個地方給我一點背景我需要用戶填充值的字典,而不是建立8-10控件都做同樣的事情,但不同的類型(事實上很多時候唯一的區別就是哪個枚舉作爲鍵)我想要一個控件來處理這個

回答

3

您可以像使用XAML一樣使用泛型。但是如果你想使用XAML來定義你的控件,你不能使用通用的

+0

我打算把它添加到XAML的方法是通過充當一個容器,內容控制,我然後實例化通用代碼,並添加它的容器。 – MikeT 2011-03-15 14:09:42

1

如果你想能夠在xaml中使用你的控件,你將無法像WPF那樣創建一個通用的UserControl,不支持它。你將如何聲明性地在xaml中實例化該類型?

我會看看其他控件如何處理這樣的事情。例如,ListBox允許您填充項目列表,而不考慮解析到其ItemsSource中的集合類型。

<ListBox ItemsSource="{Binding DictionaryItems}" > 
    <ListBox.ItemTemplate> 
     <DataTemplate> 
     <StackPanel Orientation="Horizontal"> 
      <TextBlock Text="{Binding Key}" /> 
      <TextBlock Text="{Binding Value}" /> 
     </StackPanel> 
     </DataTemplate> 
    </ListBox.ItemTemplate> 
</ListBox> 

對於各種字典類型,您可以爲每個不同的字典類型使用多個DataTemplates,並使用TemplateSelector進行切換。

public class SomeSelector : DataTemplateSelector 
{ 
    public DataTemplate Template1 { get; set; } 
    public DataTemplate Template2 { get; set; } 

    public override DataTemplate SelectTemplate(object item, DependencyObject container) 
    { 
     if (item is IDictionary<string, int>) 
     { 
     return Template1; 
     } 

     return Template2; 
    } 
} 

然後在XAML

<UserControl.Resources> 
    <DataTemplate x:Key="Template1"> 
     <StackPanel Orientation="Horizontal"> 
     <TextBlock Text="{Binding Key}" /> 
     <TextBlock Text="{Binding Value}" /> 
     </StackPanel> 
    </DataTemplate> 

    <DataTemplate x:Key="Template2> 
     <StackPanel Orientation="Vertical"> 
     <TextBlock Text="{Binding Key}" /> 
     <TextBlock Text="{Binding Value}" /> 
     </StackPanel> 
    </DataTemplate> 

    <SomeSelector x:Key="SomeSelector" Template1="{StaticResource Template1}" Template2="{StaticResource Template2}" /> 
</UserControl.Resources> 

<ListBox ItemsSource="{Binding DictionaryItems}" ItemTemplateSelector="{StaticResource SomeSelector}" /> 
+3

我不得不說,當MS重寫.net以包含好的類型安全的泛型時,它總是讓我感到奇怪,他們並沒有決定將它包含在設計者的控件中。 畢竟我確定我不是唯一一個能夠看到類型安全控制的獎金 – MikeT 2011-03-15 14:18:59

1

正如Steyca提到的,你不能在XAML中使用泛型。然而,你可以創建你的通用用戶控件,並從這個通用類中派生出特定的類型,你可以使用可以在XAML中使用。這至少在一定程度上減少了代碼重複。

作爲旁註,如果您自己支持XAML,則可以使用XAML中的泛型,方法是將Type作爲屬性的值傳遞。至少,我相信這是this article的意圖,但我沒有時間自己嘗試一下。

+0

我將控制類的焦點轉移到控件類上,而不是像用戶控件那樣通過設計器支持實例化,所以轉儲XAML。這意味着我必須計劃所有的圖形無法看到它們,但至少擺脫了我無法覆蓋的生成代碼 – MikeT 2011-03-15 14:16:47

1

使用MVVM可能會更好,並將所有泛型和約束放在您的視圖模型上,而不是視圖中。

2

我終於有一個工作的答案。

我建立一個圍繞使用對象

一個Hashtable的控制,然後添加擴展的對象類

public static bool TryParse<TType>(this object obj, out TType result) 
    { 
     try 
     { 
      result = (TType)Convert.ChangeType(obj, typeof(TType)); 
      return true; 
     } 
     catch 
     { 
      result = default(TType); 
      return false; 
     } 
    } 
    public static TType Parse<TType>(this object obj) where TType : struct 
    { 
     try 
     { 
      return (TType)Convert.ChangeType(obj, typeof(TType)); 
     } 
     catch 
     { 
      throw new InvalidCastException("Cant cast object to " + typeof(TType).Name); 
     } 
    } 

然後添加調用擴展到投的對象字典

的通用屬性
0

你爲什麼要設置一個通用的用戶控件的原因是因爲你不知道什麼鍵和值:

private Dictionary<TKey,TValue> someDictionary; 

類型將提前我相信。如果是這種情況,那麼聲明您的字典爲:

private Dictionary<dynamic,dynamic> someDictionary 

然後您將能夠添加任何類型的鍵和值。所以確保如果你的key是一個int,並且你的值是一個字符串,那麼總是遵循該模式。例如,編譯器將讓你編譯此代碼:

 Dictionary<dynamic, dynamic> myDictionAry = new Dictionary<dynamic, dynamic>(); 
     myDictionAry.Add(1, "kd"); 
     myDictionAry.Add("kjdf", 3);