использование ModelView в представлении в MVVM + WPF - PullRequest
0 голосов
/ 12 января 2020

У меня есть модель с именем 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; }
    }

Я хочу, чтобы эта модель внедрила 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));
        }
    }

Это 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> 

У меня 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();
    }
}

На основе MVVM мы Я должен использовать viewmodel вместо модели, моя проблема заключается в следующем:

<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>

Когда я использую модель CEntity, она работает нормально, но я не знаю, что я должен поставить как часть модели представления вместо CEntity.

1 Ответ

0 голосов
/ 14 января 2020

CEntity не должен наследоваться от Entity, поскольку тогда скрываются свойства X и Y.

Лучше использовать композицию и обтекание 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));
    }
}

Затем можно напрямую связать свойства X и Y как обычно:

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