我正在构建一个WPF应用程序,我想我会使用AutoMapper在viewmodels中复制对象。我遇到的问题是,AutoMapper似乎试图使用绑定控件作为源值,我不明白为什么。我是汽车制造商的新手,所以我想我遗漏了一些细节。
详细信息
UI有一个列表框和三个按钮(添加、编辑、删除)。如果列表框中未选择任何内容,则只有“添加”按钮处于活动状态。
如果在列表框中选择了一个项目,则所有按钮都处于活动状态。
如果单击“添加”按钮,将创建一个新的空对象,其属性绑定到UI中的文本框。
如果单击“编辑”按钮,将创建列表框中所选项目的副本,副本的属性将绑定到UI中的文本框。
所有这些都有效。如果我尝试使用AutoMapper制作副本,就会出现问题。
这是有问题的代码。我已经包括了工作原理(手动复制,逐个属性)和使用AutoMapper时失败的代码。
viewmodel中包含三个属性:
// 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时,它到达了失败的行,调试器显示此错误:
系统Windows。数据错误:17:无法从“”(类型“CarTypesViewModel”)获取“CarTypeDto”值(类型“CarType”)。BindingExpression:路径=CarTypeDto。描述DataItem='CarTypesViewModel'(HashCode=66939890);目标元素是“TextBox”(Name='DescriptionTextBox');目标属性为“Text”(类型为“String”)
让我困惑的是,我获得了对所选项目(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}" />
在应用程序的引导程序部分,我像这样初始化映射程序。。。
private void InitializeAutomapper()
{
var mapperConfig = new MapperConfiguration(cfg =>
{
cfg.CreateMap<CarType, CarType>();
});
_mapper = new Mapper(mapperConfig);
}
。。。然后根据需要将\u映射器注入viewmodels。我已经测试了映射器,它将正确映射对象。当我尝试在上面显示的CarTypeDto属性中进行映射时,就会出现这个问题。
==============================
编辑-有关解决方案的注释
我想为稍后可能阅读本文的人添加一条关于该解决方案的注释,尤其是对AutoMapper和属性绑定较新的人(如我自己)。
下面的答案让我意识到,我填充CarTypeDto属性的方法是不正确的。在最终解决方案中,我对该物业进行了如下改造:
public CarType CarTypeDto
{
get { return _carTypeDto; }
set { SetProperty(ref _carTypeDto, value); }
}
然后,在需要时,我将该值更新到其他地方的CarTypeDto属性。例如,单击Edit按钮时,我会检索所选值并将其映射到CarTypeDto。本文顶部显示的代码不是填充绑定属性值的合适方法。
虽然所有这些都与AutoMapper无关,但当我尝试使用AutoMapper时,它揭示了更大的问题。