C#通用用户控件WPF

时间:2011-03-15 10:45:46

标签: c# wpf generics user-controls

我正在尝试构建一个显示词典内容的用户控件

问题是我不知道用户控件中键和值的类型,我知道在创建用户控件时,C#似乎不想让我创建一个通用用户控件这会让我把它们传递给托管字典

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

因为它引用了。\ Obj \ Debug \ MyCtrl.g.i.cs中生成的文件 这是只读的

向我展示的唯一解决方案是从头开始创建类,而不是让设计人员处理任何格式化是否有更好的可能性?

在我的代码中提供大约8-10个位置的一些背景我需要用户填充值的字典而不是构建8-10个控件,它们都完全相同但具有不同的类型(事实上很多当时唯一的区别是哪个枚举用作关键字)我想要一个控件来处理这个

6 个答案:

答案 0 :(得分:3)

您可以使用generic,就像您不使用XAML一样。但是,如果您想使用XAML来定义控件,则不能使用泛型

答案 1 :(得分:2)

我终于得到了一个有效的答案。

我围绕使用对象的Hashtable构建Control

然后添加对象类的扩展

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

然后添加一个调用扩展的泛型属性,将对象强制转换为Dictionary

答案 2 :(得分:1)

如果您希望能够在xaml中使用您的控件,您将无法以这种方式创建通用UserControl,因为WPF不支持它。你会如何在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>

对于各种字典类型,您可以为每种不同的字典类型使用多个DataTemplate,并使用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 :(得分:1)

正如Steyca所说,你不能在XAML中使用泛型。但是,您可以创建通用用户控件,并从此通用类派生特定类型,可以在XAML中使用。这至少可以在一定程度上减少代码重复。

作为旁注,如果您自己支持XAML中的泛型,则可以将Type作为属性的值传递。至少,我认为这是this article的意图,但我没有时间自己尝试。

答案 4 :(得分:1)

您可能最好使用MVVM,并将所有通用类型和约束放在viewmodel上,而不是视图。

答案 5 :(得分:0)

您想要设置通用用户控件的原因是因为您不知道其中的键和值是什么:

 private Dictionary<TKey,TValue> someDictionary;
我相信

类型将会提前。如果是这种情况,则将您的词典声明为:

private Dictionary<dynamic,dynamic> someDictionary

然后您将能够为其添加任何类型的键和值。所以请确保如果你键是一个int而你的值是一个字符串,那么总是遵循那个模式。例如,编译器将允许您编译此代码:

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