代码之家  ›  专栏  ›  技术社区  ›  DMK

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

  •  0
  • DMK  · 技术社区  · 6 年前

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

    1 回复  |  直到 6 年前
        1
  •  0
  •   user1672994    6 年前

    您提到的错误是绑定错误,而不是Automapper异常消息。

    系统Windows。数据错误:17:无法从“”(类型“CarTypesViewModel”)获取“CarTypeDto”值(类型“CarType”)。BindingExpression:路径=CarTypeDto。描述DataItem='CarTypesViewModel'(HashCode=66939890);目标元素是“TextBox”(Name='DescriptionTextBox');目标属性为“Text”(类型为“String”)

    现在关于映射不起作用——在使用之前 Automapper ,应创建地图,以便 AutoMapper 能够理解如何将一个对象/类型映射到另一个对象/类型。在您的场景中,由于您需要从相同的类型键入,因此您应该创建一个类似

    _mapper.CreateMap<MyType, MyType>(); 
    

    这个 CreateMap 应该打电话进来 自动制表符 配置文件初始化

    绑定错误更新:

    尝试创建的新对象时出现绑定错误 CarType 每次在Get property中如此 CarTypeDto 属性未指向最初在XAML处绑定的对象。您应该处理同一对象并更新属性,而不是使用映射器创建新对象。