GridViewColumn Command in HeaderTemplate

|▌冷眼眸甩不掉的悲伤 提交于 2019-12-08 10:19:16

问题


I have a GridView with GridViewColumn, the header uses a template with a textblox to show the column name. I want a command attached to this column, basically when the user clicks the column, a command in my VM gets called ?

this is for sorting purposes.

Thanks


回答1:


Probably too late to help you but for anyone else looking for an answer, you can do this using Attached Behaviours and the GridViewColumnHeader.Click event (see this MSDN article on sorting a GridView on header item click).

My code was as follows; XAML:

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

(where 'behav' is the namespace for my attached behaviours). The attached behaviour classes look like this:

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;
    }
}

and:

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);
        }
    }
}

and then your command can be based on the event handler described in the MSDN article:

    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;
            }
        }
    }

I haven't yet thought of an MVVM-ish way to set the header template (the view should obviously be bound to something in here) so you're on your own there!

Note that I'm deviating slightly from the Josh Smith article in my implementation of the attached behaviour - having a separate class makes multiple stateful handlers easier than using a static event handler method, so it's a pattern I follow in general.




回答2:


You can replace the textblock in the header template with a button and then attach a command to it. If you want, you can set a style for the buttons to remove the borders.



来源:https://stackoverflow.com/questions/5333351/gridviewcolumn-command-in-headertemplate

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!