WPF中ListView MVVM模式下的删除按钮

7

我在listview中有一个按钮来删除选定的项目。当我点击按钮时,RemoveSubjectCommand没有触发。如果我把按钮放在listview外面,它就可以正常工作。希望这只是因为嵌套项目的原因。我该如何解决这个问题?

<ListView HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
        HorizontalContentAlignment="Stretch" Grid.ColumnSpan="3" Grid.Row="2"
        ItemsSource="{Binding AssignedSubjects}">
    <ListView.ItemContainerStyle>
        <Style TargetType="ListViewItem">
            <Setter Property="HorizontalContentAlignment" Value="Center" />
        </Style>
    </ListView.ItemContainerStyle>
    <ListView.View>
        <GridView>
            <GridViewColumn Width="140" Header="Subjects" DisplayMemberBinding="{Binding Name}" />
            <GridViewColumn Width="auto">
                <GridViewColumn.CellTemplate>
                    <DataTemplate>
                        <Button Content="X" Command="{Binding RemoveSubjectCommand}"  />
                    </DataTemplate>
                </GridViewColumn.CellTemplate>
            </GridViewColumn>
        </GridView>
    </ListView.View>
</ListView>

视图模型,
private ICommand removeSubjectCommand;
**
public ICommand RemoveSubjectCommand
{
    get { return removeSubjectCommand ?? (removeSubjectCommand = new RelayCommand(param => this.RemoveSubject(), null)); }
}
**
private void RemoveSubject()
{ ***
}

如果我放置以下代码,它将正常工作。
<ListView.InputBindings>
    <KeyBinding Key="Delete" Command="{Binding RemoveSubjectCommand}" />
</ListView.InputBindings>

2
你好。你如何在没有向命令发送参数的情况下删除该行? - Javidan
@Javidan,你可以使用 CommandParameter 按钮。例如,使用 CommandParameter="{Binding}" 将其绑定到 ListViewItem 的 DataContext(即 item 本身)。然后,在你的 ViewModel 中,你可以定义 DelegateCommand 来接受参数,例如 public DelegateCommand<object> RemoveSubjectCommand{ get; }(注意我添加的 <object>,它也可以是任何其他类型,只要一切保持一致即可)。 - Stefan
3个回答

14

那是因为按钮的 DataContext 是 ListBoxItem 的 DataContext。所以您需要转到父 ListView 的 DataContext。

一种方法是给 ListView 命名,并使用元素名称进行绑定。

<ListView Name="lv" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
        HorizontalContentAlignment="Stretch" Grid.ColumnSpan="3" Grid.Row="2"
        ItemsSource="{Binding AssignedSubjects}">
    <ListView.ItemContainerStyle>
        <Style TargetType="ListViewItem">
            <Setter Property="HorizontalContentAlignment" Value="Center" />
        </Style>
    </ListView.ItemContainerStyle>
    <ListView.View>
        <GridView>
            <GridViewColumn Width="140" Header="Subjects" DisplayMemberBinding="{Binding Name}" />
            <GridViewColumn Width="auto">
                <GridViewColumn.CellTemplate>
                    <DataTemplate>
                        <Button Content="X" Command="{Binding ElementName=lv,Path=DataContext.RemoveSubjectCommand}"  />
                    </DataTemplate>
                </GridViewColumn.CellTemplate>
            </GridViewColumn>
        </GridView>
    </ListView.View>
</ListView>

:段落标记。

我相信你可以通过使用绑定和findancestor来跳过命名部分。 - Joe
正确的,findancestor是另一种实现这个功能的方式,但由于它已经在答案中存在,我选择了这个。 - Arsen Mkrtchyan
我不明白,如果没有通过按钮发送命令参数,我们怎么知道从集合中删除哪个项目?而且ListView中的SelectedItem属性也没有绑定到ViewModel... - Adolfo Perez
好的,我假设项目视图模型具有RemoveSubjectCommand命令,并且它知道如何从列表中删除自己。 - Arsen Mkrtchyan

8
你需要使用 FindAncestor 将 Command 绑定到 ViewModel。否则,它将尝试使用 ListViewItem 的数据上下文绑定到 RemoveSubjectCommand,而不是ViewModel的。

请尝试以下操作:

<Button Content="X" Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=ListView}, Path=DataContext.RemoveSubjectCommand}"  />

TemplateParent 不会是 ListView,而是 ListViewitem,对吧? - Arsen Mkrtchyan
1
在你的回答中,需要将 RemoveSubjectCommand 替换为 DataContext.RemoveSubjectCommand。谢谢并点赞。 - Chamika Sandamal

2

如果我把按钮放在列表视图外面,它可以正常工作。

这是因为RemoveSubjectCommand属性是在ListView的数据上下文中定义的,而不是在item的数据上下文中定义的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接