[英]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.