2

我有一个 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);
        }
    }
4

4 回答 4

4

我会使用ItemContainerStyleonListBox将项目的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);
}
于 2010-05-10T17:32:03.553 回答
3

这对我来说看起来相当干净,尽管您可以使用绑定SelectedItems到 VM 上的属性Mode=OneWayToSource,然后使用来自RemoveTags.
我不完全确定,但在这种情况下,您可以使用强类型的 IList 集合。

于 2010-05-10T16:29:27.073 回答
0

为什么不将 type 参数指定RelayCommand为 a List<Tag>,因为无论如何这就是你要得到的?没有必要指定比这更通用的类型,因为执行的处理程序是硬编码的,可以处理Tag对象列表。由于您已经在那里建立了依赖关系,因此您也可以在 type 参数上建立它。然后您执行的处理程序将不需要任何强制转换或复制。

于 2010-05-10T16:22:27.237 回答
0

1.) 将您的移除按钮绑定到您的 ViewModel 中的命令。

2.) 设置绑定时,使用 CommandParameter 通过为 ListBox 命名并使用 ElementName=NameOfListBox, Path=SelectedItems 从 ListBox 中获取 Selecteditems

3.) 确保 ViewModel 中的 Command 传递参数。您将获得一个可以转换为 IList 的对象。

下面是一个简单的示例,这应该可以帮助您设置结构。

在视图中:

<Button Command="{Binding CommandInViewModelForRemove}"
        CommandParameter="{Binding ElementName=blah,Path=SelectedItems}"

<ListBox x:Name="blah" .... />

在视图模型中:

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
}

希望这可以帮助!

于 2010-05-10T18:39:22.213 回答