【问题标题】:GridViewColumn Command in HeaderTemplateHeaderTemplate 中的 GridViewColumn 命令
【发布时间】:2011-03-17 00:14:05
【问题描述】:

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

这是为了排序。

谢谢

【问题讨论】:

    标签: wpf xaml gridviewcolumn


    【解决方案1】:

    可能为时已晚,但对于其他正在寻找答案的人来说,您可以使用 Attached Behaviours 和 GridViewColumnHeader.Click 事件来完成此操作(请参阅 this MSDN article 在标题项单击时对 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 的文章略有不同 - 拥有一个单独的类使得多个有状态处理程序比使用静态事件处理程序方法更容易,因此这是我通常遵循的模式。

    【讨论】:

    • 我有点明白。因此,我将 SortViewCommand 放入 ViewModel 并让它调用 SortResultViewCommandHandler()?
    • 很抱歉,我回复得太晚了,但为了其他读者的利益 - 是的,你说的是正确的。
    【解决方案2】:

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

    【讨论】:

    • 这是我的 DataTemplate: 问题是,当我改变列的宽度时,按钮的大小保持不变,我需要接管整个列大小的按钮。
    • 不需要DockPanel,需要设置Horizo​​ntalAlignment,而不是Button的Horizo​​ntalContentAlignment。试试这个模板: Button Horizo​​ntalAlignment="Stretch">
    猜你喜欢
    • 2011-07-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多