2017-05-17 2 views
0

J'ai un contrôle personnalisé WPF dans lequel j'ai une Listview. Le contrôle a des propriétés de dépendance pour ItemSource et ItemTemplate de ListView. Tout cela fonctionne très bien. Ce que je voudrais faire est de pouvoir définir un ItemTemplate par défaut afin que je ne finisse pas avec object.ToString() pour les Items dans la Listview.Spécifier la valeur par défaut ItemTemplate

Voici le style Xaml pour mon contrôle.

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
       xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
       xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
       xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
       xmlns:btl="clr-namespace:Btl.Controls" 
       mc:Ignorable="d"> 

<DataTemplate x:Key="DefaultListViewItem" DataType="btl:SelectableItem"> 
    <StackPanel Orientation="Horizontal"> 
     <CheckBox Margin="2" IsChecked="{Binding Selected}" /> 
     <TextBlock Margin="5,2" Text="{Binding Description}" VerticalAlignment="Center"/> 
    </StackPanel> 
</DataTemplate> 
<Style TargetType="{x:Type btl:SelectItemsControl}"> 
    <Setter Property="Template"> 
     <Setter.Value> 
      <ControlTemplate TargetType="{x:Type btl:SelectItemsControl}"> 
       <Grid> 
        <Grid.RowDefinitions> 
         <RowDefinition Height="Auto"/> 
         <RowDefinition Height="Auto"/> 
         <RowDefinition Height="*"/> 
         <RowDefinition Height="Auto"/> 
        </Grid.RowDefinitions> 
        <TextBlock x:Name="PART_Title" Margin="10" 
           Text="{Binding Path=Title, 
             RelativeSource={RelativeSource TemplatedParent}}" 
           TextWrapping="Wrap" 
           Visibility="Collapsed"/> 
        <GroupBox Grid.Row="2" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"> 
         <GroupBox.Header> 
          <StackPanel Orientation="Horizontal"> 
           <CheckBox x:Name="PART_EnabledCheck" Margin="0,5" 
              Content="" 
              IsChecked="{Binding Path=EnabledCheck, Mode=TwoWay, 
              RelativeSource={RelativeSource TemplatedParent}}"/> 
           <TextBlock x:Name="PART_GroupTitle" VerticalAlignment="Center" 
              Text="{Binding Path=GroupTitle, 
             RelativeSource={RelativeSource TemplatedParent}}"/> 
          </StackPanel> 
         </GroupBox.Header> 
         <Grid> 
          <Grid.RowDefinitions> 
           <RowDefinition Height="*"/> 
           <RowDefinition Height="Auto"/> 
          </Grid.RowDefinitions> 
          <DockPanel HorizontalAlignment="Stretch" VerticalAlignment="Stretch" > 
           <ListView x:Name="PART_Items" 
              ItemsSource="{Binding ItemSourceList, 
               RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type btl:SelectItemsControl}}}" 
              ItemTemplate="{Binding ItemTemplate, 
               RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type btl:SelectItemsControl}}}" 
              HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="2" 
              > 
           </ListView> 
          </DockPanel> 
          <CheckBox x:Name="PART_SelectAllCheck" Grid.Row="1" Margin="11,5" Content="Select All" 
             IsChecked="{Binding Selected}"/> 
         </Grid> 
        </GroupBox> 

       </Grid> 
      </ControlTemplate> 
     </Setter.Value> 
    </Setter> 
</Style> 

Voici mon contrôle

using System; 
using System.Collections; 
using System.Collections.Generic; 
using System.Linq; 
using System.Windows; 
using System.Windows.Controls; 
using System.Windows.Data; 
using System.Windows.Media; 

namespace Btl.Controls 
{ 
/// <summary> 
/// 
/// </summary> 
/// 
[TemplatePart(Name = "PART_Title", Type = typeof(TextBlock))] 
[TemplatePart(Name = "PART_EnabledCheck", Type = typeof(CheckBox))] 
[TemplatePart(Name = "PART_GroupTitle", Type = typeof(TextBlock))] 
[TemplatePart(Name = "PART_Items", Type = typeof(ListView))] 
[TemplatePart(Name = "PART_SelectAllCheck", Type = typeof(CheckBox))] 
public class SelectItemsControl : UserControl 
{ 

    #region DependencyProperties 

    #region Title 
    public string Title 
    { 
     get { return (string)GetValue(TitleProperty); } 
     set { SetValue(TitleProperty, value); } 
    } 

    // Using a DependencyProperty as the backing store for Title. This enables animation, styling, binding, etc... 
    public static readonly DependencyProperty TitleProperty = 
     DependencyProperty.Register("Title", typeof(string), typeof(SelectItemsControl), new PropertyMetadata(string.Empty, 
      OnTitleChanged 
      )); 

    private static void OnTitleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
    { 

     var control = d as TextBlock; 
     if (control != null) 
      if (string.IsNullOrEmpty(e.NewValue.ToString())) 
     { 
      control.Visibility = string.IsNullOrEmpty(e.NewValue.ToString()) ? Visibility.Collapsed : Visibility.Visible; 
     } 

    } 


    #endregion 

    #region HasEnabledCheck 
    public bool HasEnabledCheck 
    { 
     get { return (bool)GetValue(HasEnabledCheckProperty); } 
     set { SetValue(HasEnabledCheckProperty, value); } 
    } 

    // Using a DependencyProperty as the backing store for EnabledCheck. This enables animation, styling, binding, etc... 
    public static readonly DependencyProperty HasEnabledCheckProperty = 
     DependencyProperty.Register("HasEnabledCheck", typeof(bool), typeof(SelectItemsControl), new UIPropertyMetadata(false)); 
    #endregion 

    #region EnabledCheck 
    public bool EnabledCheck 
    { 
     get { return (bool)GetValue(EnabledCheckProperty); } 
     set { SetValue(EnabledCheckProperty, value); } 
    } 

    // Using a DependencyProperty as the backing store for EnabledCheck. This enables animation, styling, binding, etc... 
    public static readonly DependencyProperty EnabledCheckProperty = 
     DependencyProperty.Register("EnabledCheck", typeof(bool), typeof(SelectItemsControl), new UIPropertyMetadata(true)); 
    #endregion 

    #region GroupTitle 
    public string GroupTitle 
    { 
     get { return (string)GetValue(GroupTitleProperty); } 
     set { SetValue(GroupTitleProperty, value); } 
    } 

    // Using a DependencyProperty as the backing store for GroupTitle. This enables animation, styling, binding, etc... 
    public static readonly DependencyProperty GroupTitleProperty = 
     DependencyProperty.Register("GroupTitle", typeof(string), typeof(SelectItemsControl), new UIPropertyMetadata("")); 

    #endregion 

    #region ItemSourceList 
    public IEnumerable<ISelectable> ItemSourceList 
    { 
     get { return (IEnumerable<ISelectable>)GetValue(ItemSourceListProperty); } 
     set { SetValue(ItemSourceListProperty, value); } 
    } 

    // Using a DependencyProperty as the backing store for Items. This enables animation, styling, binding, etc... 
    public static readonly DependencyProperty ItemSourceListProperty = 
     DependencyProperty.Register("ItemSourceList", typeof(IEnumerable), typeof(SelectItemsControl)); 


    #endregion 

    #region ItemTemplate 

    public DataTemplate ItemTemplate 
    { 
     get { return (DataTemplate)GetValue(ItemTemplateProperty); } 
     set { SetValue(ItemTemplateProperty, value); } 
    } 

    // Using a DependencyProperty as the backing store for MyProperty. This enables animation, styling, binding, etc... 
    public static readonly DependencyProperty ItemTemplateProperty = 
     DependencyProperty.Register("ItemTemplate", typeof(DataTemplate), typeof(SelectItemsControl), 
     new UIPropertyMetadata(default(DataTemplate))); 

    #endregion 


    #region DescriptionTemplate 

    public DataTemplate DescriptionTemplate 
    { 
     get { return (DataTemplate)GetValue(DescriptionTemplateProperty); } 
     set { SetValue(DescriptionTemplateProperty, value); } 
    } 

    // Using a DependencyProperty as the backing store for MyProperty. This enables animation, styling, binding, etc... 
    public static readonly DependencyProperty DescriptionTemplateProperty = 
     DependencyProperty.Register("DescriptionTemplate", typeof(DataTemplate), typeof(SelectItemsControl), 
     new UIPropertyMetadata(default(DataTemplate), OnDescriptionTemplateChanged)); 

    private static void OnDescriptionTemplateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
    { 
    } 

    #endregion 

    #region ItemSelected 

    public bool ItemSelected 
    { 
     get { return (bool)GetValue(ItemSelectedProperty); } 
     set { SetValue(ItemSelectedProperty, value); } 
    } 

    // Using a DependencyProperty as the backing store for EnabledCheck. This enables animation, styling, binding, etc... 
    public static readonly DependencyProperty ItemSelectedProperty = 
     DependencyProperty.Register("ItemSelectedCheck", typeof(bool), typeof(SelectItemsControl), new UIPropertyMetadata(false)); 

    #endregion 

    #region ItemDescription 



    public string ItemDescription 
    { 
     get { return (string)GetValue(ItemDescriptionProperty); } 
     set { SetValue(ItemDescriptionProperty, value); } 
    } 

    // Using a DependencyProperty as the backing store for ItemDescription. This enables animation, styling, binding, etc... 
    public static readonly DependencyProperty ItemDescriptionProperty = 
     DependencyProperty.Register("ItemDescription", typeof(string), typeof(SelectItemsControl), new UIPropertyMetadata("")); 


    #endregion 

    #region SelectAllCheck 
    public bool SelectAll 
    { 
     get { return (bool)GetValue(SelectAllProperty); } 
     set { SetValue(SelectAllProperty, value); } 
    } 

    // Using a DependencyProperty as the backing store for SelectAll. This enables animation, styling, binding, etc... 
    public static readonly DependencyProperty SelectAllProperty = 
     DependencyProperty.Register("SelectAll", typeof(bool), typeof(SelectItemsControl), new UIPropertyMetadata(false)); 


    #endregion 

    #endregion 

    #region Private Members 

    private TextBlock _partTitle; 
    private CheckBox _partEnabledCheck; 
    private TextBlock _partGroupTitle; 
    private ListView _partItemsListView; 
    private CheckBox _partSelectAllCheck; 

    #endregion 

    /// <summary> 
    /// 
    /// </summary> 
    static SelectItemsControl() 
    { 
     DefaultStyleKeyProperty.OverrideMetadata(typeof(SelectItemsControl), 
      new FrameworkPropertyMetadata(typeof(SelectItemsControl))); 
    } 

    public SelectItemsControl() 
    { 
     Loaded += OnLoaded; 
     Unloaded += OnUnloaded; 
    } 

    private void OnLoaded(object sender, RoutedEventArgs routedEventArgs) 
    { 
     if (ItemTemplate == null) 
     { 
      CreateDefaultItemTemplate(); 
     } 
     PresentationSource presentationSource = PresentationSource.FromVisual((Visual)sender); 

     // Subscribe to PresentationSource's ContentRendered event 
     // ReSharper disable once PossibleNullReferenceException 
     presentationSource.ContentRendered += SelectItemsControl_ContentRendered; 
    } 

    private void SelectItemsControl_ContentRendered(object sender, EventArgs e) 
    { 
     // Don't forget to unsubscribe from the event 
     ((PresentationSource)sender).ContentRendered -= SelectItemsControl_ContentRendered; 
     ListenToSelectedCheckBoxClickEvent(_partItemsListView, true); 
    } 

    private void OnUnloaded(object sender, RoutedEventArgs e) 
    { 
     ListenToSelectedCheckBoxClickEvent(_partItemsListView, false); 
    } 

    private void CreateDefaultItemTemplate() 
    { 
     DataTemplate template = new DataTemplate { DataType = typeof(ListViewItem) }; 
     FrameworkElementFactory stackPanelFactory = new FrameworkElementFactory(typeof(StackPanel)); 
     stackPanelFactory.SetValue(StackPanel.OrientationProperty, Orientation.Horizontal); 

     FrameworkElementFactory selected = new FrameworkElementFactory(typeof(CheckBox)); 
     selected.SetBinding(TextBlock.TextProperty, new Binding("Selected")); 
     stackPanelFactory.AppendChild(selected); 

     FrameworkElementFactory title = new FrameworkElementFactory(typeof(TextBlock)); 
     title.SetBinding(TextBlock.TextProperty, new Binding("Description")); 
     stackPanelFactory.AppendChild(title); 
    } 

    public override void OnApplyTemplate() 
    { 
     base.OnApplyTemplate(); 

     // Code to get the Template parts as instance member 
     _partTitle = GetTemplateChild("PART_Title") as TextBlock; 
     _partEnabledCheck = GetTemplateChild("PART_EnabledCheck") as CheckBox; 
     _partGroupTitle = GetTemplateChild("PART_GroupTitle") as TextBlock; 
     _partItemsListView = GetTemplateChild("PART_Items") as ListView; 
     //_partItemSelectedCheck = GetTemplateChild("PART_ItemSelectedCheck") as CheckBox; 
     _partSelectAllCheck = GetTemplateChild("PART_SelectAllCheck") as CheckBox; 

     if (_partTitle == null || _partEnabledCheck == null || _partGroupTitle == null || _partItemsListView == null || 
      _partSelectAllCheck == null) 
     { 
      throw new NullReferenceException("Template parts not available"); 
     } 

     // set visibility 
     _partEnabledCheck.Visibility = HasEnabledCheck ? Visibility.Visible : Visibility.Collapsed; 
     _partEnabledCheck.Click += PartEnabledCheckOnClick; 
     _partTitle.Visibility = string.IsNullOrEmpty(_partTitle.Text) ? Visibility.Collapsed : Visibility.Visible; 
     _partGroupTitle.Visibility = string.IsNullOrEmpty(_partGroupTitle.Text) ? Visibility.Collapsed : Visibility.Visible; 
     _partSelectAllCheck.Click += PartSelectAllCheckOnClick; 

    } 

    private void PartEnabledCheckOnClick(object sender, RoutedEventArgs routedEventArgs) 
    { 
     _partItemsListView.IsEnabled = EnabledCheck; 
     _partSelectAllCheck.IsEnabled = EnabledCheck; 
    } 

    private void ListenToSelectedCheckBoxClickEvent(DependencyObject parent, bool set) 
    { 
     foreach (CheckBox cb in VisualTreeHelpers.FindVisualChildren<CheckBox>(parent)) 
     { 
      BindingExpression binding = cb.GetBindingExpression(CheckBox.IsCheckedProperty); 
      // ReSharper disable once PossibleNullReferenceException 
      if (binding.ParentBinding.Path.Path == "Selected") 
      { 
       if (set) 
        cb.Click += SelectedCheckBox_Click; 
       else 
        cb.Click -= SelectedCheckBox_Click; 
      } 
     } 

    } 

    private void SelectedCheckBox_Click(object sender, RoutedEventArgs e) 
    { 
     _partSelectAllCheck.IsChecked = !ItemSourceList.AsQueryable().Any(x => x.Selected == false); 

    } 

    private void PartSelectAllCheckOnClick(object sender, RoutedEventArgs routedEventArgs) 
    { 
     foreach (CheckBox cb in VisualTreeHelpers.FindVisualChildren<CheckBox>(_partItemsListView)) 
     { 
      BindingExpression binding = cb.GetBindingExpression(CheckBox.IsCheckedProperty); 
      // ReSharper disable once PossibleNullReferenceException 
      if (binding.ParentBinding.Path.Path == "Selected") 
      { 
       cb.IsChecked = _partSelectAllCheck.IsChecked ?? false; 
      } 
     } 
    } 

} 

}

Quelqu'un pourrait-il s'il vous plaît poster un code qui montre comment ensemble - créer le modèle par défaut?

Répondre

0

Cela s'est avéré plus simple que je ne le pensais. Parce que ItemTemplate est lié à une propriété de dépendance, je peux spécifier le modèle par défaut. Cela a juste laissé la création du modèle. Voir ci-dessous.

#region ItemTemplate 

    public DataTemplate ItemTemplate 
    { 
     get { return (DataTemplate)GetValue(ItemTemplateProperty); } 
     set { SetValue(ItemTemplateProperty, value); } 
    } 

    // Using a DependencyProperty as the backing store for MyProperty. This enables animation, styling, binding, etc... 
    public static readonly DependencyProperty ItemTemplateProperty = 
     DependencyProperty.Register("ItemTemplate", typeof(DataTemplate), typeof(SelectItemsControl), 
     new UIPropertyMetadata(DefaultItemTemplate)); 

    private static DataTemplate DefaultItemTemplate 
    { 
     get 
     { 
      // tried using a MemoryStream - StreamWriter but was getting a 
      // "Root element missing error", would be nice to know why. 
      var sb = new StringBuilder(); 

      sb.Append("<DataTemplate xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\">"); 
      sb.Append("<StackPanel Orientation=\"Horizontal\">"); 
      sb.Append("<CheckBox Margin=\"2\" IsChecked=\"{Binding Selected}\" />"); 
      sb.Append("<TextBlock Margin=\"5,2\" Text=\"{Binding Description}\" VerticalAlignment=\"Center\"/>"); 
      sb.Append("</StackPanel>"); 
      sb.Append("</DataTemplate>"); 

      var myByteArray = System.Text.Encoding.UTF8.GetBytes(sb.ToString()); 
      var ms = new MemoryStream(myByteArray); 

      return (DataTemplate) XamlReader.Load(ms); 
     } 
    } 

    #endregion