WPF 使用样式和模板扩展列表视图
WPF extending a listview with styles and templates
我正在尝试在 .NET WPF 中创建 ListView 的扩展版本。
我有更多的模板和样式然后我想实现,但出于测试目的将其删除。即使这两个剂量似乎也无法工作或加载,因为没有显示已配置的内容。
现在对我来说奇怪的是,这些在用户控件中工作时,使用常规 ListView 并使用相同类型的 StaticResource
引用。
然而,我认为可以将它们放在共享的 xaml 和 cs 文件中以获得更好的可重用性。
我是否为特定类型的 ListView 设置了错误?
XAML
<ListView x:Class="MyProject.SharedView.ExtListView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<ListView.Resources>
<Style x:Key="ArColumnHeaderContainerStyle" TargetType="{x:Type GridViewColumnHeader}">
<Setter Property="Control.HorizontalContentAlignment" Value="Stretch" />
<Setter Property="Control.VerticalContentAlignment" Value="Center" />
<Setter Property="Control.Background" Value="Gray" />
</Style>
<DataTemplate x:Key="ArColumnHeaderTemplate">
<StackPanel Orientation="Vertical" VerticalAlignment="Top" HorizontalAlignment="Stretch">
<DockPanel Name="dpQColHead" Grid.Row="0">
<CheckBox/>
<TextBlock Foreground="Red" TextTrimming="None" TextWrapping="Wrap">
<TextBlock.Text>
<Binding />
</TextBlock.Text>
</TextBlock>
</DockPanel>
</StackPanel>
</DataTemplate>
</ListView.Resources>
<ListView.View>
<GridView
ColumnHeaderTemplate="{StaticResource ArColumnHeaderTemplate}"
ColumnHeaderContainerStyle="{StaticResource ArColumnHeaderContainerStyle}">
</GridView>
</ListView.View>
CS
public partial class ExtListView : ListView
{
public ExtListView()
{
InitializeComponent();
this.AddHandler(
GridViewColumnHeader.ClickEvent,
new RoutedEventHandler(GridViewColumnHeaderClickedHandler));
}
private GridViewColumnHeader _lastHeaderClicked = null;
private ListSortDirection _lastDirection = ListSortDirection.Ascending;
/// <summary>
/// Sort data
/// </summary>
/// <param name="sortBy"></param>
/// <param name="direction"></param>
private void Sort(string sortBy, ListSortDirection direction)
{
ICollectionView dataView =
CollectionViewSource.GetDefaultView(this.ItemsSource);
if (dataView != null)
{
dataView.SortDescriptions.Clear();
SortDescription sd = new SortDescription(sortBy, direction);
dataView.SortDescriptions.Add(sd);
dataView.Refresh();
}
}
/// <summary>
/// Event, Grid column header clicked
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void GridViewColumnHeaderClickedHandler(object sender, RoutedEventArgs e)
{
GridViewColumnHeader headerClicked = e.OriginalSource as GridViewColumnHeader;
ListSortDirection direction;
if (headerClicked != null &&
headerClicked.Role != GridViewColumnHeaderRole.Padding)
{
if (_lastHeaderClicked != null)
{
ColumnAdorner.RemoveAdorner(_lastHeaderClicked);
}
if (headerClicked != _lastHeaderClicked)
{
direction = ListSortDirection.Ascending;
}
else
{
if (_lastDirection == ListSortDirection.Ascending)
{
direction = ListSortDirection.Descending;
}
else
{
direction = ListSortDirection.Ascending;
}
}
// see if we have an attached SortPropertyName value
string sortBy = GetSortPropertyName(headerClicked.Column);
if (string.IsNullOrEmpty(sortBy))
{
// otherwise use the column header name
sortBy = headerClicked.Column.Header as string;
}
Sort(sortBy, direction);
_lastHeaderClicked = headerClicked;
_lastDirection = direction;
ColumnAdorner.SetAdorner(headerClicked, direction);
}
}
/// <summary>
/// Custom sorting property
/// </summary>
public static readonly DependencyProperty SortPropertyNameProperty =
DependencyProperty.RegisterAttached("SortPropertyName", typeof(string), typeof(AriesListView));
/// <summary>
/// Gets property
/// </summary>
/// <param name="obj"></param>
/// <returns></returns>
public static string GetSortPropertyName(GridViewColumn obj)
{
return (string)obj.GetValue(SortPropertyNameProperty);
}
/// <summary>
/// Set property name
/// </summary>
/// <param name="obj"></param>
/// <param name="value"></param>
public static void SetSortPropertyName(GridViewColumn obj, string value)
{
obj.SetValue(SortPropertyNameProperty, value);
}
}
运行自定义ListView
...
<sv:ArListView
BorderBrush="#b7d9ed" BorderThickness="1"
VirtualizingStackPanel.IsVirtualizing="True"
VirtualizingStackPanel.VirtualizationMode="Recycling"
Grid.Row="1" Margin="4,4,0,0"
ItemsSource="{Binding Path=TargetObject.AssignedClassification.ExternalStandardMappings}"
GridViewColumnHeader.Click="SortGridViewByColumn">
<sv:ArListView.View>
<GridView>
<GridViewColumn DisplayMemberBinding="{Binding Path=Standard.Name}" Header="Standard" Width="100"/>
<GridViewColumn DisplayMemberBinding="{Binding Path=ID}" Header="ID" Width="Auto"/>
<GridViewColumn DisplayMemberBinding="{Binding Path=Description}" Header="Description" Width="Auto"/>
</GridView>
</sv:ArListView.View>
</sv:ArListView>
...
以下 XAML 标记创建 ListView
的实例并将其 GridView
属性 设置为全新的 GridView
这意味着 GridView
您在 ExtListView.xaml.cs 中定义的内容将被覆盖:
<sv:ArListView.View>
<GridView>
<GridViewColumn DisplayMemberBinding="{Binding Path=Standard.Name}" Header="Standard" Width="100"/>
<GridViewColumn DisplayMemberBinding="{Binding Path=ID}" Header="ID" Width="Auto"/>
<GridViewColumn DisplayMemberBinding="{Binding Path=Description}" Header="Description" Width="Auto"/>
</GridView>
<sv:ArListView.View>
如果您处理 ListView
的 Loaded
事件,您应该能够设置 ColumnHeaderTemplate
和 ColumnHeaderContainerStyle
属性 after View
属性 已设置:
public partial class ExtListView : ListView
{
public ExtListView()
{
InitializeComponent();
this.AddHandler(
GridViewColumnHeader.ClickEvent,
new RoutedEventHandler(GridViewColumnHeaderClickedHandler));
Loaded += OnLoaded;
}
private void OnLoaded(object sender, RoutedEventArgs e)
{
GridView gridView = View as GridView;
if (gridView != null)
{
gridView.ColumnHeaderTemplate = Resources["ArColumnHeaderTemplate"] as DataTemplate;
gridView.ColumnHeaderContainerStyle = Resources["ArColumnHeaderContainerStyle"] as Style;
}
}
}
我正在尝试在 .NET WPF 中创建 ListView 的扩展版本。 我有更多的模板和样式然后我想实现,但出于测试目的将其删除。即使这两个剂量似乎也无法工作或加载,因为没有显示已配置的内容。
现在对我来说奇怪的是,这些在用户控件中工作时,使用常规 ListView 并使用相同类型的 StaticResource
引用。
然而,我认为可以将它们放在共享的 xaml 和 cs 文件中以获得更好的可重用性。
我是否为特定类型的 ListView 设置了错误?
XAML
<ListView x:Class="MyProject.SharedView.ExtListView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<ListView.Resources>
<Style x:Key="ArColumnHeaderContainerStyle" TargetType="{x:Type GridViewColumnHeader}">
<Setter Property="Control.HorizontalContentAlignment" Value="Stretch" />
<Setter Property="Control.VerticalContentAlignment" Value="Center" />
<Setter Property="Control.Background" Value="Gray" />
</Style>
<DataTemplate x:Key="ArColumnHeaderTemplate">
<StackPanel Orientation="Vertical" VerticalAlignment="Top" HorizontalAlignment="Stretch">
<DockPanel Name="dpQColHead" Grid.Row="0">
<CheckBox/>
<TextBlock Foreground="Red" TextTrimming="None" TextWrapping="Wrap">
<TextBlock.Text>
<Binding />
</TextBlock.Text>
</TextBlock>
</DockPanel>
</StackPanel>
</DataTemplate>
</ListView.Resources>
<ListView.View>
<GridView
ColumnHeaderTemplate="{StaticResource ArColumnHeaderTemplate}"
ColumnHeaderContainerStyle="{StaticResource ArColumnHeaderContainerStyle}">
</GridView>
</ListView.View>
CS
public partial class ExtListView : ListView
{
public ExtListView()
{
InitializeComponent();
this.AddHandler(
GridViewColumnHeader.ClickEvent,
new RoutedEventHandler(GridViewColumnHeaderClickedHandler));
}
private GridViewColumnHeader _lastHeaderClicked = null;
private ListSortDirection _lastDirection = ListSortDirection.Ascending;
/// <summary>
/// Sort data
/// </summary>
/// <param name="sortBy"></param>
/// <param name="direction"></param>
private void Sort(string sortBy, ListSortDirection direction)
{
ICollectionView dataView =
CollectionViewSource.GetDefaultView(this.ItemsSource);
if (dataView != null)
{
dataView.SortDescriptions.Clear();
SortDescription sd = new SortDescription(sortBy, direction);
dataView.SortDescriptions.Add(sd);
dataView.Refresh();
}
}
/// <summary>
/// Event, Grid column header clicked
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void GridViewColumnHeaderClickedHandler(object sender, RoutedEventArgs e)
{
GridViewColumnHeader headerClicked = e.OriginalSource as GridViewColumnHeader;
ListSortDirection direction;
if (headerClicked != null &&
headerClicked.Role != GridViewColumnHeaderRole.Padding)
{
if (_lastHeaderClicked != null)
{
ColumnAdorner.RemoveAdorner(_lastHeaderClicked);
}
if (headerClicked != _lastHeaderClicked)
{
direction = ListSortDirection.Ascending;
}
else
{
if (_lastDirection == ListSortDirection.Ascending)
{
direction = ListSortDirection.Descending;
}
else
{
direction = ListSortDirection.Ascending;
}
}
// see if we have an attached SortPropertyName value
string sortBy = GetSortPropertyName(headerClicked.Column);
if (string.IsNullOrEmpty(sortBy))
{
// otherwise use the column header name
sortBy = headerClicked.Column.Header as string;
}
Sort(sortBy, direction);
_lastHeaderClicked = headerClicked;
_lastDirection = direction;
ColumnAdorner.SetAdorner(headerClicked, direction);
}
}
/// <summary>
/// Custom sorting property
/// </summary>
public static readonly DependencyProperty SortPropertyNameProperty =
DependencyProperty.RegisterAttached("SortPropertyName", typeof(string), typeof(AriesListView));
/// <summary>
/// Gets property
/// </summary>
/// <param name="obj"></param>
/// <returns></returns>
public static string GetSortPropertyName(GridViewColumn obj)
{
return (string)obj.GetValue(SortPropertyNameProperty);
}
/// <summary>
/// Set property name
/// </summary>
/// <param name="obj"></param>
/// <param name="value"></param>
public static void SetSortPropertyName(GridViewColumn obj, string value)
{
obj.SetValue(SortPropertyNameProperty, value);
}
}
运行自定义ListView
...
<sv:ArListView
BorderBrush="#b7d9ed" BorderThickness="1"
VirtualizingStackPanel.IsVirtualizing="True"
VirtualizingStackPanel.VirtualizationMode="Recycling"
Grid.Row="1" Margin="4,4,0,0"
ItemsSource="{Binding Path=TargetObject.AssignedClassification.ExternalStandardMappings}"
GridViewColumnHeader.Click="SortGridViewByColumn">
<sv:ArListView.View>
<GridView>
<GridViewColumn DisplayMemberBinding="{Binding Path=Standard.Name}" Header="Standard" Width="100"/>
<GridViewColumn DisplayMemberBinding="{Binding Path=ID}" Header="ID" Width="Auto"/>
<GridViewColumn DisplayMemberBinding="{Binding Path=Description}" Header="Description" Width="Auto"/>
</GridView>
</sv:ArListView.View>
</sv:ArListView>
...
以下 XAML 标记创建 ListView
的实例并将其 GridView
属性 设置为全新的 GridView
这意味着 GridView
您在 ExtListView.xaml.cs 中定义的内容将被覆盖:
<sv:ArListView.View>
<GridView>
<GridViewColumn DisplayMemberBinding="{Binding Path=Standard.Name}" Header="Standard" Width="100"/>
<GridViewColumn DisplayMemberBinding="{Binding Path=ID}" Header="ID" Width="Auto"/>
<GridViewColumn DisplayMemberBinding="{Binding Path=Description}" Header="Description" Width="Auto"/>
</GridView>
<sv:ArListView.View>
如果您处理 ListView
的 Loaded
事件,您应该能够设置 ColumnHeaderTemplate
和 ColumnHeaderContainerStyle
属性 after View
属性 已设置:
public partial class ExtListView : ListView
{
public ExtListView()
{
InitializeComponent();
this.AddHandler(
GridViewColumnHeader.ClickEvent,
new RoutedEventHandler(GridViewColumnHeaderClickedHandler));
Loaded += OnLoaded;
}
private void OnLoaded(object sender, RoutedEventArgs e)
{
GridView gridView = View as GridView;
if (gridView != null)
{
gridView.ColumnHeaderTemplate = Resources["ArColumnHeaderTemplate"] as DataTemplate;
gridView.ColumnHeaderContainerStyle = Resources["ArColumnHeaderContainerStyle"] as Style;
}
}
}