0

我有一个带有 GridViewColumn 的 GridView,标题使用带有 textblox 的模板来显示列名。我想要一个附加到该列的命令,基本上当用户单击该列时,我的 VM 中的一个命令被调用?

这是为了排序。

谢谢

4

2 回答 2

4

可能为时已晚,但对于其他正在寻找答案的人来说,您可以使用附加行为和 GridViewColumnHeader.Click 事件来完成此操作(请参阅这篇 MSDN 文章,关于在标题项单击时对 GridView 进行排序)。

我的代码如下;XAML:

<ListView Width="Auto" Height="Auto" Margin="12,12,12,12"
  ItemsSource="{Binding SearchResults}" 
  behav:GridViewColumnHeaderClick.Command="{Binding SortViewCommand}">

(其中 'behav' 是我附加行为的命名空间)。附加的行为类如下所示:

public class GridViewColumnHeaderClick
{
    public static readonly DependencyProperty CommandProperty =
        DependencyProperty.RegisterAttached("Command", typeof(ICommand), typeof(GridViewColumnHeaderClick), new UIPropertyMetadata(null,
            GridViewColumnHeaderClick.CommandChanged));

    public static readonly DependencyProperty CommandBehaviourProperty =
        DependencyProperty.RegisterAttached("CommandBehaviour", typeof(GridViewColumnHeaderClickCommandBehaviour), typeof(GridViewColumnHeaderClick),
            new UIPropertyMetadata(null));

    public static ICommand GetCommand(DependencyObject obj)
    {
        return (ICommand)obj.GetValue(CommandProperty);
    }

    public static void SetCommand(DependencyObject obj, ICommand value)
    {
        obj.SetValue(CommandProperty, value);
    }

    public static GridViewColumnHeaderClickCommandBehaviour GetCommandBehaviour(DependencyObject obj)
    {
        return (GridViewColumnHeaderClickCommandBehaviour)obj.GetValue(CommandBehaviourProperty);
    }

    public static void SetCommandBehaviour(DependencyObject obj, GridViewColumnHeaderClickCommandBehaviour value)
    {
        obj.SetValue(CommandBehaviourProperty, value);
    }

    private static void CommandChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
    {
        GridViewColumnHeaderClick.GetOrCreateBehaviour(sender).Command = e.NewValue as ICommand;
    }

    private static GridViewColumnHeaderClickCommandBehaviour GetOrCreateBehaviour(DependencyObject element)
    {
        GridViewColumnHeaderClickCommandBehaviour returnVal = GridViewColumnHeaderClick.GetCommandBehaviour(element);

        if (returnVal == null)
        {
            ListView typedElement = element as ListView;

            if (typedElement == null)
            {
                throw new InvalidOperationException("GridViewColumnHeaderClick.Command property can only be set on instances of ListView");
            }

            returnVal = new GridViewColumnHeaderClickCommandBehaviour(typedElement);

            GridViewColumnHeaderClick.SetCommandBehaviour(element, returnVal);
        }

        return returnVal;
    }
}

和:

public class GridViewColumnHeaderClickCommandBehaviour
{
    public GridViewColumnHeaderClickCommandBehaviour(ListView element)
    {
        element.AddHandler(GridViewColumnHeader.ClickEvent, new RoutedEventHandler(this.ClickEventHandler));
    }

    public ICommand Command { get; set; }

    private void ClickEventHandler(object sender, RoutedEventArgs e)
    {
        ICommand localCommand = this.Command;
        object parameter = e.OriginalSource as GridViewColumnHeader;

        if ((localCommand != null) && localCommand.CanExecute(parameter))
        {
            localCommand.Execute(parameter);
        }
    }
}

然后您的命令可以基于 MSDN 文章中描述的事件处理程序:

    private void SortResults(string sortBy, ListSortDirection direction)
    {
        ICollectionView dataView = CollectionViewSource.GetDefaultView(this.SearchResults);    // where SearchResults is the data to which the ListView is bound
        dataView.SortDescriptions.Clear();

        SortDescription sortDescription = new SortDescription(sortBy, direction);
        dataView.SortDescriptions.Add(sortDescription);
        dataView.Refresh();
    }

    private void SortViewCommandHandler(object parameter)
    {
        GridViewColumnHeader typedParameter = parameter as GridViewColumnHeader;

        ListSortDirection direction;

        if (typedParameter != null)
        {
            if (typedParameter.Role != GridViewColumnHeaderRole.Padding)
            {
                if (typedParameter != this.previousSortHeader)
                {
                    direction = ListSortDirection.Ascending;
                }
                else
                {
                    if (this.previousSortDirection == ListSortDirection.Ascending)
                    {
                        direction = ListSortDirection.Descending;
                    }
                    else
                    {
                        direction = ListSortDirection.Ascending;
                    }
                }

                string headerLabel = typedParameter.Column.Header as string;

                this.SortResults(headerLabel, direction);

                if (direction == ListSortDirection.Ascending)
                {
                    typedParameter.Column.HeaderTemplate =
                      Resources["HeaderTemplateArrowUp"] as DataTemplate;
                }
                else
                {
                    typedParameter.Column.HeaderTemplate =
                      Resources["HeaderTemplateArrowDown"] as DataTemplate;
                }

                // Remove arrow from previously sorted header
                if ((this.previousSortHeader != null) && (this.previousSortHeader != typedParameter))
                {
                    this.previousSortHeader.Column.HeaderTemplate = null;
                }

                this.previousSortHeader = typedParameter;
                this.previousSortDirection = direction;
            }
        }
    }

我还没有想到一种 MVVM 方式来设置标题模板(视图显然应该绑定到这里的某些东西),所以你自己在那里!

请注意,在附加行为的实现中,我与 Josh Smith 的文章略有不同——拥有一个单独的类使得多个有状态的处理程序比使用静态事件处理程序方法更容易,所以这是我通常遵循的模式。

于 2011-11-08T22:06:53.960 回答
0

您可以用按钮替换标题模板中的文本块,然后将命令附加到它。如果需要,您可以为按钮设置样式以删除边框。

于 2011-03-17T09:48:33.947 回答