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>

如果您处理 ListViewLoaded 事件,您应该能够设置 ColumnHeaderTemplateColumnHeaderContainerStyle 属性 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;
        }
    }
}