C # Общий пользовательский контроль WPF - PullRequest
9 голосов
/ 15 марта 2011

Я пытаюсь создать пользовательский элемент управления, который будет отображать содержимое словаря

проблема в том, что я не знаю типы ключа и значения в пользовательском элементе управления, я бы знал, когда я создаю пользовательский элемент управления, но C #, похоже, не хочет позволять мне создавать универсальный пользовательский элемент управления это позволило бы мне передать их в размещенный словарь

е

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

потому что он ссылается на сгенерированный файл в. \ Obj \ Debug \ MyCtrl.g.i.cs только для чтения

единственное решение, которое мне представляется, это создать класс с нуля и не позволить дизайнеру обрабатывать какое-либо форматирование, есть ли лучшая возможность?

, чтобы дать немного фона примерно в 8-10 местах в моем коде, мне нужно, чтобы пользователь заполнял словари значений и вместо создания 8-10 элементов управления, которые все делают одно и то же, но с разными типами (на самом деле много единственное различие времени в том, какой enum служит в качестве ключа) я хотел, чтобы один элемент управления обрабатывал это

Ответы [ 6 ]

3 голосов
/ 15 марта 2011

Вы можете использовать универсальный, как если бы вы не использовали XAML.Но если вы хотите использовать XAML для определения вашего элемента управления, вы не можете использовать универсальный

2 голосов
/ 04 апреля 2011

У меня наконец есть рабочий ответ.

Я строю элемент управления вокруг 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);
        }
    }

, затемдобавить универсальное свойство, которое вызывает расширение для приведения объектов в словарь

1 голос
/ 15 марта 2011

Возможно, вам лучше использовать MVVM и наложить все общие типы и ограничения на модель представления, а не на представление.

1 голос
/ 15 марта 2011

Как уже упоминал Стейка, вы не можете использовать дженерики в XAML. Однако вы можете создать свой универсальный пользовательский элемент управления и получить определенные типы из этого универсального класса, который вы можете использовать в XAML. Это по крайней мере уменьшает дублирование кода до некоторой степени.

В качестве идентификатора, обобщение в XAML может быть возможным, если вы поддерживаете его самостоятельно, передавая тип в качестве значения свойства. По крайней мере, я думаю, что это и есть цель этой статьи , но у меня еще не было времени попробовать ее самостоятельно.

1 голос
/ 15 марта 2011

Если вы хотите использовать свой элемент управления в 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>

Для ваших различных типов словарей вы можете иметь несколько 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}" />
0 голосов
/ 28 марта 2012

Причина, по которой вы хотите установить общий пользовательский элемент управления, заключается в том, что вы не знаете, в чем ключ и значение:

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