2015-03-12 3 views
1

У меня есть некоторые проблемы с настраиваемым элементом управления, который мне нужно создать. Я пытаюсь объяснить вам мои потребности в первую очередьWPF Customcontrol, Templates, Inheritance и Dependencyproperties

Мне нужно иметь выпадающее поле, которое позволяет проверять несколько элементов во время (с флажком), но я хочу, чтобы он был достаточно умным, чтобы привязываться к определенному типу.

Я нашел несколько MultiSelectionComboBox, но ни один из них не отражает мою потребность. Btw моя главная проблема в том, что я хочу иметь общий класс как

public class BaseClass<T> : BaseClass 
{ 
    public static readonly DependencyProperty ItemsSourceProperty = 
     DependencyProperty.Register("ItemsSource", typeof(IEnumerable<T>), typeof(BaseClass<T>), new FrameworkPropertyMetadata(null, 
new PropertyChangedCallback(BaseClass<T>.OnItemsSourceChanged))); 

    private static void OnItemsSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
    { 
     int i = 0; 
     //MultiSelectComboBox control = (MultiSelectComboBox)d; 
     //control.DisplayInControl(); 
    } 

    public IEnumerable<T> ItemsSource 
    { 
     get { return (IEnumerable<T>)GetValue(ItemsSourceProperty); } 
     set 
     { 
      SetValue(ItemsSourceProperty, value); 
     } 
    } 
} 

public class BaseClass : Control 
{ 

} 

и больше контекста конкретного элемента, например

public class MultiCurr : BaseClass<Currency> 
{ 
    static MultiCurr() 
    { 
     DefaultStyleKeyProperty.OverrideMetadata(typeof(MultiCurr), new FrameworkPropertyMetadata(typeof(MultiCurr))); 
    } 
} 

В моей App.xaml я определил ресурс как

<ResourceDictionary> 
     <Style TargetType="local:MultiCurr"> 
      <Setter Property="Template"> 
       <Setter.Value> 
        <ControlTemplate TargetType="local:MultiCurr"> 
         <ComboBox Width="120" Background="Red" Height="30" ItemsSource="{Binding ItemsSource}" DisplayMemberPath="Description" ></ComboBox> 
        </ControlTemplate> 
       </Setter.Value> 
      </Setter> 
     </Style> 
    </ResourceDictionary> 

В моей MainWindow я создал объект как

<Grid> 
    <local:MultiCurr x:Name="test" ItemsSource="{Binding Currencies}"></local:MultiCurr> 
</Grid> 

и MainWindow.cs определяется как

общественный частичный класс MainWindow: Window, INotifyPropertyChanged { частные валюты IList;

public MainWindow() 
    { 
     InitializeComponent(); 
     this.DataContext = this; 
     this.Loaded += MainWindow_Loaded; 
    } 

    void MainWindow_Loaded(object sender, RoutedEventArgs e) 
    { 
     var lst = new List<Currency>(); 
     for (int i = 0; i < 10; i++) 
     { 
      var curr = new Currency 
      { 
       ID = i, 
       Description = string.Format("Currency_{0}", i) 
      }; 

      lst.Add(curr); 
     } 

     Currencies = lst; 
    } 
    public IList<Currency> Currencies 
    { 
     get 
     { 
      return this.currencies; 
     } 
     set 
     { 
      this.currencies = value; 
      NotifyPropertyChanged("Currencies"); 

     } 
    } 

    public event PropertyChangedEventHandler PropertyChanged; 

    // This method is called by the Set accessor of each property. 
    // The CallerMemberName attribute that is applied to the optional propertyName 
    // parameter causes the property name of the caller to be substituted as an argument. 
    private void NotifyPropertyChanged(String propertyName = "") 
    { 
     if (PropertyChanged != null) 
     { 
      PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); 
     } 
    } 
} 

И вот результат ... The result is this one

Мне было интересно, что я делаю неправильно? возможно ли, чего я добиваюсь?

Благодаря

UPDATE # 1:

Я видел, что основной проблемой является DataContext обычая UserControl

<Application.Resources> 
    <ResourceDictionary> 
     <Style TargetType="local:MultiCurr"> 
      <Setter Property="Template"> 
       <Setter.Value> 
        <ControlTemplate TargetType="local:MultiCurr"> 
         <ComboBox Width="120" Background="Red" Height="30" ItemsSource="{Binding **Currencies**}" DisplayMemberPath="{Binding **DisplayMemeberPath**}" ></ComboBox> 
        </ControlTemplate> 
       </Setter.Value> 
      </Setter> 
     </Style> 
    </ResourceDictionary> 
</Application.Resources> 

Если я ставлю ItemsSource в валюте (это это свойство MainWindow). Если я ставлю ItemsSource и DisplayMemberPath (которые определены в BaseClass нет .. как я могу установить контекст UserControl к себе?)

UPDATE # 2 Я добавил GoogleDrive ссылку на проект here если кто-то хочет попробовать Решение

Благодаря

+0

В вашем шаблоне привязки шаблона используйте привязку шаблона. –

+0

является 'currencies'' ObservableCollection'? И, кстати, у вас не должно быть сеттеров для ваших списков. – Default

ответ

1
  1. выпадающий не подходит для управления множественного выбора, потому что он дал поведение, что когда лет выберите пункт, выпадающий закрывается I tself. Вот почему Combobox не имеет свойства SelectionMode, такого как ListBox. Я думаю, что ListBox внутри расширителя - это то, что вам нужно.
  2. Общие типы не могут идти. WPF обрабатывает этот другой, лучший способ. Возьмите список в качестве примера. Если вы связываете listbox.itemssource с общей наблюдаемой коллекцией и пытаетесь определить e.g ItemTemplate, вы получаете полный intellisense при написании привязок и предупреждении, если вы привязываетесь к уже существующему свойству. http://visualstudiomagazine.com/articles/2014/03/01/~/media/ECG/visualstudiomagazine/Images/2014/03/Figure8.ashx Дизайнер WPF автоматически распознает параметр типа вашей наблюдаемой коллекции. Из cousre вам нужно указать тип datacontext на вашей странице, используя что-то вроде этого: d:DataContext="{d:DesignInstance search:AdvancedSearchPageViewModel}". Однако ваш контроль не должен быть и не должен знать о типах товаров.

Следующий пример демонстрирует контроль, который отвечает вашим требованиям:

<Expander> 
    <Expander.Header> 
     <ItemsControl ItemsSource="{Binding ElementName=PART_ListBox, Path=SelectedItems}"> 
      <ItemsControl.ItemTemplate> 
       <DataTemplate> 
        <TextBlock> 
         <Run Text="{Binding Mode=OneWay}" /> 
         <Run Text=";" /> 
        </TextBlock> 
       </DataTemplate> 
      </ItemsControl.ItemTemplate> 
      <ItemsControl.ItemsPanel> 
       <ItemsPanelTemplate> 
        <WrapPanel /> 
       </ItemsPanelTemplate> 
      </ItemsControl.ItemsPanel> 
     </ItemsControl> 
    </Expander.Header> 
    <Expander.Content> 
     <ListBox x:Name="PART_ListBox" SelectionMode="Multiple"> 
      <ListBox.ItemsSource> 
       <x:Array Type="system:String"> 
        <system:String>ABC</system:String> 
        <system:String>DEF</system:String> 
        <system:String>GHI</system:String> 
        <system:String>JKL</system:String> 
       </x:Array> 
      </ListBox.ItemsSource> 
     </ListBox> 
    </Expander.Content> 
</Expander> 

Я рекомендую вам создать контроль, производный от ListBox (не UserControl). У меня есть hardcoded datatemplates, но вы должны раскрывать их в своих пользовательских свойствах зависимостей и использовать TemplateBinding в вашем шаблоне управления. Конечно, вам нужно модифицировать расширитель, чтобы он выглядел как combobox и стиль ListBoxItem, поэтому он выглядит как CheckBox, но это легко.

+0

Спасибо за ваше предложение, но в моем случае я 90% на работе ... combobox отлично работает. У меня просто есть проблемы с передачей ItemsSource из mainview в usercontrol ... btw Я посмотрю спасибо – advapi

+0

You необходимо создать свойство ItemsSource dependecyproperty в вашем UserControl. И привяжите привязку к своей комбинации или что-то вроде этого: Liero

+0

Liero, если вы посмотрите на мой код выше, у меня есть combobox, определенный в стиле, I Я только что создал свойство в BaseClass , из которого наследуется MultiCurr .. если в моем ресурсе App я указываю Валюты как itemsource (который является свойством MainWindow, он работает), если я укажу ItemSource не – advapi

Смежные вопросы