将项添加到ObservableCollection,并使其在绑定的ListCollectionView中被选中



我有一个带有ObservableCollection的ViewModel和一个使用Xaml声明的CollectionViewSource的View,后者绑定到DataGrid.ItemsSource

ViewModel有一个创建新对象并将其添加到ObservableCollection的命令。同样在ViewModel中,我正在处理CollectionChanged事件,所以我"知道"何时发生Add。

我的疑问是:

如何在DataGrid中选择刚刚添加的对象?

请注意,添加和更改的事件都在ViewModel中,但选择必须在View中进行。

我不介意基于代码隐藏的解决方案。

ViewModel:

public class TelaInicialViewModel : ViewModelBase
{
    public ObservableCollection<PacienteViewModel> Pacientes { get; set; }
    IRepositório<Paciente> _repositório_pacientes = new RepositórioPaciente();
    // CONSTRUTOR
    public TelaInicialViewModel()
    {
        var pacientes = _repositório_pacientes.Items.Select(p => new PacienteViewModel(p));
        Pacientes = new ObservableCollection<PacienteViewModel>(pacientes);
        Pacientes.CollectionChanged += Pacientes_CollectionChanged;
    }

    void Pacientes_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        switch (e.Action)
        {
            case NotifyCollectionChangedAction.Add:
                foreach (var added in e.NewItems)
                {
                    var p = added as PacienteViewModel;
                    if (p != null)
                    {
                        var novoPaciente = p.GetModel();  /////////  HERE I HAVE IT!!
                        _repositório_pacientes.Adicionar(novoPaciente);
                    }
                }
                break;
            case NotifyCollectionChangedAction.Replace:
                // ...
                break;
        }
    }

    void AdicionarPaciente()
    {
        var formulárioPaciente = new FormulárioCriaçãoPaciente();
        PacienteViewModel novoPaciente = formulárioPaciente.ExibirDiálogo(new Paciente());
        if (novoPaciente != null)
            //////// HERE I HAVE IT!!!
            Pacientes.Add(novoPaciente);
    }
    public ICommand ComandoAdicionarPaciente { get { return new RelayCommand(AdicionarPaciente); } }
}

视图(Xaml)

<UserControl.Resources>
    <CollectionViewSource
        x:Key="PacientesViewSource"
        Source="{Binding Pacientes}"
        Filter="PacientesViewSource_Filter"/>
</UserControl.Resources>

<DockPanel>
    <DockPanel DockPanel.Dock="Top" Margin="0,10,0,0" >
        <TextBox x:Name="FiltroPacienteTextBox" Height="30"
            TextChanged="FiltroPacienteTextBox_TextChanged"
            DockPanel.Dock="Bottom" Margin="10,10,10,0"/>
        <Button x:Name="botaoNovoPaciente" Width="120" Content="Novo"
            HorizontalAlignment="Left" Height="30" Margin="10,0,0,0"
            Command="{Binding ComandoAdicionarPaciente}"/>
    </DockPanel>
    <DataGrid x:Name="pacienteDataGrid" Margin="0,10,0,0"
        AutoGenerateColumns="False"
        CanUserAddRows="False" CanUserDeleteRows="False"
        CanUserReorderColumns="False" CanUserResizeRows="False"
        ItemsSource="{Binding Source={StaticResource PacientesViewSource}}"
        IsSynchronizedWithCurrentItem="True">
    </DataGrid>
</DockPanel>        

我鼓励您在这里坚持MVVM模式。在这种情况下,我通常会向ViewModel添加表示所选项目的属性。这将在ViewModel中保留所有重要的逻辑,以便对其进行测试。我想在你的ViewModel中添加以下内容(如果你的ViewModel是DependencyObject,你可以在这里使用DependencyProperty):

private Paciente _SelectedPaciente;
public Paciente SelectedPaciente
{
    get { return this._SelectedPaciente; }
    set
    {
        if (this._SelectedPaciente != value)
        {
            this._SelectedPaciente = value;
            this.RaisePropertyChanged("SelectedPaciente");
        }
    }
}

然后像这样修改你的DataGrid

<DataGrid x:Name="pacienteDataGrid" 
          Margin="0,10,0,0"
          AutoGenerateColumns="False"
          CanUserAddRows="False"
          CanUserDeleteRows="False"
          CanUserReorderColumns="False"
          CanUserResizeRows="False"
          ItemsSource="{Binding Source={StaticResource PacientesViewSource}}"
          SelectedItem="{Binding SelectedPaciente, Mode=TwoWay}"
          IsSynchronizedWithCurrentItem="True">

然后像这样修改你的AdicionarPaciente

void AdicionarPaciente()
{
    var formulárioPaciente = new FormulárioCriaçãoPaciente();
    PacienteViewModel novoPaciente = formulárioPaciente.ExibirDiálogo(new Paciente());
    if (novoPaciente != null)
    {
        //////// HERE I HAVE IT!!!
        Pacientes.Add(novoPaciente);
        this.SelectedPaciente = novoPaciente;
    }
}

现在,您可以为ViewModel编写一个单元测试,以确认当调用添加新Paciente的命令时,选择了新Paciente

好吧,看看评论中提出的一些答案,我找到了一种非常方便的方法来做我想做的事情:

视图(代码隐藏)

public partial class TelaInicialView : UserControl
{
    CollectionViewSource _pacientes_source;
    public TelaInicialView()
    {
        InitializeComponent();
        Loaded += TelaInicialView_Loaded;
    }

    void TelaInicialView_Loaded(object sender, RoutedEventArgs e)
    {
        _pacientes_source = FindResource("PacientesViewSource") as CollectionViewSource;
        // FIRST STEP: CAST CollectionView.Source to INotifyCollectionChanged, and listen to its CollectionChanged event
        var source = _pacientes_source.Source as INotifyCollectionChanged;
        source.CollectionChanged += TelaInicialView_CollectionChanged;
    }
    void TelaInicialView_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        // SECOND STEP: WHEN YOU ADD SOMETHING, SELECT IT!
        if (e.Action == NotifyCollectionChangedAction.Add)
            pacienteDataGrid.SelectedItem = e.NewItems[0];
    }
    // ...
}

最新更新