WPF .NET Framework : Penerapan MVVM di Windows Presentation Foundation

Kali ini saya akan mencoba untuk membuat aplikasi Item Penjualan sederhana menggunakan WPF dengan menerapkan arsitektur MVVM (Model View View Model). MVVM sendiri bisa dikatakan juga merupakan MVC (Model View Controller) yang memisahkan antara logic dengan GUI (Graphical User Interface). Untuk implementasinya sebagai berikut.
- Membuat Project WPF.
- Membuat Model
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Text; | |
using System.Threading.Tasks; | |
namespace LatihanMVVM | |
{ | |
public class ItemPenjualan | |
{ | |
public ItemPenjualan() | |
{ | |
DiskonPersen = 0; | |
} | |
public long Id { get; set; } | |
public string NamaBarang { get; set; } | |
public int Jumlah { get; set; } | |
public decimal Harga { get; set; } | |
public decimal DiskonPersen { get; set; } | |
public decimal Total() | |
{ | |
decimal total = Jumlah * Harga; | |
return total - (DiskonPersen / 100 * total); | |
} | |
} | |
} |
- Melakukan desain GUI (view)
<Window x:Class="LatihanMVVM.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" | |
xmlns:local="clr-namespace:LatihanMVVM" | |
mc:Ignorable="d" | |
Title="MainWindow" Height="356" Width="528"> | |
<Window.Resources> | |
<Style TargetType="TextBlock"> | |
<Setter Property="FontSize" Value="20" /> | |
<Setter Property="FontFamily" Value="Myriad Pro" /> | |
<Setter Property="FontWeight" Value="SemiBold" /> | |
<Setter Property="Background"> | |
<Setter.Value> | |
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0"> | |
<GradientStop Color="#FF508FC4" Offset="0" /> | |
<GradientStop Color="#FF6F94AD" Offset="1" /> | |
<GradientStop Color="#FFC7F3FF" Offset="0.302" /> | |
</LinearGradientBrush> | |
</Setter.Value> | |
</Setter> | |
<Setter Property="Foreground"> | |
<Setter.Value> | |
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0"> | |
<GradientStop Color="#FF5252CE" Offset="0" /> | |
<GradientStop Color="#FF0000DB" Offset="0.953" /> | |
<GradientStop Color="#FF6363CB" Offset="0.337" /> | |
</LinearGradientBrush> | |
</Setter.Value> | |
</Setter> | |
</Style> | |
<Style TargetType="Label"> | |
<Setter Property="FontSize" Value="14" /> | |
</Style> | |
<Style TargetType="TextBox"> | |
<Setter Property="Language" Value="id-ID" /> | |
<Setter Property="Template"> | |
<Setter.Value> | |
<ControlTemplate> | |
<Border x:Name="customBorder" Background="{TemplateBinding Background}" CornerRadius="5" BorderThickness="2" BorderBrush="Gray"> | |
<ScrollViewer x:Name="PART_ContentHost"/> | |
</Border> | |
<ControlTemplate.Triggers> | |
<Trigger Property="IsKeyboardFocused" Value="True"> | |
<Setter TargetName="customBorder" Property="Effect"> | |
<Setter.Value> | |
<DropShadowEffect BlurRadius="10" ShadowDepth="0" Color="#578EC9"/> | |
</Setter.Value> | |
</Setter> | |
</Trigger> | |
<Trigger Property="IsKeyboardFocused" Value="False"> | |
<Setter Property="Foreground" Value="Gray" /> | |
</Trigger> | |
</ControlTemplate.Triggers> | |
</ControlTemplate> | |
</Setter.Value> | |
</Setter> | |
<Setter Property="Validation.ErrorTemplate"> | |
<Setter.Value> | |
<ControlTemplate> | |
<StackPanel Orientation="Horizontal"> | |
<AdornedElementPlaceholder /> | |
<TextBlock Text="Perlu diperbaiki!" Padding="3" Foreground="Red" /> | |
</StackPanel> | |
</ControlTemplate> | |
</Setter.Value> | |
</Setter> | |
</Style> | |
<Style TargetType="Button"> | |
<Setter Property="Background" Value="#DEF2FC" /> | |
<Setter Property="Foreground" Value="Black" /> | |
<Setter Property="FontSize" Value="15"/> | |
<Setter Property="Effect"> | |
<Setter.Value> | |
<DropShadowEffect BlurRadius="10" ShadowDepth="0" Color="#578EC9"/> | |
</Setter.Value> | |
</Setter> | |
<Setter Property="Template"> | |
<Setter.Value> | |
<ControlTemplate TargetType="{x:Type Button}"> | |
<Border x:Name="customBorder" Background="{TemplateBinding Background}" CornerRadius="4" BorderThickness="2" BorderBrush="Gray"> | |
<ContentPresenter Content="{TemplateBinding Content}" HorizontalAlignment="Center" /> | |
</Border> | |
<ControlTemplate.Triggers> | |
<Trigger Property="IsMouseOver" Value="True"> | |
<Setter Property="Background" Value="#2394CC" /> | |
<Setter Property="Foreground" Value="White" /> | |
</Trigger> | |
<Trigger Property="IsPressed" Value="True"> | |
<Setter Property="Effect" Value="{x:Null}" /> | |
</Trigger> | |
<Trigger Property="IsEnabled" Value="False"> | |
<Setter Property="Effect"> | |
<Setter.Value> | |
<BlurEffect Radius="3" /> | |
</Setter.Value> | |
</Setter> | |
</Trigger> | |
</ControlTemplate.Triggers> | |
</ControlTemplate> | |
</Setter.Value> | |
</Setter> | |
</Style> | |
</Window.Resources> | |
<Grid> | |
<Label Content="Nama Barang:" Height="29" HorizontalAlignment="Left" Margin="0,49,0,0" Name="label2" VerticalAlignment="Top" HorizontalContentAlignment="Right" Width="107" /> | |
<TextBox Text="" Height="23" HorizontalAlignment="Stretch" Margin="112,55,12,0" Name="textBox1" VerticalAlignment="Top" /> | |
<Label Content="Jumlah:" Height="27" HorizontalAlignment="Left" Margin="1,86,0,0" Name="label3" VerticalAlignment="Top" Width="106" HorizontalContentAlignment="Right" /> | |
<TextBox Text="" Height="23" HorizontalAlignment="Left" Margin="113,90,0,0" Name="textBox2" VerticalAlignment="Top" Width="62" /> | |
<Label Content="Harga:" Height="28" HorizontalAlignment="Left" Margin="12,122,0,0" Name="label4" VerticalAlignment="Top" HorizontalContentAlignment="Right" Width="95" /> | |
<TextBox Text="" Height="23" HorizontalAlignment="Left" Margin="113,127,0,0" Name="textBox3" VerticalAlignment="Top" Width="124" /> | |
<Button Content="Simpan" Height="27" HorizontalAlignment="Left" Margin="207,228,0,0" Name="button1" VerticalAlignment="Top" Width="82" /> | |
<Label Content="Diskon (%):" Height="33" HorizontalAlignment="Left" Margin="12,161,0,0" Name="label5" VerticalAlignment="Top" HorizontalContentAlignment="Right" Width="95" /> | |
<TextBox Text="" Height="23" HorizontalAlignment="Left" Margin="113,165,0,0" Name="textBox4" VerticalAlignment="Top" Width="62" /> | |
<Label Content="Total:" Height="33" HorizontalAlignment="Left" Margin="12,194,0,0" Name="label6" VerticalAlignment="Top" HorizontalContentAlignment="Right" Width="95" /> | |
<Label Content="" Height="28" HorizontalAlignment="Left" Margin="113,194,0,0" Name="label7" VerticalAlignment="Top" Width="402" /> | |
<TextBlock Height="28" HorizontalAlignment="Stretch" Name="textBlock1" Text="Tambah Item Penjualan" VerticalAlignment="Top" TextAlignment="Center" Margin="0,12,0,0" /> | |
<Grid.Background> | |
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0"> | |
<GradientStop Color="#FFB7CEFF" Offset="0.192" /> | |
<GradientStop Color="White" Offset="1" /> | |
<GradientStop Color="#FF1648AD" Offset="0" /> | |
</LinearGradientBrush> | |
</Grid.Background> | |
</Grid> | |
</Window> |
Untuk hasilnya akan membentuk window yang kira-kira seperti gambar dibawah ini.
- Membuat ViewModel
using System; | |
using System.Collections.Generic; | |
using System.ComponentModel; | |
using System.Linq; | |
using System.Text; | |
using System.Threading.Tasks; | |
namespace LatihanMVVM | |
{ | |
class ItemPenjualanViewModel : INotifyPropertyChanged | |
{ | |
//System.Threading.Thread.CurrentThread.CurrentUICulture = new CultureInfo("en-US"); | |
public event PropertyChangedEventHandler PropertyChanged; | |
private ItemPenjualan model; | |
public ItemPenjualanViewModel(ItemPenjualan itemPenjualan = null) | |
{ | |
this.model = itemPenjualan ?? new ItemPenjualan(); | |
} | |
public string NamaBarang | |
{ | |
get { return model.NamaBarang; } | |
set | |
{ | |
if (value != model.NamaBarang) | |
{ | |
model.NamaBarang = value; | |
PropertyChanged(this, new PropertyChangedEventArgs("NamaBarang")); | |
} | |
} | |
} | |
public int Jumlah | |
{ | |
get { return model.Jumlah; } | |
set | |
{ | |
if (value != model.Jumlah) | |
{ | |
model.Jumlah = value; | |
PropertyChanged(this, new PropertyChangedEventArgs("Jumlah")); | |
PropertyChanged(this, new PropertyChangedEventArgs("Total")); | |
} | |
} | |
} | |
public decimal Harga | |
{ | |
get { return model.Harga; } | |
set | |
{ | |
if (value != model.Harga) | |
{ | |
model.Harga = value; | |
PropertyChanged(this, new PropertyChangedEventArgs("Harga")); | |
PropertyChanged(this, new PropertyChangedEventArgs("Total")); | |
} | |
} | |
} | |
public decimal DiskonPersen | |
{ | |
get { return model.DiskonPersen; } | |
set | |
{ | |
if (value != model.DiskonPersen) | |
{ | |
model.DiskonPersen = value; | |
PropertyChanged(this, new PropertyChangedEventArgs("DiskonPersen")); | |
PropertyChanged(this, new PropertyChangedEventArgs("Total")); | |
} | |
} | |
} | |
public string Total | |
{ | |
get | |
{ | |
decimal? total = model.Total(); | |
if (!total.HasValue) | |
{ | |
return "-"; | |
} | |
else | |
{ | |
return total.Value.ToString("C"); | |
} | |
} | |
} | |
public ItemPenjualan Model | |
{ | |
get { return this.model; } | |
} | |
} | |
} |
- Melakukan Data Binding
Untuk menghubungkan antara model, view, dan view model perlu didefinisikan sebuah DataContext. Untuk implementasinya adalah dengan membuat MainWindow.xaml.cs sebagai berikut.
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Text; | |
using System.Threading.Tasks; | |
using System.Windows; | |
using System.Windows.Controls; | |
using System.Windows.Data; | |
using System.Windows.Documents; | |
using System.Windows.Input; | |
using System.Windows.Media; | |
using System.Windows.Media.Imaging; | |
using System.Windows.Navigation; | |
using System.Windows.Shapes; | |
namespace LatihanMVVM | |
{ | |
/// <summary> | |
/// Interaction logic for MainWindow.xaml | |
/// </summary> | |
public partial class MainWindow : Window | |
{ | |
public MainWindow() | |
{ | |
InitializeComponent(); | |
DataContext = new ItemPenjualanViewModel(); | |
} | |
} | |
} |
Kemudian kita lakukan Data Binding dengan mengubah MainWindow.xaml menjadi sebagai berikut.
... | |
<Label Content="Nama Barang:" ... /> | |
<TextBox Name="textBox1" ... Text="{Binding Path=NamaBarang}"/> | |
<Label Content="Jumlah:" ... /> | |
<TextBox ... Text="{Binding Path=Jumlah, StringFormat={}{0:#,0}}"/> | |
<Label Content="Harga:" ... /> | |
<TextBox ... Text="{Binding Path=Harga, StringFormat={}{0:C}}"/> | |
<Label Content="Diskon (%):" ... /> | |
<TextBox ... Text="{Binding Path=DiskonPersen, StringFormat={}{0:#.#}}"/> | |
<Label Content="Total:" ... /> | |
<Label .... Content="{Binding Path=Total}" /> | |
... |
Hasil dari aplikasi yang telah kita buat hingga saat ini menjadi sebagai berikut.
Komentar
Posting Komentar