我有一个WPF ListBox中的项目列表。我想允许用户选择其中几个项目,然后单击“删除”按钮从列表中删除这些项目。
使用MVVM RelayCommand模式,我创建了一个带有以下签名的命令:
public RelayCommand<IList> RemoveTagsCommand { get; private set; }
在我的视图中,我将这样的RemoveTagsCommand连接起来:
<DockPanel>
<Button DockPanel.Dock="Right" Command="{Binding RemoveTagsCommand}" CommandParameter="{Binding ElementName=TagList, Path=SelectedItems}">Remove tags</Button>
<ListBox x:Name="TagList" ItemsSource="{Binding Tags}" SelectionMode="Extended">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.Resources>
<DataTemplate DataType="{x:Type Model:Tag}">
...
</DataTemplate>
</ListBox.Resources>
</ListBox>
</DockPanel>
我的ViewModel构造函数设置命令的实例:
RemoveTagsCommand = new RelayCommand<IList>(RemoveTags, CanRemoveTags);
我目前对RemoveTags的实现感觉很笨重,有强制转换和复制。有没有更好的方法来实现这个?
public void RemoveTags(IList toRemove)
{
var collection = toRemove.Cast<Tag>();
List<Tag> copy = new List<Tag>(collection);
foreach (Tag tag in copy)
{
Tags.Remove(tag);
}
}
答案 0 :(得分:4)
我使用ItemContainerStyle
上的ListBox
将项目'IsSelected
属性绑定到模型中的标志(而不是视图模型),例如:
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="IsSelected" Value="{Binding Path=IsSelected, Mode=TwoWay}"/>
</Style>
</ListBox.ItemContainerStyle>
然后你不必担心你传递给你的命令的论点。另外,根据我的经验,当视图模型中的对象很容易知道用户选择它时,您会发现该信息的其他用途。
命令中的代码如下:
foreach (Tag t in Tags.Where(x => x.IsSelected).ToList())
{
Tags.Remove(t);
}
答案 1 :(得分:2)
虽然您可以使用SelectedItems
将Mode=OneWayToSource
绑定到VM上的属性,然后使用RemoveTags
中的绑定集合属性,但这对我来说看起来相当干净。我不完全确定,但在这种情况下你可以使用强类型的IList集合。
答案 2 :(得分:0)
为什么不指定RelayCommand
的类型参数为List<Tag>
,因为这是你要获得的?没有必要指定比它更通用的类型,因为执行的处理程序是硬编码的,可以使用Tag
个对象列表。既然你已经在那里建立了依赖关系,你也可以在类型参数上创建它。然后你执行的处理程序将不需要任何强制转换或复制。
答案 3 :(得分:0)
1。)在ViewModel中将“删除”按钮绑定到命令。
2。)设置绑定时,使用CommandParameter从ListBox获取Selecteditems,为ListBox命名并使用ElementName = NameOfListBox,Path = SelectedItems
3.确保ViewModel中的Command传递参数。您将获得一个可以作为IList进行投射的对象。
下面是一个简单的例子,这可以帮助您设置结构。
在视图中:
<Button Command="{Binding CommandInViewModelForRemove}"
CommandParameter="{Binding ElementName=blah,Path=SelectedItems}"
<ListBox x:Name="blah" .... />
在ViewModel中:
public ViewModel(){
RemoveCommand = new RelayCommand<object>(Remove, CanRemove);
}
private void Remove(object selectedItems){
var list = (IList)selectedItems;
//do some work, cast to view models that represent list items, etc
}
希望这有帮助!