Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/wpf/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在MVVM+;WPF_C#_Wpf_Mvvm_Viewmodel - Fatal编程技术网

C# 在MVVM+;WPF

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

我有一个名为实体的模型,它首先由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; }
    }
这是
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}" />