Примечание. См. также связанных опубликовать.
В этой статье описывается, как можно привязать поведения из исходного кода.
Однако я твердо не советовал бы вам идти по этому пути, если у вас нет веской необходимости в этом. Если вы используете этот подход в своем ViewModel
, вы потеряете всякую тестируемость, поскольку он генерирует ViewModel
, который сильно связан с View
и фактически не может жить без него. (Дополнительное примечание: по этой причине также не рекомендуется возвращать аргументы событий в ViewModel
, используйте CommandParameter
вместо того, чтобы возвращать DataContext
, если необходимо).
Обычно вы можете архивировать свою цель с помощью MVVM другим способом, и остальная часть сообщения описывает это.
Во-первых, вам не нужно использовать Command
для получения выбранного свойства или для получения уведомления об изменении этого свойства. Обычный шаблон для этого состоит в том, что вы привязываете SelectedItem
вашего списка к свойству в вашем ViewModel
. Теперь вы можете использовать событие PropertyChanged
, чтобы отслеживать изменение этого свойства.
Во-вторых, используйте шаблоны для создания и стилизации ваших списков. Если вам нужно показать их только при выборе элемента, используйте BooleanToVisibility
(Образец см. Здесь converter и привяжите свойство Visibility
подсписок к свойству на вашем ViewModel
с помощью конвертера (не в моем примере).
В примере создается ListBox, ItemsSource
которого привязан к свойству Items объекта ViewModel
. Далее он создает ContentControl
, DataContext
которого привязан к SelectedItem
ViewModel
. Затем ContentControl
снова содержит ListBox
, где DataContext
привязан к свойству SubItem
ItemViewModel
. MainViewModel
генерирует тестовые данные для отображения во время разработки и выполнения.
В остальной части поста показан образец:
1. XAML главной страницы (кроме):
<ContentControl x:Name="target1" Grid.Row="1" DataContext="{Binding SelectedItem}" Margin="20,0">
<ContentControl.Template>
<ControlTemplate>
<StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Name:" Margin="0,0,10,0"/>
<TextBlock Text="{Binding Name}"/>
</StackPanel>
<ListBox ItemsSource="{Binding SubItems}">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="Padding" Value="1"/>
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<Border Background="navy" BorderBrush="White" BorderThickness="1">
<TextBlock Text="{Binding Name}"/>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
</ControlTemplate>
</ContentControl.Template>
</ContentControl>
</Grid>
</Grid>
2. Модель основного представления
public MainViewModel()
{
// working with fields to ensure no events are fired during initial phase
this._items = new ObservableCollection<ItemViewModel>();
for (int i = 0; i < 5; ++i) {
var item = new ItemViewModel() { Name = string.Format("Item {0}", i) };
for (int j = 0; j < 3; ++j)
item.SubItems.Add(new ItemViewModel() { Name = string.Format("{0} - Sub Item {1}", item.Name, j) });
this._items.Add(item);
}
this.SelectedItem = this._items[0];
if (IsInDesignMode) {
// Code runs in Blend --> create design time data.
} else {
// Code runs "for real"
}
}
#region [Items]
/// <summary>
/// The <see cref="Items" /> property's name.
/// </summary>
public const string ItemsPropertyName = "Items";
private ObservableCollection<ItemViewModel> _items = default(ObservableCollection<ItemViewModel>);
/// <summary>
/// Gets the Items property.
/// TODO Update documentation:
/// Changes to that property's value raise the PropertyChanged event.
/// This property's value is broadcasted by the Messenger's default instance when it changes.
/// </summary>
public ObservableCollection<ItemViewModel> Items {
get {
return _items;
}
set {
if (_items == value) {
return;
}
var oldValue = _items;
_items = value;
// Update bindings, no broadcast
RaisePropertyChanged(ItemsPropertyName);
// Update bindings and broadcast change using GalaSoft.MvvmLight.Messenging
//RaisePropertyChanged(ItemsPropertyName, oldValue, value, true);
}
}
#endregion
#region [SelectedItem]
/// <summary>
/// The <see cref="SelectedItem" /> property's name.
/// </summary>
public const string SelectedItemPropertyName = "SelectedItem";
private ItemViewModel _selectedItem = default(ItemViewModel);
/// <summary>
/// Gets the SelectedItem property.
/// TODO Update documentation:
/// Changes to that property's value raise the PropertyChanged event.
/// This property's value is broadcasted by the Messenger's default instance when it changes.
/// </summary>
public ItemViewModel SelectedItem {
get {
return _selectedItem;
}
set {
if (_selectedItem == value) {
return;
}
var oldValue = _selectedItem;
_selectedItem = value;
// Update bindings, no broadcast
RaisePropertyChanged(SelectedItemPropertyName);
// Update bindings and broadcast change using GalaSoft.MvvmLight.Messenging
//RaisePropertyChanged(SelectedItemPropertyName, oldValue, value, true);
}
}
#endregion
}
3. Модель ItemView
открытый класс ItemViewModel: ViewModelBase {#region [Имя]
/// <summary>
/// The <see cref="Name" /> property's name.
/// </summary>
public const string NamePropertyName = "Name";
private string _name = default(string);
/// <summary>
/// Gets the Name property.
/// TODO Update documentation:
/// Changes to that property's value raise the PropertyChanged event.
/// This property's value is broadcasted by the Messenger's default instance when it changes.
/// </summary>
public string Name {
get {
return _name;
}
set {
if (_name == value) {
return;
}
var oldValue = _name;
_name = value;
// Update bindings, no broadcast
RaisePropertyChanged(NamePropertyName);
// Update bindings and broadcast change using GalaSoft.MvvmLight.Messenging
//RaisePropertyChanged(NamePropertyName, oldValue, value, true);
}
}
#endregion
#region [SubItems]
/// <summary>
/// The <see cref="SubItems" /> property's name.
/// </summary>
public const string SubItemsPropertyName = "SubItems";
private ObservableCollection<ItemViewModel> _myProperty = new ObservableCollection<ItemViewModel>();
/// <summary>
/// Gets the SubItems property.
/// TODO Update documentation:
/// Changes to that property's value raise the PropertyChanged event.
/// This property's value is broadcasted by the Messenger's default instance when it changes.
/// </summary>
public ObservableCollection<ItemViewModel> SubItems {
get {
return _myProperty;
}
set {
if (_myProperty == value) {
return;
}
var oldValue = _myProperty;
_myProperty = value;
// Update bindings, no broadcast
RaisePropertyChanged(SubItemsPropertyName);
// Update bindings and broadcast change using GalaSoft.MvvmLight.Messenging
//RaisePropertyChanged(SubItemsPropertyName, oldValue, value, true);
}
}
#endregion
}
Изменить 2
Шаблон элемента управления Panorama
можно найти здесь а>.
person
AxelEckenberger
schedule
25.06.2011