简体   繁体   English

在 MVVM + WPF 中的 View 中使用 ModelView

[英]using ModelView in View in MVVM + WPF

I have a model called Entity which is created by EF database first :我有一个名为Entity的模型,它首先由 EF 数据库创建:

public partial class Entity
    {
        public Entity()
        {
            this.Properties = new HashSet<Property>();
        }

        public long Id { get; set; }
        public string Name { get; set; }
        public int X { get; set; }
        public int Y { get; set; }

        public virtual ICollection<Property> Properties { get; set; }
    }

I want this model Implement INotifyPropertyChanged for notifying when X and Y are changing so I created another model like CEntity我想要这个模型实现 INotifyPropertyChanged 以通知 X 和 Y 何时发生变化,所以我创建了另一个模型,如CEntity

public class CEntity : Entity, INotifyPropertyChanged
    {
        private int _x;
        private int _y;

        public CEntity()
        {
        }

        public CEntity(long id, string name, int x, int y)
        {
            Id = id;
            Name = name;
            _x = x;
            _y = y;
        }

        public int X
        {
            get => _x;
            set
            {
                _x = value;
                OnPropertyChanged();
            }

        }
        public int Y
        {
            get => _y;
            set
            {
                _y = value;
                OnPropertyChanged();
            }

        }

        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }

This is MainWindow.xaml这是MainWindow.xaml

<Window x:Class="DomainModelEditor.UI.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d"
        xmlns:local="clr-namespace:Example.UI"
        xmlns:example="clr-namespace:Example"
        xmlns:models="clr-namespace:Example.Models"
        xmlns:vm="clr-namespace:Example.UI.ViewModels"
        Title="Modeler" Height="350" Width="525">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="26"/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <Border Grid.Row="0" BorderThickness="0,0,0,1" BorderBrush="Black">
            <StackPanel Orientation="Horizontal" Height="26">
                <Label Content="Domain Model Editor" HorizontalAlignment="Left" VerticalAlignment="Top"/>
                <Button Width="80" Content="Add Entity" Margin="0,3,0,3" Click="AddEntity_Click"/>
            </StackPanel>
        </Border>
        <ItemsControl x:Name="EditorCanvas" Grid.Row="1" ItemsSource="{Binding Path=Entities}">
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <Canvas/>
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
            <ItemsControl.ItemContainerStyle>
                <Style TargetType="ContentPresenter">
                    <Setter Property="Canvas.Left" Value="{Binding Path=(models:CEntity.X)}" />
                    <Setter Property="Canvas.Top" Value="{Binding Path=(models:CEntity.Y)}" />
                </Style>
            </ItemsControl.ItemContainerStyle>
            <ItemsControl.ItemTemplate>
                <DataTemplate DataType="{x:Type models:CEntity}">
                    <Thumb HorizontalAlignment="Right" VerticalAlignment="Top" DragDelta="Thumb_OnDragDelta" MouseDoubleClick="Thumb_MouseDoubleClick">
                        <Thumb.Template>
                            <ControlTemplate>
                                <Grid>
                                    <Rectangle Width="80" Height="50" RadiusX="4" RadiusY="4" Stroke="Black" Fill="LightBlue"/>
                                    <Label Content="{Binding Path=Name}"/>
                                </Grid>
                            </ControlTemplate>
                        </Thumb.Template>
                    </Thumb>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>
    </Grid>
</Window> 

I have Entities in my viewmodel as below:我的视图模型中有Entities如下:

public class MainViewModel 
{
    private readonly IEntityRepository _entityRepository;
    private readonly IUnitOfWork _unitOfWork;

    public MainViewModel(IEntityRepository entityRepository, IUnitOfWork unitOfWork)
    {
        _entityRepository = entityRepository;
        _unitOfWork = unitOfWork;
        Entity = new CEntity();
        Entities = new ObservableCollection<CEntity>();
    }

    public void Load()
    {
        var entities = _entityRepository.GetAll().Select(entity => new CEntity()
        {
            Id = entity.Id,
            Name = entity.Name,
            X = entity.X,
            Y = entity.Y
        });

        Entities.Clear();

        foreach (var entity in entities)
        {
            Entities.Add(entity);
        }
    }

    public ObservableCollection<CEntity> Entities { get; set; }

    public void Add(string name, int x, int y)
    {
        var entity = new Entity()
        {
            Name = name,
            X = x,
            Y = y
        };
        _entityRepository.Add(entity);
        _unitOfWork.Save();
    }
}

Based on MVVM we have to use viewmodel instead of model in view, my problem is this part in view:基于MVVM我们必须在视图中使用视图模型而不是模型,我的问题是视图中的这部分:

<ItemsControl.ItemContainerStyle>
                <Style TargetType="ContentPresenter">
                    <Setter Property="Canvas.Left" Value="{Binding Path=(models:CEntity.X)}" />
                    <Setter Property="Canvas.Top" Value="{Binding Path=(models:CEntity.Y)}" />
                </Style>
</ItemsControl.ItemContainerStyle>

When I use Model CEntity here it works fine but I don't know what should I put as part of viewmodel instead of CEntity.当我在这里使用 Model CEntity ,它工作正常,但我不知道我应该把什么作为 viewmodel 的一部分而不是 CEntity。

CEntity should not inherit from Entity as it then hides the X and Y properties. CEntity不应从Entity继承,因为它会隐藏XY属性。

You'd better use composition and wrap Entity :您最好使用组合并包装Entity

public class CEntity : INotifyPropertyChanged
{
    private readonly Entity _entity;

    public CEntity(Entity entity)
    {
        _entity = entity;
    }

    public int X
    {
        get => _entity.X;
        set
        {
            _entity.X = value;
            OnPropertyChanged();
        }
    }

    public int Y
    {
        get => _entity.Y;
        set
        {
            _entity.Y = value;
            OnPropertyChanged();
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

You can then bind directly to the X and Y properties as usual:然后你可以像往常一样直接绑定到XY属性:

<Setter Property="Canvas.Left" Value="{Binding Path=X}" />
<Setter Property="Canvas.Top" Value="{Binding Path=Y}" />

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM