WPF Datagrid:加载时,选择当前项目(突出显示)

Posted

技术标签:

【中文标题】WPF Datagrid:加载时,选择当前项目(突出显示)【英文标题】:WPF Datagrid : On load, selection on current item (highlighting) 【发布时间】:2011-07-09 03:42:45 【问题描述】:

我有一个 WPF Datagrid 绑定到我的 ViewModel 中的一些属性

<DataGrid AutoGenerateColumns="False" Name="dataGrid" SelectionMode="Single"
          ItemsSource="Binding ItemList" SelectedItem="Binding SelectedItem">
...
</DataGrid>

当我的窗口加载和 Datagrid 也加载时,我设置了 SelectedItem 并且它绑定得很好,但该行没有突出显示。当我单击一行时,该行突出显示,问题就解决了。

如何在加载/初始化时设置/触发 DataGrid 中 SelectedItem 的突出显示?

编辑:

它实际上是被选中的,因为我有一个小的选择单元格。只是高亮的渲染没有触发。

【问题讨论】:

【参考方案1】:

我知道这个帖子太老了,但没有一个解决方案对我有帮助。

如果有人遇到同样的问题,我发现的一个非常简单的解决方案是在加载所选项目之前简单地将焦点设置到数据网格。

private void Window_Loaded(object sender, RoutedEventArgs e)

    dataGrid.Focus();
    // Set selected item in datagrid

【讨论】:

【参考方案2】:

在将虚拟数据插入 WPF DataGrid 时遇到相同的问题,然后尝试更改行顺序。行高亮显示(下图)。

原因是多次插入完全相同的“相同”记录对象。

//Ex: Messes up highlighting.    
grid.Items.Add(rowObj);
grid.Items.Add(rowObj);
grid.Items.Add(rowObj);

//Ex: Highlighting OK.  Create a new object each time.  Even if all columns have exact same values.  
rowobj = new .....
grid.Items.Add(rowObj);

rowobj = new .....
grid.Items.Add(rowObj);

【讨论】:

【参考方案3】:

这有点老了,但任何帖子中的答案似乎都没有完全正确。您想要的是它以应有的方式工作:即无论控件是否具有焦点,突出显示都是相同的(这似乎是偶然的)。

这可以通过DataGridRow 样式完成,但诀窍不是自己指定颜色,而是使用默认颜色,所以一切正常。一个额外的烦恼来自于突出显示的是单元格,而不是行,因此您基本上需要复制单元格突出显示样式:

<Style
    x:Key="DataGridRowStyle"
    TargetType="x:Type DataGridRow">
    <Style.Triggers>
        <MultiTrigger>
            <MultiTrigger.Conditions>
                <Condition
                    Property="IsKeyboardFocusWithin"
                    Value="False" />
                <Condition
                    Property="IsSelected"
                    Value="True" />
            </MultiTrigger.Conditions>
            <Setter
                Property="Background"
                Value="DynamicResource
                    x:Static SystemColors.InactiveSelectionHighlightBrushKey" />
            <Setter
                Property="Foreground"
                Value="DynamicResource
                    x:Static SystemColors.InactiveSelectionHighlightTextBrushKey" />
        </MultiTrigger>
        <MultiTrigger>
            <MultiTrigger.Conditions>
                <Condition
                    Property="IsKeyboardFocusWithin"
                    Value="True" />
                <Condition
                    Property="IsSelected"
                    Value="True" />
            </MultiTrigger.Conditions>
            <Setter
                Property="Background"
                Value="DynamicResource
                    x:Static SystemColors.HighlightBrushKey" />
            <Setter
                Property="Foreground"
                Value="DynamicResource
                    x:Static SystemColors.HighlightTextBrushKey" />
        </MultiTrigger>
    </Style.Triggers>
</Style>

注意有一个问题,要设置行上下文菜单,您需要覆盖 DataGrid 上的 DataGridRow 样式,因此如果您在全局范围内执行此操作并且它不起作用,请检查您的 RowStyle没有被覆盖。

【讨论】:

【参考方案4】:

我遇到了同样的“问题”,终于找到了一个很好的解决方案。正如您已经说过的,不是没有选择该行,而是它没有突出显示该行。如果您仔细观察,您会注意到,当您单击行中的任意位置(使用鼠标)时,它仍然不会突出显示该行,而只会突出显示其中的单元格。

所以 2 个选项;

创建代码以选择行的单元格 或创建一个 Style.Trigger 以突出显示该行(这是我认为的最佳选择)。

为此,在 xaml 文件中的数据网格中添加类似这样的内容:

            <DataGrid.RowStyle>
                <Style TargetType="DataGridRow">
                    <Style.Triggers>
                        <Trigger Property="IsSelected" Value="True">
                            <Setter Property="Background" Value="DodgerBlue"/>
                            <Setter Property="Foreground" Value="White"/>
                        </Trigger>
                    </Style.Triggers>
                </Style>
            </DataGrid.RowStyle>

希望对你有帮助!

干杯, 长期保费

【讨论】:

【参考方案5】:

当使用模型作为 WPF 窗口的 DataContext 时,DataGrid 的 SelectionChanged 事件直到加载窗口后才会被调用,这就是为什么该行永远不会突出显示并且您只能看到第一行的部分强调。可能有更优雅的方式,但这里有一个解决方法。

在Window的loaded事件或DataGrid的loaded事件中,重置SelectedItem绑定:

public MainWindow()

    InitializeComponent(); 
    this.Loaded += new RoutedEventHandler( OnLoaded );


// could also be placed in the DataGrid's loaded event handler
private void OnLoaded( object sender, RoutedEventArgs e )

    if( dataGrid != null && Model.SelectedItem != null )
    
        var selected = Model.SelectedItem;
        Model.SelectedItem = null;
        Model.SelectedItem = selected;
    

这是一个完整的工作示例。

XAML

<Window x:Class="WpfDataGridHighlightOnLoad.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:model="clr-namespace:WpfDataGridHighlightOnLoad" 
        Title="MainWindow" Height="350" Width="525">

    <Window.DataContext>
        <model:MainWindowModel x:Name="Model" />
    </Window.DataContext>

    <Grid>
        <DataGrid AutoGenerateColumns="True" SelectionMode="Single"
                  HorizontalAlignment="Stretch" 
                  Name="dataGrid" 
                  VerticalAlignment="Top"
                  ItemsSource="Binding ItemList"
                  SelectedItem="Binding SelectedItem">
        </DataGrid>

        <Button Content="Cycle Selection" Click="OnCycleClick" 
                Height="23" 
                HorizontalAlignment="Right" 
                Name="button1" 
                VerticalAlignment="Bottom" Width="125" />

        <Button Content="Reset Grid" Click="OnResetClick" 
                Height="23" 
                HorizontalAlignment="Left" 
                Name="button2" 
                VerticalAlignment="Bottom" Width="125" />

    </Grid>
</Window>

代码背后

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows;

namespace WpfDataGridHighlightOnLoad

    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    
        public MainWindow()
        
            InitializeComponent();   
            this.Loaded += new RoutedEventHandler( OnLoaded );
        

        // could also be placed in the DataGrid's loaded event handler
        private void OnLoaded( object sender, RoutedEventArgs e )
        
            if( dataGrid != null && Model.SelectedItem != null )
            
                var selected = Model.SelectedItem;
                Model.SelectedItem = null;
                Model.SelectedItem = selected;
            
        

        private void OnCycleClick( object sender, RoutedEventArgs e )
        
            int index = Model.ItemList.IndexOf( Model.SelectedItem );
            index = index == Model.ItemList.Count - 1 ? 0 : index + 1;
            Model.SelectedItem = Model.ItemList[index];
        

        private void OnResetClick( object sender, RoutedEventArgs e )
        
            Model.Reset();
        
    

    public class MainWindowModel : INotifyPropertyChanged
    
        public MainWindowModel()
        
            Reset();
        

        public void Reset()
        
            ItemList = new List<Person>
                           
                               new Person("Joe", 20),
                               new Person("John", 30),
                               new Person("Jane", 40),
                               new Person("Jill", 50),
                               new Person("Fido", 7),
                           ;

            SelectedItem = ItemList[2];
        

        private Person _selectedItem;
        public Person SelectedItem
        
            get  return _selectedItem; 
            set
            
                _selectedItem = value;
                NotifyPropertyChanged( "SelectedItem" );
            
        

        private List<Person> _itemList;
        public List<Person> ItemList
        
            get  return _itemList; 
            set
            
                _itemList = value;
                NotifyPropertyChanged( "ItemList" );
            
        

        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;

        private void NotifyPropertyChanged( String info )
        
            if( PropertyChanged != null )
            
                PropertyChanged( this, new PropertyChangedEventArgs( info ) );
            
        

        #endregion
    

    public class Person
    
        public string Name  get; set; 
        public int Age  get; set; 

        public Person( string name, int age )
        
            Name = name;
            Age = age;
        

        public override string ToString()
        
            return Name;
        
    

【讨论】:

UIElement 上没有 Loaded 事件 DataGrid 继承自 Controls,它确实有一个 Loaded 事件:MSDN DataGrid Events @Smurf - 重置 SelecteItem 解决了我几天来一直试图理解的问题。谢谢!!! 这是第一次加载。但是当我更改视图模型值时,它仍然没有突出显示正确的行。尽管它已被选中。

以上是关于WPF Datagrid:加载时,选择当前项目(突出显示)的主要内容,如果未能解决你的问题,请参考以下文章

如何防止 WPF DataGrid 在项目更新时取消选择 SelectedItem?

从MVVM WPF项目中的DataGrid中选择多个项目

WPF DataGrid“选择所有按钮”,后跟 Control-C

WPF DataGrid获取选择行的数据

在运行时将新表重新加载/替换到 WPF DataGrid 中

WPF 后台实现按数字键滚动DataGrid 当前选中项