c# - 在 MVVM + WPF 的视图中使用 ModelView
问题描述
我有一个模型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
我们必须在视图中使用视图模型而不是模型,我的问题是视图中的这一部分:
<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 的一部分。
解决方案
CEntity
不应该继承自Entity
,因为它会隐藏X
andY
属性。
你最好使用 composition 和 wrap 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
andY
属性:
<Setter Property="Canvas.Left" Value="{Binding Path=X}" />
<Setter Property="Canvas.Top" Value="{Binding Path=Y}" />
推荐阅读
- java - Android Instrumentation 测试:使用 Espresso 和 Spoon 的“找不到测试类”
- php - WordPress 命令不同步
- powerbi - 如何在 Power BI 中创建具有互补日期范围的两列的累积和
- flutter - 在 Flutter/dart 中使用泛型类型解析 JSON 的最佳方法
- asp.net-core - 如何添加声明以在身份服务器中使用它们
- bootstrap-datetimepicker - Datetimepicker 不显示日历
- python - 我是使用 python 制作不和谐欢迎机器人的新手,我遇到了问题
- terraform - 如何使用 terraform 0.13.5 检查列表中是否存在值?
- python - 在 Windows 上识别 Python 中丢失的 DLL
- git - 将 1 个分支合并到另一个分支,但不是所有文件/文件夹