如何在MVVM中从ViewModel中选择数据网格中的一行

本文关键字:网格 一行 数据网 数据 MVVM 中从 选择 ViewModel | 更新日期: 2023-09-27 18:05:25

我正在尝试验证数据网格中的用户输入,我这样做的方式是:

I)允许用户添加行

II)允许用户填充一些单元格

当EndEdit()事件发生时,我将更新我的模型

IV)如果模型无法更新(例如当用户没有提供时)

V)这里是棘手的部分!我想留在数据网格的错误行上,但是尽管我已经正确设置了SelectedIndex和SelectedValue,但高度亮化的行将发生变化。

这是我的XAML:
<DataGrid x:Name="gd_Contacts" SelectedItem="{Binding SelectedContact,Converter={StaticResource NewPlaceConverter}}" 
              SelectedIndex="{Binding SelectedItemIndex}"
              Margin="0,5,1,0" ItemsSource="{Binding ContactCollection, Mode=TwoWay}" 
              CanUserAddRows="True" CanUserDeleteRows="False" AutoGenerateColumns="False" Grid.Column="1">
这是我的ViewModel:
private ObservableCollection<ActionEnabledContacts> FContactCollection;
//....
public ActionEnabledContacts SelectedContact //THE PROPERTY FOR SELECTEDITEM
    {
        get { return FSelectedContact; }
        set 
        { 
            //
            List <ActionEnabledContacts> InvalidList=ContactCollection.Where<ActionEnabledContacts>(p => p.cnt_Key == 0).ToList();
            if (InvalidList != null && InvalidList.Count > 0)
            {
                //now find index of that bastard
                List<ActionEnabledContacts> AllContacts = ContactCollection.ToList();
                int BastardIndex = 0;
                foreach (ActionEnabledContacts AContact in AllContacts)
                {
                    if (AContact.cnt_Key == 0)
                    {
                        FSelectedContact = InvalidList[0];
                        NotifyPropertyChanged();
                        SelectedItemIndex = BastardIndex;
                        //^^^^ THIS LINE DO UPDATE SELECTEDINDEX AND CALL NotifyPropertyChanged()
                    }
                    BastardIndex++;
                }
            }
            else
            {
                //
                FSelectedContact = value;
                NotifyPropertyChanged();
            }
        }
    }

如何在MVVM中从ViewModel中选择数据网格中的一行

当选择正在改变时你不能改变选择…如果有意义的话:P

如果选择刚刚更改,您将不得不等待,直到您可以再次以编程方式更改它。这通常会使用Dispatcher.BeginInvoke将调用添加到Dispatcher队列中,因此它会在当前选择被处理后执行。

if (AContact.cnt_Key == 0)
{
    FSelectedContact = InvalidList[0];
    NotifyPropertyChanged();
    Application.Current.Dispatcher.BeginInvoke(new Action(() =>
        SelectedItemIndex = BastardIndex));
}
BastardIndex++;

在你的视图模型中这样做并不是最好的解决方案,尽管- mvvm明智或在多个UI线程场景中。您可以简单地在该行中引发一个事件(在EventArgs中传递索引),让视图订阅该事件,并从事件处理程序中触发Dispatcher调用(使用this.Dispatcher而不是Application.Current.Dispatcher)。

多亏了@almulo,我已经在ViewModel中实现了一个事件,并在View中实现了相应的处理程序,它像一个魅力一样工作,对于那些可能需要帮助的人来说,这些是步骤:

I)在ViewModel中添加一个像这样的事件

public event EventHandler<EventArg<int>> DataGridRowSelectionChange;

*注意EventArg只是一个简单的类,可以保存T类型的值,如下所示:

    public class EventArg<T> : EventArgs
{
    private T FEventData;
    public EventArg(T Param)
    {
        // TODO: Complete member initialization
        FEventData = Param;
    }
    public T EventData
    {
        get { return FEventData; }
        set { FEventData = value; }
    }
}

II),当你想改变选定的行:

if (DataGridRowSelectionChange != null)
     DataGridRowSelectionChange(this, new EventArg<int>(DesiredIndex));

III)在View构造函数中添加事件处理程序,如下所示:

((YourViewModelClass)DataContext).DataGridRowSelectionChange += CurrentViewModel_DataGridRowSelectionChange_EventHandler;

IV),最后在View中编写处理程序,如下所示:

void CurrentViewModel_DataGridRowSelectionChange_EventHandler(object sender, EventArg<int> e)
    {
       Dispatcher.BeginInvoke(new Action(() => GRIDNAME.SelectedIndex = e.EventData));
    }

就这些了:)