Возьмем эту простую модель представления с базовым классом, который реализует интерфейс INotifyPropertyChanged
, и классом Train, TrainViewModel и MainViewModel.
public class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
protected void SetValue<T>(
ref T storage, T value, [CallerMemberName] string propertyName = null)
{
if (!Equals(storage, value))
{
storage = value;
OnPropertyChanged(propertyName);
}
}
}
public class Train : ViewModelBase
{
private string name;
public string Name
{
get { return name; }
set { SetValue(ref name, value); }
}
private string details;
public string Details
{
get { return details; }
set { SetValue(ref details, value); }
}
// more properties
}
public class TrainViewModel : ViewModelBase
{
public ObservableCollection<Train> Trains { get; }
= new ObservableCollection<Train>();
private Train selectedTrain;
public Train SelectedTrain
{
get { return selectedTrain; }
set { SetValue(ref selectedTrain, value); }
}
}
public class MainViewModel
{
public TrainViewModel TrainViewModel { get; } = new TrainViewModel();
}
, который может быть инициализирован в конструкторе MainWindow следующим образом:
public MainWindow()
{
InitializeComponent();
var vm = new MainViewModel();
DataContext = vm;
vm.TrainViewModel.Trains.Add(new Train
{
Name = "Train 1",
Details = "Details of Train 1"
});
vm.TrainViewModel.Trains.Add(new Train
{
Name = "Train 2",
Details = "Details of Train 2"
});
}
Элементы управления TrainDetails будут выглядеть следующим образом, конечно, с большим количеством элементов для большего количества свойств класса Train:
<UserControl ...>
<StackPanel>
<TextBlock Text="{Binding Name}"/>
<TextBlock Text="{Binding Details}"/>
</StackPanel>
</UserControl>
и родительским UserControl, таким образом, где я непосредственно используюListBox вместо элемента управления TrainList:
<UserControl ...>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<ListBox ItemsSource="{Binding Trains}"
SelectedItem="{Binding SelectedTrain}"
DisplayMemberPath="Name"/>
<local:TrainDetailsControl Grid.Column="1" DataContext="{Binding SelectedTrain}"/>
</Grid>
</UserControl>
Он будет создан в MainWindow следующим образом:
<Grid>
<local:TrainControl DataContext="{Binding TrainViewModel}"/>
</Grid>
Обратите внимание, что в этом простом примере элементы в пользовательском элементе управления XAML связываютсянепосредственно к экземпляру модели представления, который передается через их DataContext.Это означает, что UserControl знает модель представления (или хотя бы их свойства).Более общий подход заключается в объявлении свойств зависимостей в классе UserControl, которые связаны для просмотра свойств модели.Тогда UserControl будет независимым от какой-либо конкретной модели представления.