如何使用MVVM应用程序在WPF中以编程方式设置DataGrid的选定项?

时间:2022-09-10 21:03:02

I have bound the DataTable to the DataGrid control. How can I set the selected item programmatically ?

我已将DataTable绑定到DataGrid控件。如何以编程方式设置所选项?

Example

In my view model I have a property of type DataTable to bind the DataGrid

在我的视图模型中,我有一个DataTable类型的属性来绑定DataGrid

 private DataTable sizeQuantityTable;

 public DataTable SizeQuantityTable
 {
        get
        {
            return sizeQuantityTable;
        }
        set
        {
            sizeQuantityTable = value;
            NotifyPropertyChanged("SizeQuantityTable");
        }
  }

My XAML

我的XAML

<DataGrid 
            ItemsSource="{Binding SizeQuantityTable}"
            AutoGenerateColumns="True" 
            Margin="0,0,0,120" />

The constructor of the view model (assigning dummy values)

视图模型的构造函数(指定虚拟值)

this.SizeQuantityTable = new DataTable();

DataColumn sizeQuantityColumn = new DataColumn();
sizeQuantityColumn.ColumnName = "Size Quantity";
this.SizeQuantityTable.Columns.Add(sizeQuantityColumn);

DataColumn sColumn = new DataColumn();
sColumn.ColumnName = "S";
this.SizeQuantityTable.Columns.Add(sColumn);

DataColumn mColumn = new DataColumn();
mColumn.ColumnName = "M";
this.SizeQuantityTable.Columns.Add(mColumn);

DataRow row1 = this.SizeQuantityTable.NewRow();
row1[sizeQuantityColumn] = "Blue";
row1[sColumn] = "12";
row1[mColumn] = "15";
this.SizeQuantityTable.Rows.Add(row1);

DataRow row2 = this.SizeQuantityTable.NewRow();
row2[sizeQuantityColumn] = "Red";
row2[sColumn] = "18";
row2[mColumn] = "21";
this.SizeQuantityTable.Rows.Add(row2);

DataRow row3 = this.SizeQuantityTable.NewRow();
row3[sizeQuantityColumn] = "Green";
row3[sColumn] = "24";
row3[mColumn] = "27";
this.SizeQuantityTable.Rows.Add(row3);

OK. I have created three columns namely sizeQuantityColumn, sColumn and mColumn and added three rows namely row1, row2 and row2.

好。我创建了三列,即sizeQuantityColumn,sColumn和mColumn,并添加了三行,即row1,row2和row2。

So, Let's say I wanna set the selected item as row2 (So in the view, the second row should be highlighted).

所以,假设我想将所选项目设置为row2(因此在视图中,应突出显示第二行)。

How can I do this?

我怎样才能做到这一点?

EDIT

编辑

I hardcoded the SelectedIndex of the DataGrid to 1. (So the second row should be selected). In design time it shows as selected. But not in the run time. You can see it in the below snapshot.

我将DataGrid的SelectedIndex硬编码为1.(因此应该选择第二行)。在设计时,它显示为选中。但不是在运行时间。您可以在下面的快照中看到它。

So ultimaltely the problem is Not highlighting the row.

所以最后问题是没有突出显示行。

如何使用MVVM应用程序在WPF中以编程方式设置DataGrid的选定项?

5 个解决方案

#1


11  

There are a few way to select items in the DataGrid. It just depends which one works best for the situation

有几种方法可以在DataGrid中选择项目。这取决于哪一个最适合这种情况

First and most basic is SelectedIndex this will just select the Row at that index in the DataGrid

第一个也是最基本的是SelectedIndex,这将只选择DataGrid中该索引处的Row

 <DataGrid SelectedIndex="{Binding SelectedIndex}" />

private int _selectedIndex;
public int SelectedIndex
{
    get { return _selectedIndex; }
    set { _selectedIndex = value; NotifyPropertyChanged("SelectedIndex"); }
}

SelectedIndex = 2;

SelectedItem will select the row that matches the row you set

SelectedItem将选择与您设置的行匹配的行

<DataGrid SelectedItem="{Binding SelectedRow}" />

private DataRow _selectedRow;
public DataRow SelectedRow
{
    get { return _selectedRow; }
    set { _selectedRow = value; NotifyPropertyChanged("SelectedRow");}
}

SelectedRow = items.First(x => x.whatever == something);

The most common one is SelectedValue with SelectedValuePath set, in this case you set the column you want to select with and then to can select the row by setting the corresponding value

最常见的是SelectedValue和SelectedValuePath set,在这种情况下,您设置要选择的列,然后可以通过设置相应的值来选择行

<DataGrid SelectedValuePath="Size Quantity" SelectedValue="{Binding SelectionValue}" 

private string _selectedValue
public string SelectionValue 
{
    get { return _selectedValue; }
    set { _selectedValue = value; NotifyPropertyChanged("SelectionValue"); }
}

SelectionValue = "Blue";

Edit:

Here is my test and it is highlighting just fine

这是我的测试,它突出显示就好了

Code:

码:

public partial class MainWindow : Window, INotifyPropertyChanged
{
    public MainWindow()
    {
        InitializeComponent();

        this.SizeQuantityTable = new DataTable();
        DataColumn sizeQuantityColumn = new DataColumn();
        sizeQuantityColumn.ColumnName = "Size Quantity";
        ...................
        ........

    }

    private string _selectedValue;
    public string SelectionValue 
    {
        get { return _selectedValue; }
        set { _selectedValue = value; NotifyPropertyChanged("SelectionValue"); }
    }

    private int _selectedIndex;
    public int SelectedIndex
    {
        get { return _selectedIndex; }
        set { _selectedIndex = value; NotifyPropertyChanged("SelectedIndex"); }
    }

    private DataTable sizeQuantityTable;
    public DataTable SizeQuantityTable
    {
        get { return sizeQuantityTable; }
        set { sizeQuantityTable = value; NotifyPropertyChanged("SizeQuantityTable"); }
    }

    private void Button_Click_1(object sender, RoutedEventArgs e)
    {
        SelectedIndex = 2;
    }

    private void Button_Click_2(object sender, RoutedEventArgs e)
    {
        SelectionValue = "Blue";
    }

    private void NotifyPropertyChanged(string p)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(p));
        }
    }
}

Xaml:

XAML:

<Window x:Class="WpfApplication21.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="202" Width="232" Name="UI">

    <Grid DataContext="{Binding ElementName=UI}">
        <DataGrid SelectedValuePath="Size Quantity"        
                  SelectedValue="{Binding SelectionValue}" 
                  SelectedIndex="{Binding SelectedIndex}"
                  ItemsSource="{Binding SizeQuantityTable}"
                  AutoGenerateColumns="True" 
                  Margin="0,0,0,41" />
        <StackPanel Orientation="Horizontal" Height="37" VerticalAlignment="Bottom" >
            <Button Content="SelectedIndex" Height="26"  Width="107" Click="Button_Click_1"/>
            <Button Content="SelectedValue" Height="26"  Width="107" Click="Button_Click_2"/>
        </StackPanel>
    </Grid>
</Window>

Result:

结果:

如何使用MVVM应用程序在WPF中以编程方式设置DataGrid的选定项?

#2


3  

You can always use SelectedItem property and bind it against row, as such:

您始终可以使用SelectedItem属性并将其绑定到行,如下所示:

SelectedItem="{Binding ActiveRow}"

and in ViewModel do:

并在ViewModel中执行:

ActiveRow = secondRow;

#3


1  

Add SelectedItem, SelectedValue in your DataGrid.

在DataGrid中添加SelectedItem,SelectedValue。

<DataGrid 
        ItemsSource="{Binding SizeQuantityTable}"
        AutoGenerateColumns="True" 
        SelectedValue ="{Binding SelectedValue}"
        Margin="0,0,0,120" />

And in your view model

并在您的视图模型中

private string _selectedValue;
public string SelectedValue
{
    get
    {
        return _selectedValue;
    }
    set
    {
        _selectedValue = value;
        NotifyPropertyChanged("SelectedValue");
    }
}

private DataTable sizeQuantityTable;
public DataTable SizeQuantityTable
{
    get
    {
        return sizeQuantityTable;
    }
    set
    {
        sizeQuantityTable = value;
        NotifyPropertyChanged("SizeQuantityTable");
    }
}

You can use SelectedItem as well, that is preferred.

您也可以使用SelectedItem,这是首选。

#4


1  

I just had the same problem. I saw that the item of a datagrid was selected correctly at design time, but not at runtime. (By the way, I create the instance of the view model in the xaml).

我刚遇到同样的问题。我看到数据网格的项目在设计时被正确选择,但在运行时没有。 (顺便说一下,我在xaml中创建了视图模型的实例)。

I could solve this problem by moving the code to programmatically set the selected item from the view models constructor to a different method in the view model and then calling this method in the loaded event of the window (or usercontrol).

我可以通过移动代码以编程方式将所选项从视图模型构造函数设置为视图模型中的不同方法,然后在窗口(或usercontrol)的已加载事件中调用此方法来解决此问题。

Obviously the view is not completely done initializing itself when the view models constructor is called. This can be avoided by not coding in the view models constructor.

显然,在调用视图模型构造函数时,视图并未完全初始化。通过在视图模型构造函数中不编码可以避免这种情况。

View (xaml):

查看(xaml):

<Window x:Class="MyWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Test" 
        xmlns:viewModel="clr-namespace:ViewModels" Loaded="Window_Loaded">
    <Window.DataContext>
        <viewModel:ExampleViewModel/>
    </Window.DataContext>

View (code behind):

查看(代码背后):

    private void Window_Loaded(object sender, RoutedEventArgs e)
    {
        ((ExampleViewModel)this.DataContext).LoadData();
    }

If you do not like setting up the Loaded event in the code behind, you can also do it in xaml (references to "Microsoft.Expression.Interactions" and "System.Windows.Interactivity" are needed):

如果您不喜欢在后面的代码中设置Loaded事件,您也可以在xaml中执行此操作(需要引用“Microsoft.Expression.Interactions”和“System.Windows.Interactivity”):

    <Window x:Class="MyWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Test" 
        xmlns:viewModel="clr-namespace:ViewModels">
    <Window.DataContext>
        <viewModel:ExampleViewModel/>
    </Window.DataContext>
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="Loaded">
            <ei:CallMethodAction TargetObject="{Binding}" MethodName="LoadData"/>
        </i:EventTrigger>
    </i:Interaction.Triggers>

In each case, you call the LoadData method in the ViewModel:

在每种情况下,您都可以在ViewModel中调用LoadData方法:

public class ExampleViewModel
{
    /// <summary>
    /// Constructor.
    /// </summary>
    public ExampleViewModel()
    {
        // Do NOT set selected item here
    }


    public void LoadData()
    {
        // Set selected item here
    }

#5


0  

For anyone using Observable Collections you may find this solution useful.

对于使用Observable Collections的任何人,您可能会发现此解决方案很有用。

The SelectedModelIndex property simply returns the index of the SelectedModel from the ItemSource collection. I've found setting the SelectedIndex along with the SelectedItem highlights the row in the DataGrid.

SelectedModelIndex属性只是从ItemSource集合返回SelectedModel的索引。我发现设置SelectedIndex以及SelectedItem突出显示DataGrid中的行。

    private ObservableCollection<Model> _itemSource
    public ObservableCollection<Model> ItemSource
    {
        get { return _itemSource; }
        set 
        { 
            _itemSource = value; 
            OnPropertyChanged("ItemSource"); 
        }
    }

    // Binding must be set to One-Way for read-only properties
    public int SelectedModelIndex
    {
        get 
        {
            if (ItemSource != null && ItemSource.Count > 0)
                return ItemSource.IndexOf(SelectedModel);
            else
                return -1;
        }            
    }

    private Model _selectedModel;
    public Model SelectedModel
    {
        get { return _selectedModel; }
        set 
        {
            _selectedModel = value;
            OnPropertyChanged("SelectedModel"); 
            OnPropertyChanged("SelectedModelIndex");               
        }                
    }

#1


11  

There are a few way to select items in the DataGrid. It just depends which one works best for the situation

有几种方法可以在DataGrid中选择项目。这取决于哪一个最适合这种情况

First and most basic is SelectedIndex this will just select the Row at that index in the DataGrid

第一个也是最基本的是SelectedIndex,这将只选择DataGrid中该索引处的Row

 <DataGrid SelectedIndex="{Binding SelectedIndex}" />

private int _selectedIndex;
public int SelectedIndex
{
    get { return _selectedIndex; }
    set { _selectedIndex = value; NotifyPropertyChanged("SelectedIndex"); }
}

SelectedIndex = 2;

SelectedItem will select the row that matches the row you set

SelectedItem将选择与您设置的行匹配的行

<DataGrid SelectedItem="{Binding SelectedRow}" />

private DataRow _selectedRow;
public DataRow SelectedRow
{
    get { return _selectedRow; }
    set { _selectedRow = value; NotifyPropertyChanged("SelectedRow");}
}

SelectedRow = items.First(x => x.whatever == something);

The most common one is SelectedValue with SelectedValuePath set, in this case you set the column you want to select with and then to can select the row by setting the corresponding value

最常见的是SelectedValue和SelectedValuePath set,在这种情况下,您设置要选择的列,然后可以通过设置相应的值来选择行

<DataGrid SelectedValuePath="Size Quantity" SelectedValue="{Binding SelectionValue}" 

private string _selectedValue
public string SelectionValue 
{
    get { return _selectedValue; }
    set { _selectedValue = value; NotifyPropertyChanged("SelectionValue"); }
}

SelectionValue = "Blue";

Edit:

Here is my test and it is highlighting just fine

这是我的测试,它突出显示就好了

Code:

码:

public partial class MainWindow : Window, INotifyPropertyChanged
{
    public MainWindow()
    {
        InitializeComponent();

        this.SizeQuantityTable = new DataTable();
        DataColumn sizeQuantityColumn = new DataColumn();
        sizeQuantityColumn.ColumnName = "Size Quantity";
        ...................
        ........

    }

    private string _selectedValue;
    public string SelectionValue 
    {
        get { return _selectedValue; }
        set { _selectedValue = value; NotifyPropertyChanged("SelectionValue"); }
    }

    private int _selectedIndex;
    public int SelectedIndex
    {
        get { return _selectedIndex; }
        set { _selectedIndex = value; NotifyPropertyChanged("SelectedIndex"); }
    }

    private DataTable sizeQuantityTable;
    public DataTable SizeQuantityTable
    {
        get { return sizeQuantityTable; }
        set { sizeQuantityTable = value; NotifyPropertyChanged("SizeQuantityTable"); }
    }

    private void Button_Click_1(object sender, RoutedEventArgs e)
    {
        SelectedIndex = 2;
    }

    private void Button_Click_2(object sender, RoutedEventArgs e)
    {
        SelectionValue = "Blue";
    }

    private void NotifyPropertyChanged(string p)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(p));
        }
    }
}

Xaml:

XAML:

<Window x:Class="WpfApplication21.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="202" Width="232" Name="UI">

    <Grid DataContext="{Binding ElementName=UI}">
        <DataGrid SelectedValuePath="Size Quantity"        
                  SelectedValue="{Binding SelectionValue}" 
                  SelectedIndex="{Binding SelectedIndex}"
                  ItemsSource="{Binding SizeQuantityTable}"
                  AutoGenerateColumns="True" 
                  Margin="0,0,0,41" />
        <StackPanel Orientation="Horizontal" Height="37" VerticalAlignment="Bottom" >
            <Button Content="SelectedIndex" Height="26"  Width="107" Click="Button_Click_1"/>
            <Button Content="SelectedValue" Height="26"  Width="107" Click="Button_Click_2"/>
        </StackPanel>
    </Grid>
</Window>

Result:

结果:

如何使用MVVM应用程序在WPF中以编程方式设置DataGrid的选定项?

#2


3  

You can always use SelectedItem property and bind it against row, as such:

您始终可以使用SelectedItem属性并将其绑定到行,如下所示:

SelectedItem="{Binding ActiveRow}"

and in ViewModel do:

并在ViewModel中执行:

ActiveRow = secondRow;

#3


1  

Add SelectedItem, SelectedValue in your DataGrid.

在DataGrid中添加SelectedItem,SelectedValue。

<DataGrid 
        ItemsSource="{Binding SizeQuantityTable}"
        AutoGenerateColumns="True" 
        SelectedValue ="{Binding SelectedValue}"
        Margin="0,0,0,120" />

And in your view model

并在您的视图模型中

private string _selectedValue;
public string SelectedValue
{
    get
    {
        return _selectedValue;
    }
    set
    {
        _selectedValue = value;
        NotifyPropertyChanged("SelectedValue");
    }
}

private DataTable sizeQuantityTable;
public DataTable SizeQuantityTable
{
    get
    {
        return sizeQuantityTable;
    }
    set
    {
        sizeQuantityTable = value;
        NotifyPropertyChanged("SizeQuantityTable");
    }
}

You can use SelectedItem as well, that is preferred.

您也可以使用SelectedItem,这是首选。

#4


1  

I just had the same problem. I saw that the item of a datagrid was selected correctly at design time, but not at runtime. (By the way, I create the instance of the view model in the xaml).

我刚遇到同样的问题。我看到数据网格的项目在设计时被正确选择,但在运行时没有。 (顺便说一下,我在xaml中创建了视图模型的实例)。

I could solve this problem by moving the code to programmatically set the selected item from the view models constructor to a different method in the view model and then calling this method in the loaded event of the window (or usercontrol).

我可以通过移动代码以编程方式将所选项从视图模型构造函数设置为视图模型中的不同方法,然后在窗口(或usercontrol)的已加载事件中调用此方法来解决此问题。

Obviously the view is not completely done initializing itself when the view models constructor is called. This can be avoided by not coding in the view models constructor.

显然,在调用视图模型构造函数时,视图并未完全初始化。通过在视图模型构造函数中不编码可以避免这种情况。

View (xaml):

查看(xaml):

<Window x:Class="MyWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Test" 
        xmlns:viewModel="clr-namespace:ViewModels" Loaded="Window_Loaded">
    <Window.DataContext>
        <viewModel:ExampleViewModel/>
    </Window.DataContext>

View (code behind):

查看(代码背后):

    private void Window_Loaded(object sender, RoutedEventArgs e)
    {
        ((ExampleViewModel)this.DataContext).LoadData();
    }

If you do not like setting up the Loaded event in the code behind, you can also do it in xaml (references to "Microsoft.Expression.Interactions" and "System.Windows.Interactivity" are needed):

如果您不喜欢在后面的代码中设置Loaded事件,您也可以在xaml中执行此操作(需要引用“Microsoft.Expression.Interactions”和“System.Windows.Interactivity”):

    <Window x:Class="MyWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Test" 
        xmlns:viewModel="clr-namespace:ViewModels">
    <Window.DataContext>
        <viewModel:ExampleViewModel/>
    </Window.DataContext>
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="Loaded">
            <ei:CallMethodAction TargetObject="{Binding}" MethodName="LoadData"/>
        </i:EventTrigger>
    </i:Interaction.Triggers>

In each case, you call the LoadData method in the ViewModel:

在每种情况下,您都可以在ViewModel中调用LoadData方法:

public class ExampleViewModel
{
    /// <summary>
    /// Constructor.
    /// </summary>
    public ExampleViewModel()
    {
        // Do NOT set selected item here
    }


    public void LoadData()
    {
        // Set selected item here
    }

#5


0  

For anyone using Observable Collections you may find this solution useful.

对于使用Observable Collections的任何人,您可能会发现此解决方案很有用。

The SelectedModelIndex property simply returns the index of the SelectedModel from the ItemSource collection. I've found setting the SelectedIndex along with the SelectedItem highlights the row in the DataGrid.

SelectedModelIndex属性只是从ItemSource集合返回SelectedModel的索引。我发现设置SelectedIndex以及SelectedItem突出显示DataGrid中的行。

    private ObservableCollection<Model> _itemSource
    public ObservableCollection<Model> ItemSource
    {
        get { return _itemSource; }
        set 
        { 
            _itemSource = value; 
            OnPropertyChanged("ItemSource"); 
        }
    }

    // Binding must be set to One-Way for read-only properties
    public int SelectedModelIndex
    {
        get 
        {
            if (ItemSource != null && ItemSource.Count > 0)
                return ItemSource.IndexOf(SelectedModel);
            else
                return -1;
        }            
    }

    private Model _selectedModel;
    public Model SelectedModel
    {
        get { return _selectedModel; }
        set 
        {
            _selectedModel = value;
            OnPropertyChanged("SelectedModel"); 
            OnPropertyChanged("SelectedModelIndex");               
        }                
    }