最近在研究Xamarin的MVVM,
想說以前寫過WPF,
卻是用Windows Form的寫法去做,
從未使用MVVM,
所以就來研究MVVM吧。
需求:金額乘以數量算出總價
第一個範例是透過Button去觸發計算
Model物件
namespace WPFMVVM
{
public class Calc
{
public int count { get; set; }
public int money { get; set; }
public int total { get; set; }// { return count * money; } }
}
}
View Model物件
需實作INotifyPropertyChanged介面
RelayCommand該類別內容為天空的垃圾場的範例中取得
namespace WPFMVVM
{
public class CalcViewModel : INotifyPropertyChanged
{
public Calc calc { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
/// <summary>
/// 建立Command物件,可設定於Button Command屬性中
/// </summary>
public ICommand UpdateName { get { return new RelayCommand(UpdateTotalExecute, CanUpdateNameExecute); } }
public CalcViewModel()
{
calc = new Calc()
{ count = 0 };
}
/// <summary>
/// 數量
/// </summary>
public int Count
{
get { return calc.count; }
set
{
if (calc.count != value)
{
calc.count = value;
//當值有改變時,觸發event
RaisePropertyChanged("count");
}
}
}
/// <summary>
/// 單價
/// </summary>
public int Money
{
get { return calc.money; }
set
{
if (calc.money != value)
{
calc.money = value;
//當值有改變時,觸發event
RaisePropertyChanged("money");
}
}
}
/// <summary>
/// 金額
/// </summary>
public int Total
{
get { return calc.total; }
set
{
if (calc.total != value)
{
calc.total = value;
//當值有改變時,觸發event
RaisePropertyChanged("total");
}
}
}
private void RaisePropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
/// <summary>
/// Command執行的商業邏輯
/// </summary>
void UpdateTotalExecute()
{
Total = Money * Count;
}
bool CanUpdateNameExecute()
{
return true;
}
}
}
Xaml部分
第一步驟:設定DataContext
第二步驟:綁定數量及單價的TextBox、金額的Label
第三步驟:設定計算Button的Command屬性
<Window x:Class="WPFMVVM.Window1"
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"
xmlns:local="clr-namespace:WPFMVVM"
mc:Ignorable="d"
Title="Window1" Height="300" Width="300">
<Window.DataContext>
<local:CalcViewModel />
</Window.DataContext>
<Grid>
<Label x:Name="label_Copy" Content="數量" HorizontalAlignment="Left" Margin="10,23,0,0" VerticalAlignment="Top" Width="51"/>
<TextBox x:Name="textBox" HorizontalAlignment="Left" Height="23" Margin="78,25,0,0" TextWrapping="Wrap" Text="{Binding Count, Mode=OneWayToSource, UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Top" Width="66" />
<Label x:Name="label_Copy1" Content="單價" HorizontalAlignment="Left" Margin="10,53,0,0" VerticalAlignment="Top" Width="51"/>
<TextBox x:Name="textBox_Copy" HorizontalAlignment="Left" Height="23" Margin="78,55,0,0" TextWrapping="Wrap" Text="{Binding Money, Mode=OneWayToSource, UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Top" Width="66" />
<Label x:Name="label_Copy2" Content="{Binding Total}" HorizontalAlignment="Left" Margin="10,98,0,0" VerticalAlignment="Top" Width="51"/>
<Button x:Name="button" Content="計算" HorizontalAlignment="Left" Margin="30,140,0,0" VerticalAlignment="Top" Width="75" Command="{Binding UpdateName}"/>
</Grid>
</Window>
結果
該範例參考天空的垃圾場 http://blog.sanc.idv.tw/2011/12/wpf-mvvm.html
第二個範例
需求:希望設定好[單價]或[數量]時,立即計算出[金額],不透過計算按鈕去計算
Model物件
制定total屬性的get內容
namespace WPFMVVM
{
public class Calc
{
public int count { get; set; }
public int money { get; set; }
public int total { get { return count * money; } }
}
}
ViewModel物件
依然實作INotifyPropertyChanged介面,
但不須設定Command物件,
當Count及Money屬性改變時,觸發Event的屬性為total
namespace WPFMVVM
{
public class CalcViewModel : INotifyPropertyChanged
{
public Calc calc { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
public CalcViewModel()
{
calc = new Calc()
{ count = 0 };
}
/// <summary>
/// 數量
/// </summary>
public int Count
{
get { return calc.count; }
set
{
if (calc.count != value)
{
calc.count = value;
//當值有改變時,觸發event
RaisePropertyChanged("total");
}
}
}
/// <summary>
/// 單價
/// </summary>
public int Money
{
get { return calc.money; }
set
{
if (calc.money != value)
{
calc.money = value;
//當值有改變時,觸發event
RaisePropertyChanged("total");
}
}
}
/// <summary>
/// 金額
/// </summary>
public int Total
{
get { return calc.total; }
}
private void RaisePropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
}
Xaml部分
第一步驟:依然定義DataContext
第二步驟:依然綁定數量及單價的TextBox、金額的Label
第三步驟:由於沒有計算按鈕,所以不需設定
<Window x:Class="WPFMVVM.Window1"
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"
xmlns:local="clr-namespace:WPFMVVM"
mc:Ignorable="d"
Title="Window1" Height="300" Width="300">
<Window.DataContext>
<local:CalcViewModel />
</Window.DataContext>
<Grid>
<Label x:Name="label_Copy" Content="數量" HorizontalAlignment="Left" Margin="10,23,0,0" VerticalAlignment="Top" Width="51"/>
<TextBox x:Name="textBox" HorizontalAlignment="Left" Height="23" Margin="78,25,0,0" TextWrapping="Wrap" Text="{Binding Count, Mode=OneWayToSource, UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Top" Width="66" />
<Label x:Name="label_Copy1" Content="單價" HorizontalAlignment="Left" Margin="10,53,0,0" VerticalAlignment="Top" Width="51"/>
<TextBox x:Name="textBox_Copy" HorizontalAlignment="Left" Height="23" Margin="78,55,0,0" TextWrapping="Wrap" Text="{Binding Money, Mode=OneWayToSource, UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Top" Width="66" />
<Label x:Name="label_Copy2" Content="{Binding Total}" HorizontalAlignment="Left" Margin="10,98,0,0" VerticalAlignment="Top" Width="51"/>
</Grid>
</Window>
結果