当有项目时,SelectionChanged中的Items.Count = 0

时间:2018-01-23 15:52:58

标签: c# wpf mvvm listbox datatemplate

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

<ContentControl x:Name="content" />
<Button Content="Test" Click="button_Click" />

按钮显示/隐藏此内容

VM _vm = new VM();
void button_Click(object sender, RoutedEventArgs e) =>
     content.Content = content.Content == null ? _vm : null;

这是datatemplate:

<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>

事件处理程序:

void listBox_SelectionChanged(object sender, SelectionChangedEventArgs e) =>
    Title = "Items: " + ((ListBox)sender).Items.Count;

视图模型:

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; }
}

问题:卸载datatemplate时,SelectionChanged事件的ListBox上升,没有任何项目。

我不想要这个活动。我不想看到&#34;项目:0&#34;选择一些东西并卸载datatemplate后。

问题:发生了什么以及如何防止这种情况发生?

注意:这是非常简短和简化的MCVE,即不是一切都很漂亮,尽管有一些关键点:datatemplate里面有ListBox,它使用IsSelected绑定,我需要摆脱它卸货时发生SelectionChanged事件。

调用堆栈:

3 个答案:

答案 0 :(得分:2)

这与设计完全一致。您通过单击列表框中的项目进行选择。卸载模板后,ItemsSource绑定将断开连接,项目源将变为空。此时,当前选择不再有效(项目源中不存在该项目),因此清除选择。这是一个选择变化:选择从什么变为零。在这种情况下,该事件是预期

很少需要订阅SelectionChanged。将SelectedItem绑定到视图模型上的属性通常会更好。只要选择发生变化,该属性就会更新。您可以回复该属性更改,而不是回复SelectionChanged事件。

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

多选的替代解决方案

如果您的ListBox支持多项选择,则可以继续订阅SelectionChanged。但是,不要查询listBoxItems;相反,浏览_vm.Items并查看IsSelected设置为true的项目。这应该告诉你实际的选择,并且结果不应该被卸载的模板影响。

您还可以通过检查处理程序中(sender as ListBox)?.ItemsSource是否为null来确定是否已卸载模板。但是,这不是必要的。

答案 1 :(得分:0)

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

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.
    }
}

答案 2 :(得分:0)

我认为listBox_SelectionChanged当您卸载列表时会触发此事件,因为部分实际已更改,检查项目计数,如果为0,则将标题设置为默认值。

void listBox_SelectionChanged(object sender, SelectionChangedEventArgs e) =>
Title = (((ListBox)sender).Items.Count > 0)? "Items: " + ((ListBox)sender).Items.Count: "Your title";