簡體   English   中英

帶有實體框架的MVVM

[英]MVVM with Entity Framework

我正在嘗試使用簡單的Crud構建一個小型應用程序。基本上是一個具有四個按鈕的列表框。 我知道我需要一個Model,ViewModel和一個View。但是還有其他問題如何將上下文實體綁定到我的列表框.wpf和mvvm是我的新手。

這是我的模特:

public class Suplemento
{
    public int Id { get; set; }
    public string Name { get; set; }
}

這是我的ViewModel:

public class SuplementoViewModel : ViewModelBase
{
    private Suplemento current = null;
    private int selectedIndex = 0;


    public SuplementoViewModel()
    {
        Suplementos = new ObservableCollection<Suplemento>(MedPlusDatabase.Instance.Suplementos);
    }

    public ObservableCollection<Suplemento> Suplementos { get; set; }
    public bool IsLoaded { get; private set; }
    public ICommand EditCommand { get; private set; }


    public bool CanEdit
    {
        get { return IsLoaded && current != null; }
    }

    public int SelectedIndex
    {
        get { return selectedIndex; }
        set
        {
            if (selectedIndex != value)
            {
                selectedIndex = value;
                RaisePropertyChanged("SelectedIndex");
            }
        }
    }

    public Suplemento Current
    {
        get { return current; }
        set
        {
            if (current != value)
            {
                current = value;
                RaisePropertyChanged("Current");
            }
        }
    }

}

這是我的觀點:

<Window x:Class="MedPlus.frmSuplemento"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:MedPlus"
    Title="Suplementos" 
    Height="470" 
    Width="400" 
    WindowStartupLocation="CenterOwner" 
    ResizeMode="CanResize" 
    WindowStyle="SingleBorderWindow" 
    MinHeight="470" 
    MinWidth="400" 
    Icon="pack://application:,,,/Resources/suplemento.png" 
    ContentRendered="Window_ContentRendered">

<Grid>

    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="15" />
        <ColumnDefinition Width="*" />
        <ColumnDefinition Width="15" />
    </Grid.ColumnDefinitions>

    <Grid.RowDefinitions>
        <RowDefinition Height="Auto" />
        <RowDefinition Height="*" />
        <RowDefinition Height="43" />
    </Grid.RowDefinitions>

    <DockPanel Grid.Row="0" Grid.Column="1" Margin="0,10,0,5">
        <TextBlock DockPanel.Dock="Top" Text="Nome do Suplemento" />
        <TextBox DockPanel.Dock="Bottom" />
    </DockPanel>

    <ListBox Name="lbSuplementos" 
             ItemsSource="{Binding Suplementos}"
             DisplayMemberPath="Name"
             SelectedItem="{Binding Current, Mode=TwoWay}"
             SelectedIndex="{Binding SelectedIndex, Mode=TwoWay}" 
             Grid.Row="1" Grid.Column="1" >
        <ListBox.ItemTemplate>
            <DataTemplate>
                <TextBlock Height="18" Text="{Binding Path=Name}" />
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>

    <Grid Grid.Row="2" Grid.Column="1" >

        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="73" />
            <ColumnDefinition Width="10" />
            <ColumnDefinition Width="73" />
            <ColumnDefinition Width="10" />
            <ColumnDefinition Width="73" />
            <ColumnDefinition Width="10" />
            <ColumnDefinition Width="73" />
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>

        <Button Name="btnNew" Content="_Novo" Grid.Column="1" IsDefault="True" Click="btnNew_Click" />
        <Button Name="btnEdit" Content="_Editar" Grid.Column="3" />
        <Button Name="btnDelete" Content="E_xcluir" Grid.Column="5" />
        <Button Name="btnCancel" Content="_Cancelar" Grid.Column="7" IsCancel="True" Click="btnCancel_Click" />

    </Grid>      

</Grid>

我的ViewModel構造函數應該是什么?

首先,您缺少MVVM模式背后的一些關鍵概念。 實施Purist MVVM模式時的主要目標之一是刪除XAML窗口或用戶控件后面的代碼中的所有代碼。 看看如何在btnNew Button控件上擁有btnNew_Click事件處理程序? 這打破了純MVVM模式。

您應該研究RelayCommand類的不同實現。 這是我過去使用過的:

public class RelayCommand : ICommand
{

    private readonly Action<object> _execute = null;
    private readonly Predicate<object> _canExecute = null;
    public event EventHandler CanExecuteChanged;

    public RelayCommand(Action<object> execute)
        :this(execute, null) {}


    public RelayCommand(Action<object> execute, Predicate<object> canExecute)
    {
        if (execute == null)
            throw new ArgumentNullException("execute");
        _execute = execute;
        _canExecute = canExecute;
    }

    public bool CanExecute(object parameter)
    {
        return _canExecute == null ? true : _canExecute(parameter);
    }

    public void Execute(object parameter)
    {
        _execute(parameter);
    }

    public void RaiseCanExecuteChanged()
    {
        CanExecuteChanged(this, new EventArgs());
    }
}

在ViewModel中,您將創建一個名為AddNewCommand的屬性,如下所示:

public RelayCommand AddNewCommand { get; set; }

然后,定義一個私有方法以在調用該命令時執行操作:

private void AddNew(object param)
{
    //Code to Add Something
}

在構造函數中,初始化命令:

public SuplementoViewModel()
{
    this.AddNewCommand = new RelayCommand(AddNew);
}

然后將命令綁定到XAML代碼中的按鈕。 不要忘記將ViewModel添加到Window或UserControl的DataContext中

DataContext綁定

參考名稱空間優先

xmlns:vm="clr-namespace:MyApp.ViewModels"

將DataContext綁定到ViewModel

<Window.DataContext>
    <vm:SuplementoViewModel />
</Window.DataContext>

將命令綁定到按鈕

<Button Name="btnNew" Content="_Novo" Grid.Column="1" IsDefault="True" Command="{Binding AddNewCommand}" />

現在,您已經將ViewModel綁定到Window / UserControl,在ViewModel的構造函數中,您需要使用一些數據填充Suplementos ObservableCollection,以便顯示列表框。 但是,您需要更改Suplementos屬性的定義。 這是應該是什么樣的:

private ObservableCollection<Suplemento> _suplementos;

public ObservableCollection<Suplemento> Suplementos
{
    get
    {
        return this._suplementos; 
    }
    set
    {
        this._suplementos = value;
        RaisePropertyChanged("Suplementos");
    }
}

這就是為什么。 假設您保持原樣,並在構造器中填充了ObservableCollection,如下所示:

public SuplementoViewModel()
{
    //Service is whatever method you are using to retrieve your values from the database
    this.Suplementos = Service.GetSumplementos();
}

您最終將遇到異常。 原因是當實例化Window / UserControl時,它將在其構造函數中觸發InitializeComponent()方法調用。 此方法實例化視圖中的所有內容和控件,包括ViewModel。 實例化ViewModel時,在實例化Window / UserControl中的任何控件之前,構造函數將運行並填充ObservableCollection。 如果您的列表框是“觀察”您的ObservableCollection,那么即使它尚不存在,又如何“觀察”您所做的更改(在構造函數中填充您的Collection)呢?

通過將您的屬性重構為我之前描述的內容,您的構造函數應如下所示:

public SuplementoViewModel()
{
    this._suplementos = Service.GetSuplementos();
}

看到我如何使用私有容器變量而不是直接填充Suplementos屬性嗎? 這樣,不會引發RaisePropertyChanged()方法,從而避免通知您不存在的ListBox。 一旦實例化了ListBox,它還將讀取其綁定的屬性,並且由於您已經用數據填充了私有容器變量,因此它將列出一些信息。

還要注意,對於您來說,ListBox會通知您對集合的更改,並將選定的項目發布回視圖模型,您的XAML應該如下所示:

<ListBox ItemsSource="{Binding Suplementos, Mode=OneWay, UpdateSourceTrigger=PropertyChanged"
SelectedItem="{Binding Current, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged" />

這就是我現在所擁有的。 祝您好運,WPFing快樂!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM