C# 从可观察集合中动态删除项-WPF

C# 从可观察集合中动态删除项-WPF,c#,wpf,xaml,listview,C#,Wpf,Xaml,Listview,我在wpf中有一个由sql查询填充的listview。我创建了一个名为“Carrier”的类,并这样定义它 public class Carrier { public Carrier(string rank, string id, string name, string add1, string add2, string add3, string add4) { _rank = rank + "."; _ca

我在wpf中有一个由sql查询填充的listview。我创建了一个名为“Carrier”的类,并这样定义它

public class Carrier
    {
        public Carrier(string rank, string id, string name, string add1, string add2, string add3, string add4)
        {
            _rank = rank + ".";
            _carrierId = id;
            _carrierName = name;
            _address1 = add1;
            _address2 = add2;
            _address3 = add3;
            _address4 = add4;
            OnRemoveClick = new DelegateCommand<string>(RemoveCarrierFromNode);
        }
}
公共级承运人
{
公共载体(字符串排名、字符串id、字符串名称、字符串地址1、字符串地址2、字符串地址3、字符串地址4)
{
_排名=排名+”;
_carrierId=id;
_carrierName=名称;
_地址1=地址1;
_地址2=地址2;
_地址3=地址3;
_地址4=地址4;
OnRemoveClick=新的DelegateCommand(RemoveCarrierFromNode);
}
}
为了节省空间,我省略了所有变量的声明

我的wpf如下所示:

每个“节点”具有不同数量的载波,并且根据所选节点,载波列表相应地改变。载波列表绑定到一个名为CarrierList的observeCollection

下面是我的Listview的XAML,它显示了动态标签和按钮是如何形成的

<ListView Margin="134,110,100,50" HorizontalAlignment="Center" Width="232" BorderBrush="LightGray" BorderThickness="1,1,1,1" Visibility="{Binding Path=ShowCarrierList, Converter={StaticResource BoolToVis}}" ItemsSource="{Binding CarrierList}" Grid.RowSpan="2" ScrollViewer.CanContentScroll="True">
            <ListView.ItemTemplate>
                <DataTemplate>
                        <DockPanel Margin="0,0,0,0" HorizontalAlignment ="Stretch">
                            <Grid HorizontalAlignment="Stretch">
                                <Grid.Resources>
                                    <Style TargetType="{x:Type Border}">
                                        <!-- All rows -->
                                        <Setter Property="BorderBrush" Value="Black" />
                                        <Setter Property="BorderThickness" Value="2" />
                                        <Setter Property="CornerRadius" Value="5" />
                                    </Style>
                                </Grid.Resources>
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition Width="165" />
                                    <ColumnDefinition Width="20" />
                                    <ColumnDefinition Width="20" />
                                    <ColumnDefinition Width="20" />
                                </Grid.ColumnDefinitions>
                            <TextBlock Text="{Binding Rank}"  />
                            <TextBlock Text="{Binding CarrierName}" Margin="13,0,0,0"/>


                            <Button  Width="20" Grid.Column="1" HorizontalAlignment="Right" ToolTip="Edit Carrier Details">
                                    <StackPanel>
                                        <Image Source="{StaticResource EditImg}"/>
                                    </StackPanel>
                                </Button>
                                <Button  Width="20" Grid.Column="2" HorizontalAlignment="Right" ToolTip="View All Nodes With This Carrier">
                                    <StackPanel>
                                        <Image Source="{StaticResource NetworkImg}"/>
                                    </StackPanel>
                                </Button>
                            <Button  Width="20" Grid.Column="3" HorizontalAlignment="Right" ToolTip="Remove Carrier From Node" Command="{Binding OnRemoveClick}" CommandParameter="{Binding CarrierName}">
                                    <StackPanel>
                                        <Image Source="{StaticResource ErrorImg}"/>
                                    </StackPanel>
                            </Button>
                            </Grid>
                        </DockPanel>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>


当我点击“X”按钮时,被触发的命令必须在载体对象内部。我尝试在视图模型中声明该命令,但它从未被触发,但当我将其放入Carrier类时,我能够触发Remove命令。但是,我不知道如何从item对象内部从集合中删除该项

如果我正确理解您的问题,您是否试图单击“X”按钮从列表中删除所选项目?如果是这样,我将使用
DelegateCommand
CommandParameter
如下

<ListView x:Name="carrierList">            
        <Button Command="{Binding ElementName=carrierList,Path=DataContext.OnRemoveClick}" CommandParameter="{Binding}">
            <StackPanel>
                <Image Source="{StaticResource ErrorImg}"/>
            </StackPanel>
        </Button>

    </ListView>

这是一种非常常见的模式,您只需进行一些更改即可使其正常工作。首先,我确实将
Remove
命令作为视图模型的一部分。如果您不这样做,正如您所注意到的,您可能需要每个
载体
项目都有一个对其集合的引用,这将非常不雅观,并且很容易导致内存泄漏

Remove
按钮绑定到视图模型的
Remove
命令时,需要指定视图模型的完整路径作为源,因为
ListViewItem
DataContext
载体
而不是视图模型。一种方法是为ListView指定一个显式名称(例如,
name=“x:\u ListView”
),然后按如下方式绑定:

Command="{Binding ElementName=_listView, Path=DataContext.OnRemoveClick}"
这将解决视图模型的命令未被激发的问题

第二,改变

CommandParameter="{Binding CarrierName}"

然后,
OnRemoveClick
命令处理程序的参数将是其按钮被单击的
Carrier
对象,现在只需说出
CarrierList.Remove(arg)

最后,您需要更改:

OnRemoveClick = new DelegateCommand<string>(RemoveCarrierFromNode);
OnRemoveClick=newdelegateCommand(RemoveCarrierFromNode);

OnRemoveClick=newdelegateCommand(RemoveCarrierFromNode);
因为您希望命令参数是载体对象,而不是其名称


希望这有帮助

当我这样设置它时,当我单击X时,什么也不会发生。我在视图模型中为我的RemoveCarrierFromNode函数设置了一个断点,它永远不会被击中。与其使用
string
字符串,不如将通过DeletegateCommand传递的类型设为一个
Carrier
啊,我错过了更改ListView名称的机会,我以为我是在把它绑定到原始的itemsource上……谢谢你的帮助。嘿,我们同时写了几乎相同的答案。伟大的头脑。。。
CommandParameter="{Binding}"
OnRemoveClick = new DelegateCommand<string>(RemoveCarrierFromNode);
OnRemoveClick = new DelegateCommand<Carrier>(RemoveCarrierFromNode);