C# 在MVVM+;WPF
我有一个名为实体的模型,它首先由EF数据库创建:C# 在MVVM+;WPF,c#,wpf,mvvm,viewmodel,C#,Wpf,Mvvm,Viewmodel,我有一个名为实体的模型,它首先由EF数据库创建: public partial class Entity { public Entity() { this.Properties = new HashSet<Property>(); } public long Id { get; set; } public string Name { get; set; }
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; }
}
这是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>
基于MVVM
我们必须使用viewmodel而不是view中的model,我的问题是view中的这一部分:
<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>
当我在这里使用Model
CEntity
时,它可以正常工作,但我不知道应该将什么内容作为viewmodel的一部分而不是CEntity。CEntity
不应该继承自实体,因为它会隐藏X
和Y
属性
您最好使用合成和包装实体:
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}" />
是模型:CEntity.X
和模型:CEntity.Y
静态字段还是实例字段?在代码段中,它们被声明为实例属性。实际上,您的CEntity
看起来像是viewmodel,而不是基于MVVM的模型我们必须使用viewmodel而不是view中的模型,我的问题是视图中的这一部分-您完全错误地理解MVVM上下文中的模型是什么。视图应该只知道ViewModel,而ViewModel应该只知道模型。视图可以向ViewModel请求数据,并且该数据可以包含在一个类的实例中,该类不必是ViewModel,但可以是一个简单的POCO类,该类也可以实现INotifyPropertyChangedBut:CEntity不应从实体继承,因为这将违反SRP。使用AutoMapper和独立类(一个用于存储数据,一个用于显示),并使用AutoMapper在它们之间进行映射。
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));
}
}
<Setter Property="Canvas.Left" Value="{Binding Path=X}" />
<Setter Property="Canvas.Top" Value="{Binding Path=Y}" />