为什么AutoMapper使用绑定属性作为源?

时间:2018-04-19 17:07:38

标签: c# wpf automapper

我正在构建一个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时,它会带来更大的问题。

1 个答案:

答案 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处绑定的对象。您不应该使用映射器创建新对象,而应该使用相同的对象并更新属性。