我有一个
页面名称空间:
xmlns:Custom="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:GalaSoft_MvvmLight_Command="clr-namespace:GalaSoft.MvvmLight.Command;assembly=GalaSoft.MvvmLight.Extras.WP7"
设计时xaml:
<ListBox x:Name="ItemGroupsList" ItemsSource="{Binding ItemGroups}" Height="496"
SelectedItem="{Binding SelectedItemGroup, Mode=TwoWay}" >
<Custom:Interaction.Triggers>
<Custom:EventTrigger EventName="SelectionChanged">
<GalaSoft_MvvmLight_Command:EventToCommand
x:Name="SelectionChangedEvent"
Command="{Binding GoToEditItemGroupCommand, Mode=OneWay}"
PassEventArgsToCommand="True"/>
</Custom:EventTrigger>
</Custom:Interaction.Triggers>
在代码中,我在运行时生成多个列表框,并希望能够绑定到viewmode上的relaycommand,如上面显示的上述xaml代码...
如何在运行时在视图后面的代码中执行上述操作。
另外,我想将动态生成的列表框的datacontext分配给不同于当前绑定到视图的视图模型。
基本上,我有一个panaroma,并且动态创建每个panaroma项目,每个panaroma项目都有一个列表框,该列表框将绑定到具有relaycommands的viewmodel
答案 0 :(得分:1)
注意:另请参阅related post。
This article描述了如何从代码中附加行为。
然而,除非您有引人注目的需要,否则我坚决不建议您沿着这条路走下去。如果您在ViewModel
中使用此方法,则会失去所有可测试性,因为它会生成与ViewModel
高度耦合的View
,实际上如果没有它就无法生存。 (旁注:因此,将事件参数返回到ViewModel
使用CommandParameter
而不是在需要时返回DataContext
也不是一种好习惯。
通常你可以用另一种方式使用MVVM归档你的目标,其余的帖子描述了这一点。
首先,您不需要使用Command
来获取所选属性,也不需要获取此属性已更改的通知。通常的模式是将列表框的SelectedItem
绑定到ViewModel
中的属性。现在,您可以使用PropertyChanged
事件来跟踪此属性何时更改。
其次,使用模板生成列表框并设置样式。如果您只需在选择项目时显示它们,请使用BooleanToVisibility
(Sample see here转换器并将子列表框'Visibility
属性绑定到ViewModel
上的属性转换器(不是我的样本)。
该示例创建一个ListBox,其ItemsSource
绑定到ViewModel
的Items属性。它进一步创建ContentControl
,其DataContext
与SelectedItem
的{{1}}绑定。然后,ViewModel
再次包含ContentControl
,其中ListBox
绑定到DataContext
的{{1}}属性。 SubItem
生成要在设计时和运行时显示的测试数据。
帖子的其余部分显示了一个示例:
<强> 1。主页的XAML(除外):
ItemViewModel
<强> 2。主视图模型
MainViewModel
第3。 ItemView模型
public class ItemViewModel:ViewModelBase { #region [姓名]
<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
}
控件的模板here。