Items.Count = 0 in SelectionChanged 当有项目时
Items.Count = 0 in SelectionChanged when there are items
我想在单击按钮时显示一些自定义内容(使用数据模板):
<ContentControl x:Name="content" />
<Button Content="Test" Click="button_Click" />
按钮shows/hides这样的内容
VM _vm = new VM();
void button_Click(object sender, RoutedEventArgs e) =>
content.Content = content.Content == null ? _vm : null;
这是数据模板:
<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; }
}
问题:当卸载数据模板时,SelectionChanged
for ListBox
事件出现,但没有任何项目。
我不想参加这个活动。我不想在选择某些内容并卸载数据模板后看到 "Items: 0"。
问题:发生了什么,我该如何防止这种情况发生?
注意:这是非常简短和简化的 MCVE,即不是所有的东西都很漂亮,尽管有关键点:内部带有 ListBox
的数据模板,它使用 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.
}
}
我认为 listBox_SelectionChanged
当您卸载列表时会触发此事件,因为部分实际上已更改,检查那里的项目计数,如果是 0,则将标题设置为默认值。
void listBox_SelectionChanged(object sender, SelectionChangedEventArgs e) =>
Title = (((ListBox)sender).Items.Count > 0)? "Items: " + ((ListBox)sender).Items.Count: "Your title";
这完全按照设计工作。您通过单击列表框中的项目进行了选择。卸载模板后,ItemsSource
绑定断开,项目源变为空。此时,当前选择不再有效(项目源中不存在该项目),因此选择被清除。这是选择的变化:选择从有到无。 预计将在这些情况下引发该事件。
很少需要订阅SelectionChanged
。通常最好将 SelectedItem
绑定到视图模型上的 属性。只要选择发生变化,属性 就会更新。您可以响应 属性 变化而不是响应 SelectionChanged
事件。
这种方法很好地避免了您遇到的问题。卸载模板后,SelectedItem
绑定将断开连接,因此您的视图模型将不再更新。因此,清除选择后您将看不到最后的更改。
多选的备选方案
如果您的ListBox
支持多选,您可以继续订阅SelectionChanged
。但是,不要查询 listBoxItems
;相反,扫描 _vm.Items
并查看哪些项目 IsSelected
设置为 true
。这应该会告诉您实际的选择,并且结果应该不受正在卸载的模板的影响。
您还可以通过检查处理程序中的 (sender as ListBox)?.ItemsSource
是否为 null 来确定模板已卸载。但是,这应该不是必需的。
我想在单击按钮时显示一些自定义内容(使用数据模板):
<ContentControl x:Name="content" />
<Button Content="Test" Click="button_Click" />
按钮shows/hides这样的内容
VM _vm = new VM();
void button_Click(object sender, RoutedEventArgs e) =>
content.Content = content.Content == null ? _vm : null;
这是数据模板:
<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; }
}
问题:当卸载数据模板时,SelectionChanged
for ListBox
事件出现,但没有任何项目。
我不想参加这个活动。我不想在选择某些内容并卸载数据模板后看到 "Items: 0"。
问题:发生了什么,我该如何防止这种情况发生?
注意:这是非常简短和简化的 MCVE,即不是所有的东西都很漂亮,尽管有关键点:内部带有 ListBox
的数据模板,它使用 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.
}
}
我认为 listBox_SelectionChanged
当您卸载列表时会触发此事件,因为部分实际上已更改,检查那里的项目计数,如果是 0,则将标题设置为默认值。
void listBox_SelectionChanged(object sender, SelectionChangedEventArgs e) =>
Title = (((ListBox)sender).Items.Count > 0)? "Items: " + ((ListBox)sender).Items.Count: "Your title";
这完全按照设计工作。您通过单击列表框中的项目进行了选择。卸载模板后,ItemsSource
绑定断开,项目源变为空。此时,当前选择不再有效(项目源中不存在该项目),因此选择被清除。这是选择的变化:选择从有到无。 预计将在这些情况下引发该事件。
很少需要订阅SelectionChanged
。通常最好将 SelectedItem
绑定到视图模型上的 属性。只要选择发生变化,属性 就会更新。您可以响应 属性 变化而不是响应 SelectionChanged
事件。
这种方法很好地避免了您遇到的问题。卸载模板后,SelectedItem
绑定将断开连接,因此您的视图模型将不再更新。因此,清除选择后您将看不到最后的更改。
多选的备选方案
如果您的ListBox
支持多选,您可以继续订阅SelectionChanged
。但是,不要查询 listBoxItems
;相反,扫描 _vm.Items
并查看哪些项目 IsSelected
设置为 true
。这应该会告诉您实际的选择,并且结果应该不受正在卸载的模板的影响。
您还可以通过检查处理程序中的 (sender as ListBox)?.ItemsSource
是否为 null 来确定模板已卸载。但是,这应该不是必需的。