ComboBox ItemTemplate 在删除所选项目时触发 TargetException?
ComboBox ItemTemplate triggering TargetException when selected item is removed?
我有一个使用 MEF 和 MVVMLight 的 WPF 应用程序 (.NET 4.5)。有一个名为 "DeviceSupervisor" 的共享 MEF 导出,它包含自定义 class、DeviceConfiguration 的 ObservableCollection,它只不过是一些字符串属性。
在主应用程序中,您可以添加和删除设备 to/from 这个 collection。这些模块之一在 ComboBox 中显示设备列表以供选择。
显式条件:
- 通过主应用程序
将一些项目添加到collection
- Select 模块下拉列表中的一项
- 通过主应用程序从 collection 中删除恰好被选中的项目
将用户更改同步到 DeviceSupervisor 的代码:
foreach (DeviceComplete set in Devices)
{
set.Configuration.CommunicationDetails = set.Device.Value.CommunicationDetails;
if (DeviceSupervisor.AvailableDevices.Any(d => d.ID == set.Configuration.ID))
{
DeviceSupervisor.AvailableDevices
.Single(d => d.ID == set.Configuration.ID)
.CommunicationDetails = set.Configuration.CommunicationDetails;
}
else
{
DeviceSupervisor.AvailableDevices.Add(set.Configuration);
}
}
var missing = new HashSet<DeviceConfiguration>(DeviceSupervisor.AvailableDevices
.Except(Devices.Select(d => d.Configuration)));
foreach (DeviceConfiguration toRemove in missing)
{
// --- TargetException thrown here ---
DeviceSupervisor.AvailableDevices.Remove(toRemove);
}
模块上 XAML 中的 CollectionViewSource:
<CollectionViewSource x:Key="AvailableDevicesCvs"
Source="{Binding Path=AvailableDevices, Mode=OneWay}" Filter="AvailableDevicesCVS_Filter">
</CollectionViewSource>
组合框:
<ComboBox HorizontalAlignment="Left" Margin="10,41,0,0" VerticalAlignment="Top" Width="120"
ItemsSource="{Binding Source={StaticResource AvailableDevicesCvs}}"
SelectedItem="{Binding Path=SelectedDevice}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=CommunicationDetails}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
异常:
An unhandled exception of type 'System.Reflection.TargetException' occurred in mscorlib.dll
Additional information: Object does not match target type.
堆栈跟踪几乎是所有变灰的 WindowsBase 和 PresentationFramework 引用。 Intellitrace 仅显示我在上面评论的行中抛出的异常。
我的发现/其他笔记
请注意,如果 ComboBox 选择了另一个项目而不是删除的项目,则不会抛出此异常。在任何地方抛出显式 one-way 绑定都没有影响。在我可以在 CollectionChanged 或 Filter 事件中抛出的任何断点之前抛出异常。
经过大量的努力、重组和反复试验,我发现如果我简单地从组合框中删除 ItemTemplate,那么一切都会按预期工作 - 没有例外,并且 ComboBox 会调整选择以弥补缺失物品。
我很紧张,因为我陷入了一些狭隘的视野陷阱,看不到我犯的愚蠢错误 - 但更紧张的是其他原因。
此后我将问题追溯到 CommunicationDetails 属性。 class 的源文件库没有对 MVVMLight 的引用,作为快速获取 xyzChanged 的快捷方式(用于其他用途),我编写了 属性,如下所示:
旧
private string mCommunicationDetails;
public string CommunicationDetails
{
get
{
return mCommunicationDetails;
}
set
{
bool changed = (mCommunicationDetails != value);
mCommunicationDetails = value;
if (changed)
{
CommunicationDetailsChanged.Raise(this, EventArgs.Empty);
}
}
}
public event EventHandler CommunicationDetailsChanged;
将其替换为原版 {get;set;} 属性 有效。我已经用 MVVMLight 属性
替换了它
新建
private string mCommunicationDetails;
public string CommunicationDetails
{
get
{
return mCommunicationDetails;
}
set
{
if (Set(() => CommunicationDetails, ref mCommunicationDetails, value))
{
CommunicationDetailsChanged.Raise(this, EventArgs.Empty);
}
}
}
public event EventHandler CommunicationDetailsChanged;
而且有效。
如果有人愿意花时间查找或解释此错误的真正根源,我会接受它作为答案,但我现在接受它以关闭问题。
我有一个使用 MEF 和 MVVMLight 的 WPF 应用程序 (.NET 4.5)。有一个名为 "DeviceSupervisor" 的共享 MEF 导出,它包含自定义 class、DeviceConfiguration 的 ObservableCollection,它只不过是一些字符串属性。
在主应用程序中,您可以添加和删除设备 to/from 这个 collection。这些模块之一在 ComboBox 中显示设备列表以供选择。
显式条件:
- 通过主应用程序 将一些项目添加到collection
- Select 模块下拉列表中的一项
- 通过主应用程序从 collection 中删除恰好被选中的项目
将用户更改同步到 DeviceSupervisor 的代码:
foreach (DeviceComplete set in Devices)
{
set.Configuration.CommunicationDetails = set.Device.Value.CommunicationDetails;
if (DeviceSupervisor.AvailableDevices.Any(d => d.ID == set.Configuration.ID))
{
DeviceSupervisor.AvailableDevices
.Single(d => d.ID == set.Configuration.ID)
.CommunicationDetails = set.Configuration.CommunicationDetails;
}
else
{
DeviceSupervisor.AvailableDevices.Add(set.Configuration);
}
}
var missing = new HashSet<DeviceConfiguration>(DeviceSupervisor.AvailableDevices
.Except(Devices.Select(d => d.Configuration)));
foreach (DeviceConfiguration toRemove in missing)
{
// --- TargetException thrown here ---
DeviceSupervisor.AvailableDevices.Remove(toRemove);
}
模块上 XAML 中的 CollectionViewSource:
<CollectionViewSource x:Key="AvailableDevicesCvs"
Source="{Binding Path=AvailableDevices, Mode=OneWay}" Filter="AvailableDevicesCVS_Filter">
</CollectionViewSource>
组合框:
<ComboBox HorizontalAlignment="Left" Margin="10,41,0,0" VerticalAlignment="Top" Width="120"
ItemsSource="{Binding Source={StaticResource AvailableDevicesCvs}}"
SelectedItem="{Binding Path=SelectedDevice}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=CommunicationDetails}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
异常:
An unhandled exception of type 'System.Reflection.TargetException' occurred in mscorlib.dll Additional information: Object does not match target type.
堆栈跟踪几乎是所有变灰的 WindowsBase 和 PresentationFramework 引用。 Intellitrace 仅显示我在上面评论的行中抛出的异常。
我的发现/其他笔记
请注意,如果 ComboBox 选择了另一个项目而不是删除的项目,则不会抛出此异常。在任何地方抛出显式 one-way 绑定都没有影响。在我可以在 CollectionChanged 或 Filter 事件中抛出的任何断点之前抛出异常。
经过大量的努力、重组和反复试验,我发现如果我简单地从组合框中删除 ItemTemplate,那么一切都会按预期工作 - 没有例外,并且 ComboBox 会调整选择以弥补缺失物品。
我很紧张,因为我陷入了一些狭隘的视野陷阱,看不到我犯的愚蠢错误 - 但更紧张的是其他原因。
此后我将问题追溯到 CommunicationDetails 属性。 class 的源文件库没有对 MVVMLight 的引用,作为快速获取 xyzChanged 的快捷方式(用于其他用途),我编写了 属性,如下所示:
旧
private string mCommunicationDetails;
public string CommunicationDetails
{
get
{
return mCommunicationDetails;
}
set
{
bool changed = (mCommunicationDetails != value);
mCommunicationDetails = value;
if (changed)
{
CommunicationDetailsChanged.Raise(this, EventArgs.Empty);
}
}
}
public event EventHandler CommunicationDetailsChanged;
将其替换为原版 {get;set;} 属性 有效。我已经用 MVVMLight 属性
替换了它新建
private string mCommunicationDetails;
public string CommunicationDetails
{
get
{
return mCommunicationDetails;
}
set
{
if (Set(() => CommunicationDetails, ref mCommunicationDetails, value))
{
CommunicationDetailsChanged.Raise(this, EventArgs.Empty);
}
}
}
public event EventHandler CommunicationDetailsChanged;
而且有效。
如果有人愿意花时间查找或解释此错误的真正根源,我会接受它作为答案,但我现在接受它以关闭问题。