2017-01-06 2 views
1

Я внедрил настраиваемый элемент управления, который внутренне использует ListView в шаблоне управления. Этот ListView доступен через FindParts. Мне нужно установить свойство ListViews View в экземпляр, который я должен программно реализовать в своем настраиваемом элементе управления. Я хочу иметь возможность создать этот экземпляр из DataTemplate, который может быть привязан к свойству моего пользовательского элемента управления.Как создать экземпляр из DataTemplate

Проблема в том, что я не знаю, как создать экземпляр из DataTemplate.

Обратите внимание, что я не хочу привязывать GridView непосредственно к виду вида (например, из ResourceDictionary, где для атрибута DataTemplates x: Shared установлено значение false), поскольку это приводит к проблемам в дизайне XAML (представление не может быть разделены более чем одним ListView).

Редактировать: Durig мое обсуждение с помощью grek40 стало ясно, что невозможно предоставить GridView в DataTemplate. Таким образом, ответ, помеченный как решение, не отвечает на вопрос о том, как создать экземпляр из DataTemplate, как это подразумевается под заголовком моего вопроса.

+0

У меня такое ощущение, что в какой-то момент вы немного отстаете. ['ListView.View'] (https://msdn.microsoft.com/en-us/library/system.windows.controls.listview.view (v = vs.110) .aspx) имеет тип' ViewBase', поэтому если вы хотите передать эту часть извне в свой CustomControl, вам потребуется свойство этого типа. Возможно, какой-то образец кода поможет понять, где вы хотите «DataTemplate» во всем этом. – grek40

+0

Да, вы правы. На данный момент у меня есть DependencyProperty типа ViewBase. В ResourceDictionary у меня есть ресурсы для этого свойства и стили с помощью Setter для назначения этих ресурсов. Как я уже упоминал выше, мне пришлось установить x: Shared = false, чтобы эти Ресурсы можно было использовать в RunTime, но они приводят к проблемам во время разработки. Теперь я хочу изменить свой элемент управления, чтобы принять DataTemplate, который содержит определение GridView. Затем элемент управления должен создать экземпляр DataTemplate. Мой вопрос заключается в том, как создать экземпляр из DataTemplate. – E812

+0

Есть ли причина, по которой вы не просто связываете источник items listview и Itemtemplate? – MikeT

ответ

2

Поскольку вы не разделяли много кода, я сделал что-то из воздуха , Идея: MyCustomControl размещает предметы и для этого, ListView используется в ControlTemplate. По умолчанию GridView включается непосредственно в ControlTemplate, но это можно изменить с помощью MyCustomControl.MyView

пользовательского элемента управления:

public class MyCustomControl : ItemsControl 
{ 
    static MyCustomControl() 
    { 
     DefaultStyleKeyProperty.OverrideMetadata(typeof(MyCustomControl), new FrameworkPropertyMetadata(typeof(MyCustomControl))); 
    } 


    public ViewBase MyView 
    { 
     get { return (ViewBase)GetValue(MyViewProperty); } 
     set { SetValue(MyViewProperty, value); } 
    } 

    public static readonly DependencyProperty MyViewProperty = 
     DependencyProperty.Register("MyView", typeof(ViewBase), typeof(MyCustomControl), new FrameworkPropertyMetadata(null, new PropertyChangedCallback(OnMyViewChanged))); 

    private static void OnMyViewChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
    { 
     ((MyCustomControl)d).HasCustomView = e.NewValue != null; 
    } 



    // readonly property to support the Trigger in the ControlTemplate in order to exchange the ListView.View 
    public bool HasCustomView 
    { 
     get { return (bool)GetValue(HasCustomViewProperty); } 
     private set { SetValue(HasCustomViewPropertyKey, value); } 
    } 

    private static readonly DependencyPropertyKey HasCustomViewPropertyKey = 
     DependencyProperty.RegisterReadOnly("HasCustomView", typeof(bool), typeof(MyCustomControl), new PropertyMetadata(false)); 
    public static readonly DependencyProperty HasCustomViewProperty = HasCustomViewPropertyKey.DependencyProperty; 
} 

Контроля шаблона (обратите внимание, GridView по умолчанию и триггер для замены):

<Style TargetType="{x:Type local:MyCustomControl}"> 
    <Setter Property="Template"> 
     <Setter.Value> 
      <ControlTemplate TargetType="{x:Type local:MyCustomControl}"> 
       <Border Background="{TemplateBinding Background}" 
         BorderBrush="{TemplateBinding BorderBrush}" 
         BorderThickness="{TemplateBinding BorderThickness}"> 
        <ListView x:Name="PART_ListView" 
           ItemsSource="{Binding Items,RelativeSource={RelativeSource TemplatedParent}}"> 
         <ListView.View> 
          <GridView> 
           <GridView.Columns> 
            <GridViewColumn Header="DEF"/> 
           </GridView.Columns> 
          </GridView> 
         </ListView.View> 
        </ListView> 
       </Border> 
       <ControlTemplate.Triggers> 
        <Trigger Property="HasCustomView" Value="True"> 
         <Setter TargetName="PART_ListView" Property="View" Value="{Binding MyView,RelativeSource={RelativeSource TemplatedParent}}"/> 
        </Trigger> 
       </ControlTemplate.Triggers> 
      </ControlTemplate> 
     </Setter.Value> 
    </Setter> 
</Style> 

Использование:

<local:MyCustomControl> 
    <!--uses default view--> 
    <TextBlock Text="Item 1"/> 
    <TextBlock Text="Item 2"/> 
</local:MyCustomControl> 

<local:MyCustomControl> 
    <!--uses custom view--> 
    <local:MyCustomControl.MyView> 
     <GridView> 
      <GridView.Columns> 
       <GridViewColumn Header="ABC"/> 
      </GridView.Columns> 
     </GridView> 
    </local:MyCustomControl.MyView> 
    <TextBlock Text="Item 1"/> 
    <TextBlock Text="Item 2"/> 
</local:MyCustomControl> 

Не стесняйтесь спрашивать, остается ли что-то непонятным. Как прокомментировал, я не знаю, как применить идею DataTemplate ко всему этому.

Edit:

Ниже приведен пример с разделом ресурсов, чтобы определить некоторые данные и DataTemplate s, а также возможности их использования.

<StackPanel> 
    <StackPanel.Resources> 
     <x:Array x:Key="Items1" Type="{x:Type sys:Int32}"> 
      <sys:Int32>1</sys:Int32> 
      <sys:Int32>2</sys:Int32> 
      <sys:Int32>3</sys:Int32> 
      <sys:Int32>4</sys:Int32> 
     </x:Array> 

     <x:Array x:Key="Items2" Type="{x:Type sys:Int32}"> 
      <sys:Int32>5</sys:Int32> 
      <sys:Int32>4</sys:Int32> 
      <sys:Int32>6</sys:Int32> 
      <sys:Int32>7</sys:Int32> 
     </x:Array> 

     <CollectionViewSource x:Key="ItemsSource1" Source="{StaticResource Items1}"/> 
     <CollectionViewSource x:Key="ItemsSource2" Source="{StaticResource Items2}"/> 

     <DataTemplate x:Key="IntegerListTemplate1"> 
      <local:MyCustomControl ItemsSource="{Binding}"> 
       <!--uses default view--> 
      </local:MyCustomControl> 
     </DataTemplate> 

     <DataTemplate x:Key="IntegerListTemplate2"> 
      <local:MyCustomControl ItemsSource="{Binding}"> 
       <!--uses custom view--> 
       <local:MyCustomControl.MyView> 
        <GridView> 
         <GridView.Columns> 
          <GridViewColumn Header="ABC"/> 
         </GridView.Columns> 
        </GridView> 
       </local:MyCustomControl.MyView> 
      </local:MyCustomControl> 
     </DataTemplate> 
    </StackPanel.Resources> 
    <!--the default view--> 
    <ContentControl ContentTemplate="{StaticResource IntegerListTemplate1}" Content="{Binding Source={StaticResource ItemsSource1}}"/> 
    <Separator Margin="3"/> 
    <!--same items other view--> 
    <ContentControl ContentTemplate="{StaticResource IntegerListTemplate2}" Content="{Binding Source={StaticResource ItemsSource1}}"/> 
    <Separator Margin="3"/> 
    <!--different items same view as second one, no complaints about reusing--> 
    <ContentControl ContentTemplate="{StaticResource IntegerListTemplate2}" Content="{Binding Source={StaticResource ItemsSource2}}"/> 
</StackPanel> 

Edit 2, нацеливание закомментированного MCVE:

Я бы решить эту проблему именно так, как я уже объяснил в своей первой редакции. Превратите свой контроль в DataTemplate, а не в стиль.

Заменить в MainWindow.xaml:

<!-- old --> 
<myctrls:MyControl Grid.Row="0" Grid.Column="0" Style="{StaticResource AddressStyle}" ItemsSource="{Binding Addresses}"/> 
<!-- new --> 
<ContentControl Grid.Row="0" Grid.Column="0" ContentTemplate="{StaticResource AddressTemplate}" Content="{Binding Addresses}"/> 

То же самое с другими вхождений.

В MyControlStyles.xaml (или переименованный файл, который указывает на использование DataTemplate), объединить ресурс GridView и Style с myctrls:MyControl в DataTemplate.

Старый:

<GridView x:Key="AddressGridView" x:Shared="False"> 
    <GridViewColumn Header="City" Width="Auto" > 
     <GridViewColumn.CellTemplate> 
      <DataTemplate> 
       <TextBlock Text="{Binding City}" HorizontalAlignment="Left"/> 
      </DataTemplate> 
     </GridViewColumn.CellTemplate> 
    </GridViewColumn> 
    <GridViewColumn Header="Country" Width="Auto" > 
     <GridViewColumn.CellTemplate> 
      <DataTemplate> 
       <TextBlock Text="{Binding Country}" HorizontalAlignment="Left"/> 
      </DataTemplate> 
     </GridViewColumn.CellTemplate> 
    </GridViewColumn> 
</GridView> 

<Style x:Key="AddressStyle" TargetType="{x:Type myctrls:MyControl}"> 
    <Setter Property="SuggestionsView" Value="{DynamicResource AddressGridView}"/> 
</Style> 

Новое:

<DataTemplate x:Key="AddressTemplate"> 
    <!-- the base control --> 
    <myctrls:MyControl ItemsSource="{Binding}"> 
     <!-- this was previously assigned by AddressStyle --> 
     <myctrls:MyControl.SuggestionsView> 
      <!-- this was previously the AddressGridView --> 
      <!-- Same as before, only removed the x:Key and x:Shared --> 
      <GridView> 
       <GridViewColumn Header="City" Width="Auto" > 
        <GridViewColumn.CellTemplate> 
         <DataTemplate> 
          <TextBlock Text="{Binding City}" HorizontalAlignment="Left"/> 
         </DataTemplate> 
        </GridViewColumn.CellTemplate> 
       </GridViewColumn> 
       <GridViewColumn Header="Country" Width="Auto" > 
        <GridViewColumn.CellTemplate> 
         <DataTemplate> 
          <TextBlock Text="{Binding Country}" HorizontalAlignment="Left"/> 
         </DataTemplate> 
        </GridViewColumn.CellTemplate> 
       </GridViewColumn> 
      </GridView> 
     </myctrls:MyControl.SuggestionsView> 
    </myctrls:MyControl> 
</DataTemplate> 

же процедура ProductsStyle.

Если вам не нравится подход к подключению ContentControl, рассмотрите создание дополнительных режимов просмотра, которые затем собирают коллекции, например AddressListViewModel. Это позволит вам обрабатывать DataTemplate на DataType вместо ключа ресурса и явного использования в ContentControl.

+0

Ваш код довольно близок к моей проблеме. Извините, что я не придумал нечто подобное. Поскольку элемент управления используется для разных типов элементов, я определил некоторые стили для них в ResourceDictionary: '' – E812

+0

и ' ' – E812

+0

Это работает во время выполнения, но при определенных условиях во время разработки XAML-Designer показывает ошибку.« Просмотр не может использоваться более чем одним списком ListView ». Чтобы избавиться от проблемы, я хотел бы представить свойство зависимостей типа DataTemplate. Затем я бы обернул ресурсы GridView в DataTemplates и вместо того, чтобы назначать экземпляры GridView для свойства MyView, я бы назначил эти DataTemplates новому свойству. В методе OnApplyTemplate моего пользовательского элемента управления я хотел бы создать экземпляр, соответствующий шаблону данных, и присвоить его свойству MyView. – E812

0

Вы могли бы реализовать свой собственный DataTemplateSelector, который динамически создает свой разовый использовать DataTemplate, примерно так:

public DataTemplate GenerateTemplate() { 
    var template = new DataTemplate(); 
    var p = new FrameworkElementFactory(typeof(Grid)); 
    p.SetValue(FrameworkElement.HorizontalAlignmentProperty, HorizontalAlignment.Left); 
    p.SetValue(FrameworkElement.VerticalAlignmentProperty, VerticalAlignment.Center); 
    ... 
    template.VisualTree = p; 
    return template; 
} 
+0

Мне нужно сделать это наоборот. Мне нужно создать экземпляр из DataTemplate, который уже назначен собственности моего таможенного контроля. – E812

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