C# Items.Count=0,当存在项时SelectionChanged

C# Items.Count=0,当存在项时SelectionChanged,c#,wpf,mvvm,listbox,datatemplate,C#,Wpf,Mvvm,Listbox,Datatemplate,我想在单击按钮时显示一些自定义内容(使用datatemplate): <ContentControl x:Name="content" /> <Button Content="Test" Click="button_Click" /> 以下是数据模板: <DataTemplate DataType="{x:Type local:VM}"> <ListBox ItemsSource="{Binding Items}" SelectionChang

我想在单击按钮时显示一些自定义内容(使用datatemplate):

<ContentControl x:Name="content" />
<Button Content="Test" Click="button_Click" />
以下是数据模板:

<DataTemplate DataType="{x:Type local:VM}">
    <ListBox ItemsSource="{Binding Items}" SelectionChanged="listBox_SelectionChanged">
        <ListBox.ItemContainerStyle>
            <Style TargetType="ListBoxItem">
                <Setter Property="IsSelected" Value="{Binding IsSelected}" />
            </Style>
        </ListBox.ItemContainerStyle>
    </ListBox>
</DataTemplate>
视图模型:

public class VM
{
    public List<Item> Items { get; } = new List<Item> { new Item(), new Item(), new Item() };
}
public class Item
{
    public bool IsSelected { get; set; }
}
公共类虚拟机
{
公共列表项{get;}=新列表{new Item(),new Item(),new Item()};
}
公共类项目
{
公共布尔值被选为{get;set;}
}
问题:卸载datatemplate后,
列表框的
选择已更改
事件将不带任何项目出现

我不想要这件事。在选择某些内容并卸载datatemplate后,我不希望看到“Items:0”

问题:发生了什么,我如何防止这种情况发生


注意:这是一个非常简短和简化的MCVE,也就是说,虽然有一些关键点:内部带有
ListBox
的datatemplate,它使用
IsSelected
绑定,我需要在卸载时摆脱
SelectionChanged
事件

调用堆栈:


我认为这是因为您总是覆盖内容:

VM _vm = new VM();
void button_Click(object sender, RoutedEventArgs e) =>
     content.Content = content.Content == null ? _vm : null;
将其更改为此,使列表仅分配一次,因此仅分配一次

void button_Click(object sender, RoutedEventArgs e)
{
    if (content.Content == null )
    {
        content.Content = _vm; 

        // I also recommend you add the event handler for the ListBox here so it's not fired until you have content.
    }
}

我认为这是因为您总是覆盖内容:

VM _vm = new VM();
void button_Click(object sender, RoutedEventArgs e) =>
     content.Content = content.Content == null ? _vm : null;
将其更改为此,使列表仅分配一次,因此仅分配一次

void button_Click(object sender, RoutedEventArgs e)
{
    if (content.Content == null )
    {
        content.Content = _vm; 

        // I also recommend you add the event handler for the ListBox here so it's not fired until you have content.
    }
}

我认为
listBox\u SelectionChanged
当您卸载列表时,会触发此事件,因为节实际上已更改,请检查其中的项目计数,如果为0,则将标题设置为默认值

void listBox\u SelectionChanged(对象发送方,SelectionChangedEventArgs e)=>
Title=((列表框)发件人).Items.Count>0)?“项目:”+((列表框)发件人).Items.Count:“您的标题”;

我认为
listBox\u SelectionChanged
当您卸载列表时,会触发此事件,因为节实际上已更改,请检查其中的项目计数,如果为0,则将标题设置为默认值

void listBox\u SelectionChanged(对象发送方,SelectionChangedEventArgs e)=>
Title=((列表框)发件人).Items.Count>0)?“项目:”+((列表框)发件人).Items.Count:“您的标题”;

这完全符合设计要求。您通过单击列表框中的项目进行了选择。卸载模板时,
itemsource
绑定断开连接,项目源变为空。此时,当前选择不再有效(项目源中不存在该项目),因此将清除该选择。这是一个选择变化:选择从某物变为无。在这种情况下,预计将提出该活动

很少需要订阅
SelectionChanged
。通常最好将
SelectedItem
绑定到视图模型上的属性。每当选择更改时,该属性都将更新。您可以响应该属性的更改,而不是响应
SelectionChanged
事件

这种方法很好地避免了您看到的问题。卸载模板后,
SelectedItem
绑定将断开,因此视图模型将不再更新。因此,清除选择后,您将看不到最终更改


多种选择的替代解决方案 如果您的
列表框
支持多项选择,您可以继续订阅
SelectionChanged
。但是,不要查询
listBoxItems
;相反,请扫描
\u vm.Items
,查看哪些项的
IsSelected
设置为
true
。这将告诉您实际的选择,并且结果不应受到卸载模板的影响


您还可以通过检查处理程序中的
(发件人作为列表框)?.ItemsSource
是否为空来确定模板是否已卸载。但是,这是不必要的。

这完全按照设计工作。您通过单击列表框中的项目进行了选择。卸载模板时,
itemsource
绑定断开连接,项目源变为空。此时,当前选择不再有效(项目源中不存在该项目),因此将清除该选择。这是一个选择变化:选择从某物变为无。在这种情况下,预计将提出该活动

很少需要订阅
SelectionChanged
。通常最好将
SelectedItem
绑定到视图模型上的属性。每当选择更改时,该属性都将更新。您可以响应该属性的更改,而不是响应
SelectionChanged
事件

这种方法很好地避免了您看到的问题。卸载模板后,
SelectedItem
绑定将断开,因此视图模型将不再更新。因此,清除选择后,您将看不到最终更改


多种选择的替代解决方案 如果您的
列表框
支持多项选择,您可以继续订阅
SelectionChanged
。但是,不要查询
listBoxItems
;相反,请扫描
\u vm.Items
,查看哪些项的
IsSelected
设置为
true
。这将告诉您实际的选择,并且结果不应受到卸载模板的影响


您还可以通过检查处理程序中的
(发件人作为列表框)?.ItemsSource
是否为空来确定模板是否已卸载。但是,这是不必要的。

您是否有一个事件正在清除项目…另一个事件正在添加列表…并且这可能发生在这两个事件之间?
listBox\u SelectionChanged
当您卸载列表时,会触发此事件,因为实际更改了选择,请检查其中的项目计数,如果它为0,则设置为