将项目添加到 ObservableCollection 并使其在其绑定的 ListCollectionView 中被选中
Adding item to ObservableCollection and make it selected in its bound ListCollectionView
我有一个带有 ObservableCollection
的 ViewModel,以及一个使用 Xaml 声明的 CollectionViewSource
的视图,它绑定到 DataGrid.ItemsSource
.
ViewModel 有一个创建新对象并将其添加到 ObservableCollection
的命令。同样在 ViewModel 中,我正在处理 CollectionChanged
事件,因此当发生添加时我 "know"。
我的疑问是:
how can I make the just-added object selected in the DataGrid?
请注意,添加和更改事件都在 ViewModel 中,但选择必须在 View 中发生。
我不介意基于代码隐藏的解决方案。
视图模型:
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>
嗯,看了一些评论建议的答案,我发现了一个很方便的方法来做我想做的事:
查看(代码隐藏)
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];
}
// ...
}
我鼓励您在这里坚持使用 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
被选中。
我有一个带有 ObservableCollection
的 ViewModel,以及一个使用 Xaml 声明的 CollectionViewSource
的视图,它绑定到 DataGrid.ItemsSource
.
ViewModel 有一个创建新对象并将其添加到 ObservableCollection
的命令。同样在 ViewModel 中,我正在处理 CollectionChanged
事件,因此当发生添加时我 "know"。
我的疑问是:
how can I make the just-added object selected in the DataGrid?
请注意,添加和更改事件都在 ViewModel 中,但选择必须在 View 中发生。
我不介意基于代码隐藏的解决方案。
视图模型:
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>
嗯,看了一些评论建议的答案,我发现了一个很方便的方法来做我想做的事:
查看(代码隐藏)
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];
}
// ...
}
我鼓励您在这里坚持使用 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
被选中。