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?