当ItemTemplate是用户控件时,如何从ListView中正确删除项目?

时间:2016-03-10 13:29:58

标签: c# wpf mvvm

我试着按照这里的例子:

WPF ListBox with self-removing items

这是有意义的,但我的问题是,ListView本身正在确定使用的模板。因此,它可以轻松地自定义绑定以指向正确的目标。然而,我正在使用MVVM并且正在努力使两者结合在一起。

示例,如果模板是:

<ListBox.ItemTemplate>
      <DataTemplate>
          <local:MyItemView/>
      </DataTemplate>
</ListBox.ItemTemplate>

这突然变得更加困难,理想情况下,我希望在不对绑定进行硬编码的情况下重用该视图。

我尝试使用DependencyProperty来传递ListElement,所以我可以通过命令将其删除。

<ListBox.ItemTemplate Name="myList">
      <DataTemplate>
          <local:MyItemView TheList={Binding ElementName=myList, Path=DataContext.List} TheElement={Binding}/>
      </DataTemplate>
</ListBox.ItemTemplate>

但是,我遇到了绑定错误,告诉我它无法将TheElement的值从MyClassViewModel转换为MyClass。即使我评论说TheList总是为NULL。

基本上我想要:

class MyDataClass { // pretend there's more here}

class MyDataClassContainer
{
    public ObservableCollection<MyDataClass> Items;
    public void Add(MyDataClass);
    public void Remove(MyDataClass);
}

class MyDataClassEntryViewModel
{
    public static readonly DependencyProperty ListItemProperty = DependencyProperty.Register("TheClass", typeof(MyDataClass), typeof(MyDataClassEntryViewModel));
    public static readonly DependencyProperty ListContainerProperty = DependencyProperty.Register("TheContainer", typeof(MyDataClassContainer), typeof(MyDataClassEntryViewModel));

    public MyDataClass TheClass;
    public MyDataClassContainer TheContainer;
    public ICommand Delete = new DelegateCommand(RemoveItem);

    private function RemoveItem(object parameter)
    {
        TheContainer.Remove(TheClass);
    }
}

使用以下模板:

MyDataClassEntryView.xaml

<UserControl>
    <Grid>
        <Button Content="Delete" Command="{Binding Path=Delete}"/>
    </Grid>
</UserControl>

MyDataContainerView.xaml

<UserControl>
    <ListView x:Name="listView" ItemsSource="{Binding Path=Container.Items}">
        <ListView.ItemTemplate>
            <DataTemplate>
                <local:MyDataClassEntryView TheClass="{Binding}" TheContainer="{Binding ElementName=listView, Path=DataContext.Container}"/>
            </DataTemplate>
        </ListView.ItemTemplate>
     </ListView>
</UserControl>

注意:我省略了大多数多余的行,因为我试图得到一个我可以在任何地方使用的通用答案。不是硬编码的单一解决方案。我基本上想要保持MVVM结构强大,在后台没有大量的硬编码和布线。我想尽可能多地使用XAML。

我看到从列表中删除的所有其他方法都需要各种假设,例如使用SelectedIndex / Item,或者使用ContainerView本身的方法将元素作为参数进行投射,然后删除等等。简而言之,大多数解决方案都是根据给定的例子编写的。感觉应该有一种简单的方法来实现WPF。

由于ListView会自动创建我的子ViewModel / Views的实例,因此我无法显然获取任何数据。我只想基本上使用绑定传递参数。

2 个答案:

答案 0 :(得分:1)

您的按钮应如下所示:

<Button Content="Delete" 
        Command="{Binding Path=Delete}"
        CommandParameter="{Binding}/>

然后remove命令看起来像这样:

private function RemoveItem(object parameter)
    {
        var item = parameter as MyDataClass
        if(item != null)
            TheContainer.Remove(item);
    }

您不需要将列表传递给ItemTemplate中的UserControl,因为它根本不需要知道列表

编辑: 我读了几遍你的问题,看看你对此感到困惑,所以我会试着澄清一下。

ListView是否在Xaml中设置了自己的模板,或者您使用另一个UserControl,datacontext仍会传递给该项目。无论您如何决定模板项目,ItemTemplate都将具有ListView项目列表中单个项目的datacontext。

我认为你的困惑在于外面的控制被引入模板。可以把它想象成运行程序时你带来的控件中的Xaml被剪切并粘贴到ListView的DataTemplate中,然后它与那里的硬编码没什么不同。

答案 1 :(得分:0)

您无法像使用过的那样使用Element绑定到达DataTemplate之外。

相反,你需要使用像这样的亲戚源。

<local:MyItemView TheList="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ListBox}, Path=DataContext.List}" />