我正在构建一个WPF应用程序,并认为我将使用AutoMapper在我的视图模型中制作对象的副本。我遇到的问题是看起来AutoMapper试图使用绑定控件作为源值,我不明白为什么。我是AutoMapper的新手,所以我想我错过了一些细节。
详情
UI有一个列表框和三个按钮(添加,编辑,删除)。如果列表框中未选择任何内容,则只有“添加”按钮处于活动状态。
如果在列表框中选择了某个项目,则所有按钮都处于活动状态。
如果单击“添加”按钮,则会创建一个新的空对象,其属性绑定到UI中的文本框。
如果单击“编辑”按钮,则会在列表框中选择所选项目的副本,并且副本的属性将绑定到UI中的文本框。
所有这一切都有效。如果我尝试使用AutoMapper来制作副本,则会出现此问题。
以下是相关代码。我已经包含了什么有效(手动复制,属性属性)和使用AutoMapper时失败的代码。
视图模型中有三个属性:
// Bound to the list box's ItemsSource property
public ObservableCollection<CarType> CarTypes
{
get { return _carTypes; }
set { SetProperty(ref _carTypes, value); }
}
// Bound to the list box's SelectedIndex property
public int SelectedIndex
{
get { return _selectedIndex; }
set
{
SetProperty(ref _selectedIndex, value);
}
}
// Properties of CarTypeDto are bound to text boxes in the Edit UI
public CarType CarTypeDto
{
get
{
// When the value is retrieved, a copy of the selected item
// is made and the copy is returned.
if (SelectedIndex != -1)
{
// What works==========
// CarType newDto = new CarType();
// CarType src = CarTypes[SelectedIndex];
// newDto.Id = src.Id;
// newDto.Name = src.Name;
// newDto.Description = src.Description;
// _carTypeDto = newDto;
// What does NOT work============
CarType src = CarTypes[SelectedIndex];
CarType newDto = _mapper.Map<CarType>(src); <=== fails here
_carTypeDto = newDto;
// Incorrect Solution #1 ======================
// Changed the above two lines to this solves the problem:
_mapper.Map<CarType, CarType>(src,_carTypeDto);
}
return _carTypeDto;
}
set
{
SetProperty(ref _carTypeDto, value);
}
}
当我尝试使用AutoMapper时,它会进入失败的行并且调试器显示此错误:
System.Windows.Data错误:17:无法获取CarTypeDto&#39;价值(类型&#39; CarType&#39;)来自&#39;&#39; (键入&#39; CarTypesViewModel&#39;)。 BindingExpression:路径= CarTypeDto.Description;的DataItem =&#39; CarTypesViewModel&#39; (的HashCode = 66939890);目标元素是&#39; TextBox&#39; (名称=&#39; DescriptionTextBox&#39);目标属性是&#39; Text&#39; (键入&#39; String&#39;)
让我感到困惑的是,我获得了对所选项目(src)的引用,并尝试将其映射到CarType的新实例(newDto)。这两个项目(src或newDto)都不是编辑UI中与DescriptionTextBox绑定的一部分。当我使用AutoMaper时,为什么绑定会成为一个问题?
注释代码(手动复制属性)可以正常工作。
如果它有帮助,这里是有问题的绑定:
<ListBox x:Name="ContentView"
DockPanel.Dock="Top"
ItemsSource="{Binding CarTypes}"
Background="{StaticResource ControlBackgroundBrush}"
Foreground="{StaticResource ControlForegroundBrush}"
BorderBrush="{StaticResource ControlForegroundBrush}"
SelectedIndex ="{Binding SelectedIndex}" >
<TextBox Grid.Row="1"
Grid.Column="0"
Name="NameTextBox"
Margin="5"
Width="100"
MaxLength="10"
Text="{Binding CarTypeDto.Name, Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged}" />
<TextBox Grid.Row="1"
Grid.Column="1"
Grid.ColumnSpan="2"
Name="DescriptionTextBox"
Margin="5"
Width="300"
MaxLength="30"
Text="{Binding CarTypeDto.Description,
Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
在应用程序的bootstrap部分,我像这样初始化映射器......
private void InitializeAutomapper()
{
var mapperConfig = new MapperConfiguration(cfg =>
{
cfg.CreateMap<CarType, CarType>();
});
_mapper = new Mapper(mapperConfig);
}
...然后根据需要将_mapper注入viewmodels。我测试了映射器,它将正确映射对象。当我尝试在上面显示的CarTypeDto属性中执行映射时,会出现此问题。
==============================
编辑 - 关于解决方案的说明
我想为后来可能会阅读此内容的人们添加一个关于解决方案的说明 - 特别是那些更新的AutoMapper和属性绑定(比如我自己)。
下面的答案让我意识到我填充CarTypeDto属性的方法不正确。在最终解决方案中,我将属性改为:
public CarType CarTypeDto
{
get { return _carTypeDto; }
set { SetProperty(ref _carTypeDto, value); }
}
然后,我在需要时将值更新到其他地方的CarTypeDto属性。例如,当单击“编辑”按钮时,我会检索所选值并将其映射到CarTypeDto。此帖子顶部显示的代码不是填充绑定属性值的适当方法。
虽然所有这些都与AutoMapper无关,但当我尝试使用AutoMapper时,它会带来更大的问题。
答案 0 :(得分:0)
您提到的错误是绑定错误,而不是Automapper异常消息。
System.Windows.Data错误:17:无法获取CarTypeDto&#39;价值(类型&#39; CarType&#39;)来自&#39;&#39; (键入&#39; CarTypesViewModel&#39;)。 BindingExpression:路径= CarTypeDto.Description;的DataItem =&#39; CarTypesViewModel&#39; (的HashCode = 66939890);目标元素是&#39; TextBox&#39; (名称=&#39; DescriptionTextBox&#39);目标属性是&#39; Text&#39; (键入&#39; String&#39;)
现在关于映射不起作用----在使用Automapper
之前,应该创建映射,以便AutoMapper
可以理解如何将一个对象/类型映射到另一个。在您的方案中,由于您需要从相同类型键入,因此您应该创建一个类似
_mapper.CreateMap<MyType, MyType>();
CreateMap
应在Automapper
个人资料初始化中调用。
更新绑定错误:
当您尝试在Get属性中每次创建CarType
的新对象时出现绑定错误,因此CarTypeDto
属性未指向最初在XAML处绑定的对象。您不应该使用映射器创建新对象,而应该使用相同的对象并更新属性。