【问题标题】:Check/Uncheck checkbox with Space/Enter in gridview in listview - wpf在列表视图的网格视图中使用空格/输入选中/取消选中复选框 - wpf
【发布时间】:2017-02-17 23:33:54
【问题描述】:

我有一个GridView,其中CheckBox 作为一列,TextBlock 作为另一列。这是XAML 代码:

<ListView.View>
    <GridView>
        <GridView.ColumnHeaderContainerStyle>
            <Style>
                <Setter Property="UIElement.Visibility"
                        Value="Collapsed"/>
            </Style>
        </GridView.ColumnHeaderContainerStyle>

        <GridViewColumn>
            <GridViewColumn.CellTemplate>
                <DataTemplate>
                    <CheckBox Tag="{Binding}"
                              IsChecked="{Binding Path=IsFormChecked, Mode=TwoWay}"
                              IsEnabled="{Binding Path=IsUnRestricted}"
                              IsThreeState="False" 
                              UIElement.KeyUp="CheckBox_KeyUp" />
                </DataTemplate>
            </GridViewColumn.CellTemplate>
        </GridViewColumn>

        <GridViewColumn Width="auto">
            <GridViewColumn.CellTemplate>
                <DataTemplate>
                    <TextBlock Width="600"
                               Tag="{Binding}"
                               IsEnabled="{Binding Path=IsUnRestricted}"
                               Text="{Binding Path=FormName}" 
                               MouseUp="TextBlock_MouseUp">
                        <TextBlock.ToolTip>
                            <TextBlock Text="{Binding Path=FormName}"/>
                        </TextBlock.ToolTip>
                    </TextBlock>
                </DataTemplate>
            </GridViewColumn.CellTemplate>
        </GridViewColumn>
    </GridView>
</ListView.View>

当我使用键盘完整行访问此GridView 时(CheckBox 以及TextBlock)。现在,如果我按空格键,什么都不会发生。如果我想使用键盘访问CheckBox,我必须再次按 Tab 键,以便将焦点设置在复选框上,然后我可以使用空格键选中/取消选中它。我想要做的是当焦点位于我想要选中/取消选中复选框的行时,只需按一下空格键即可。

【问题讨论】:

    标签: c# wpf xaml gridview


    【解决方案1】:

    如果您对当前选定的项目有绑定,则可以在您的ListView 上处理PreviewKeyUp 事件:

    <ListView PreviewKeyUp="OnGridKeyUp"
              SelectedItem="{Binding MySelectedItem}"
              SelectionMode="Single"
              ItemsSource="{Binding ItemsList}">
        ...
    </ListView>
    

    然后在代码隐藏中处理:

    private void OnGridKeyUp(object sender, KeyEventArgs e)
    {
        if(vm.mySelectedItem != null && e.Key == Key.Space)
        {
            vm.MySelectedItem.IsChecked = !vm.MySelectedItem.IsChecked;
            e.Handled = true; //this is necessary because otherwise when the checkbox cell is selected, it will apply this keyup and also apply the default behavior for the checkbox
        }
    }
    

    这显然需要您从后面的代码中处理您的视图模型。这可能很简单:

    var vm = DataContext as MyViewModel;
    

    这不是最 MVVM 的方式,但是嘿...

    【讨论】:

    • 嘿,我还没有使用 MVVM 到那种程度,但是 PreviewKeyUp 事件解决了我的问题。谢谢... :)
    【解决方案2】:

    我做了一个更 MVVM 友好的方式来做到这一点:

    第 1 步:创建此行为

    public class ToggleSelectOnSpace : Behavior<DataGrid>
    {
        public static readonly DependencyProperty toggleSelectCommand =
            DependencyProperty.Register("ToggleSelectCommand",
            typeof(ICommand),
            typeof(ToggleSelectOnSpace));
    
        public ICommand ToggleSelectCommand
        {
            get { return this.GetValue(toggleSelectCommand) as ICommand; }
            set { this.SetValue(toggleSelectCommand, value); }
        }
    
        protected override void OnAttached()
        {
            base.OnAttached();
    
            this.AssociatedObject.PreviewKeyUp += PreviewKeyUp;
        }
    
        protected override void OnDetaching()
        {
            this.AssociatedObject.PreviewKeyUp -= PreviewKeyUp;
            base.OnDetaching();
        }
    
        private void PreviewKeyUp(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Space)
            {
                if (ToggleSelectCommand != null)
                {
                    ToggleSelectCommand.Execute(this.AssociatedObject.SelectedItems);
                }
            }
        }
    }
    

    第 2 步:在您的视图模型中实现这样的命令(命令的方法逻辑)

        private void ToggleSelectParticipant(object selectedObjects)
        {
            var items = (System.Collections.IList)selectedObjects;
            var collection = items.Cast<MyItemType>().ToList();
            bool selection = !collection.All(x => x.IsSelected);
            foreach (var item in collection)
                item.IsSelected = selection;
        }
    

    第三步:将行为绑定到网格,将命令绑定到行为

    <DataGrid>
        <i:Interaction.Behaviors>
            <shared:ToggleSelectOnSpace ToggleSelectCommand="{Binding Data.ToggleSelectParticipantCommand, Source={StaticResource BindingProxy}}" />
        </i:Interaction.Behaviors>
    ...
    </DataGrid>
    

    (Info on the BindingProxy source)

    【讨论】:

    • 我认为这是要走的路。我想实现这个解决方案,但我希望能够绑定到单个项目的 IsSelected 属性(它已经存在并绑定到复选框),而不必添加命令。我的问题是我不知道如何将项目的属性绑定到行为的属性。你能建议如何做到这一点吗?谢谢
    • 您可能应该Ask a Quesiton 并更彻底地解释您的问题。
    • 好的,我已经为它创建了一个问题,并尽力解释它:stackoverflow.com/q/28457497/352826
    猜你喜欢
    • 1970-01-01
    • 2011-01-31
    • 1970-01-01
    • 2011-08-06
    • 2011-03-02
    • 1970-01-01
    相关资源
    最近更新 更多