在 UWP 中,在列表视图数据模板中使用组合框时,selectedItem 丢失
In UWP, when using a combobox inside a listview datatemplate, selectedItem is lost
已经问了几个类似的问题,但我找不到任何看起来与我遇到的问题完全相同的问题。
我在 DataTemplate
中有一个 ComboBox
用于 ListView
。 ComboBox
与 ItemsSource
以及 SelectedItem
具有正确的绑定。我使用的模式与我在整个应用程序中使用的模式相同,没有任何问题。
无论出于何种原因,所选项目在途中某处被清空。我在所选项目中放置了断点,我可以看到它在列表构造期间被正确设置。然后,在呈现控件时,所选项目再次设置为 null
(至少它是这样显示的)。当我在它被设置为 null
时查看调用堆栈时,堆栈仅显示我所在的行 [External Code]
.
作为参考,当前代码如下所示:
<ListView ItemsSource="{x:Bind Vm.ListVms, Mode=OneWay}"
SelectedItem="{x:Bind Vm.SelectedListVm, Mode=TwoWay, Converter={StaticResource GenericConverter}}">
<ListView.ItemTemplate>
<DataTemplate x:DataType="ListItemVm">
<StackPanel Orientation="Horizontal">
<ComboBox
ItemsSource="{x:Bind ComboBoxTypes, Mode=OneWay}"
SelectedItem="{x:Bind SelectedComboBoxType, Mode=TwoWay, Converter={StaticResource GenericConverter}}"
DisplayMemberPath="Name"/>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
ComboBoxTypes
是一个 ObservableCollection
。
SelectedComboBoxType
是通过引用 RaceTypes
.
中的一行来设置的
同样,正如我上面提到的,这种模式似乎在应用程序的其他任何地方都有效,但在 ListView
.
中却无效
这是我用来填充列表项和组合框的代码示例。这不是实际代码,因为我无法提供实际代码。尽管它说明了正在采取的步骤,但它已经足够接近了。
vm.ListVms.Clear();
foreach (var unit in source.ListItems)
{
var listVm = new ListVm();
listVm.ComboBoxTypes.Add();
listVm.ComboBoxTypes.Add();
listVm.ComboBoxTypes.Add();
listVm.ComboBoxTypes.Add();
listVm.SelectedComboBoxType = listVm.ComboBoxTypes.FirstOrDefault(r => r.Id == (int) unit.ComboBoxType);
vm.ListVms.Add(listVm);
}
当您颠倒 select code-behind 中某项的顺序时,通常会发生这种情况。考虑以下两个选项:
选项 1
SelectedComboBoxType = items[0];
ComboBoxTypes = items;
选项 2
ComboBoxTypes = items;
SelectedComboBoxType = items[0];
在选项 1 中,您首先设置 selected 项目,它会导致更改通知,该通知会立即由控件处理。然而,该控件尚未绑定到 items
,因此不会将 SelectedItem
设置为您的 selection,但相反会导致更新回 SelectedComboBoxType
之前的 selected 值。
基本上这意味着您总是可以 select 只有 在 您想要 select 的值已经绑定到控件之后。 选项 2 应该可以解决您的问题。
我从 Microsoft Developer Network 收到了一些可行的答案,所以我想我会在这里与 运行 遇到同样问题的任何人分享它们。
选项 1
如果值为 null,则对 setter 进行测试以绕过更新支持字段。
这对我来说是一个 hack,但它工作得很好。
public ComboboxItemVm SelectedComboBoxType
{
get { return selectedType; }
set
{
if (value == null)
{
Debug.WriteLine("null!");
return;
}
if (value != selectedType)
{
selectedType = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("SelectedComboBoxType"));
}
}
}
选项 2
将 SelectedItem 上的绑定从 x:Bind 更改为 Binding.
<ComboBox
ItemsSource="{x:Bind ComboBoxTypes, Mode=OneWay}"
SelectedItem="{Binding SelectedComboBoxType, Mode=TwoWay, Converter={StaticResource GenericConverter}}"
DisplayMemberPath="Name"/>
令人失望的是,解决方案是使用旧的编码风格,但它也解决了这个问题,而无需在代码中添加额外的 null-test-bypass 选项。
已经问了几个类似的问题,但我找不到任何看起来与我遇到的问题完全相同的问题。
我在 DataTemplate
中有一个 ComboBox
用于 ListView
。 ComboBox
与 ItemsSource
以及 SelectedItem
具有正确的绑定。我使用的模式与我在整个应用程序中使用的模式相同,没有任何问题。
无论出于何种原因,所选项目在途中某处被清空。我在所选项目中放置了断点,我可以看到它在列表构造期间被正确设置。然后,在呈现控件时,所选项目再次设置为 null
(至少它是这样显示的)。当我在它被设置为 null
时查看调用堆栈时,堆栈仅显示我所在的行 [External Code]
.
作为参考,当前代码如下所示:
<ListView ItemsSource="{x:Bind Vm.ListVms, Mode=OneWay}"
SelectedItem="{x:Bind Vm.SelectedListVm, Mode=TwoWay, Converter={StaticResource GenericConverter}}">
<ListView.ItemTemplate>
<DataTemplate x:DataType="ListItemVm">
<StackPanel Orientation="Horizontal">
<ComboBox
ItemsSource="{x:Bind ComboBoxTypes, Mode=OneWay}"
SelectedItem="{x:Bind SelectedComboBoxType, Mode=TwoWay, Converter={StaticResource GenericConverter}}"
DisplayMemberPath="Name"/>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
ComboBoxTypes
是一个 ObservableCollection
。
SelectedComboBoxType
是通过引用 RaceTypes
.
同样,正如我上面提到的,这种模式似乎在应用程序的其他任何地方都有效,但在 ListView
.
这是我用来填充列表项和组合框的代码示例。这不是实际代码,因为我无法提供实际代码。尽管它说明了正在采取的步骤,但它已经足够接近了。
vm.ListVms.Clear();
foreach (var unit in source.ListItems)
{
var listVm = new ListVm();
listVm.ComboBoxTypes.Add();
listVm.ComboBoxTypes.Add();
listVm.ComboBoxTypes.Add();
listVm.ComboBoxTypes.Add();
listVm.SelectedComboBoxType = listVm.ComboBoxTypes.FirstOrDefault(r => r.Id == (int) unit.ComboBoxType);
vm.ListVms.Add(listVm);
}
当您颠倒 select code-behind 中某项的顺序时,通常会发生这种情况。考虑以下两个选项:
选项 1
SelectedComboBoxType = items[0];
ComboBoxTypes = items;
选项 2
ComboBoxTypes = items;
SelectedComboBoxType = items[0];
在选项 1 中,您首先设置 selected 项目,它会导致更改通知,该通知会立即由控件处理。然而,该控件尚未绑定到 items
,因此不会将 SelectedItem
设置为您的 selection,但相反会导致更新回 SelectedComboBoxType
之前的 selected 值。
基本上这意味着您总是可以 select 只有 在 您想要 select 的值已经绑定到控件之后。 选项 2 应该可以解决您的问题。
我从 Microsoft Developer Network 收到了一些可行的答案,所以我想我会在这里与 运行 遇到同样问题的任何人分享它们。
选项 1 如果值为 null,则对 setter 进行测试以绕过更新支持字段。
这对我来说是一个 hack,但它工作得很好。
public ComboboxItemVm SelectedComboBoxType
{
get { return selectedType; }
set
{
if (value == null)
{
Debug.WriteLine("null!");
return;
}
if (value != selectedType)
{
selectedType = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("SelectedComboBoxType"));
}
}
}
选项 2 将 SelectedItem 上的绑定从 x:Bind 更改为 Binding.
<ComboBox
ItemsSource="{x:Bind ComboBoxTypes, Mode=OneWay}"
SelectedItem="{Binding SelectedComboBoxType, Mode=TwoWay, Converter={StaticResource GenericConverter}}"
DisplayMemberPath="Name"/>
令人失望的是,解决方案是使用旧的编码风格,但它也解决了这个问题,而无需在代码中添加额外的 null-test-bypass 选项。