Tugas 4 - Menerapkan MVVM Di Windows Presentation Foundation (WPF)
MVVM adalah sebuah variasi dari MVC yang memisahkan view menjadi dua, yaitu view dan view model yang terhubung melalui data binding. MVVM kali ini akan dikerjakan dengan contoh berupa sebuah aplikasi yang memakai Windows Presentation Foundation (WPF)
Berikut adalah Langkah-langkahnya:
1. Buat Project baru dengan tipe WPF App. (.NET Framework)
2. Membuat Class baru ItemPenjualan.cs
Klik Kanan pada nama project > Add > Class lalu tulis kode berikut
using
System;
using
System.Collections.Generic;
using
System.Linq;
using
System.Text;
using
System.ComponentModel.DataAnnotations;
using
System.ComponentModel.DataAnnotations.Schema;
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);
}
}
}
3. Mengubah tampilan aplikasi dengan code pada MainWindow.xaml
Tuliskan kode berikut
<
Window
x:Class
=
"LatihanMVVM.MainWindow"
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
=
"in-IN"
/>
<
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
>
</
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
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
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
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
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
=
"Label"
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
>
4. Membuat class ItemPenjualanViewModel.cs sebagai view model
Tuliskan ckode berikut
using
System;
using
System.Collections.Generic;
using
System.Linq;
using
System.Text;
using
System.ComponentModel;
namespace
LatihanMVVM
{
class
ItemPenjualanViewModel : INotifyPropertyChanged
{
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; }
}
}
}
5. Ubah class MainWindow.xaml.cs untuk menghubungkan model dengan view
using
System;
using
System.Collections.Generic;
using
System.Linq;
using
System.Text;
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();
}
}
}
6. Lakukan binding dan tambahkan validation dengan mengubah code pada
MainWindow.xaml
...
<
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}"
/>
...
...
<
Style
TargetType
=
"TextBox"
>
...
<
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
>
...
7. Langkah selanjutnya adalah menghubungkan dengan database, kali ini saya menggunakan mySQL. Download MySQL Connector/.NET versi 6.8.7 (harus sama dengan versi Entity Framework nanti)
8. Tambahkan Reference MySql.Data.Entity.EF6 dan System.ComponentModel.DataAnnotations Klik Kanan pada references > Add References > search pada assemblies
9. Tambahkan Nuget Package entity FrameworkKlik Project > Manage Nuget Packages > Install Entity Framework
10. Buat Database, misal beri nama mvvm
11. Ubah code pada App.config sesuai dengan nama database, username, dan password
<?
xml
version
=
"1.0"
encoding
=
"utf-8"
?>
<
configuration
>
...
<
entityFramework
>
<
providers
>
<
provider
invariantName
=
"MySql.Data.MySqlClient"
type
=
"MySql.Data.MySqlClient.MySqlProviderServices, MySql.Data.Entity.EF6"
/>
</
providers
>
</
entityFramework
>
<
connectionStrings
>
<
add
name
=
"LatihanContext"
connectionString
=
"server=localhost; database=latihan; uid=steven; password=12345"
providerName
=
"MySql.Data.MySqlClient"
/>
</
connectionStrings
>
</
configuration
>
12. Ubah code pada ItemPenjualan.cs agar Property ID menjadi auto-increment
...
using
System.ComponentModel.DataAnnotations.Schema;
namespace
LatihanMVVM
{
public
class
ItemPenjualan
{
...
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public
long
Id {
get
;
set
; }
[StringLength(50)]
public
string
NamaBarang {
get
;
set
; }
...
}
}
13. Buat Class LatihanContext.cs
...
using
System.ComponentModel.DataAnnotations.Schema;
namespace
LatihanMVVM
{
public
class
ItemPenjualan
{
...
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public
long
Id {
get
;
set
; }
[StringLength(50)]
public
string
NamaBarang {
get
;
set
; }
...
}
}
14. Buat Class MyHistoryContext.cs
using
System;
using
System.Collections.Generic;
using
System.Linq;
using
System.Text;
using
System.Data.Entity.Migrations.History;
using
System.Data.Common;
using
System.Data.Entity;
namespace
LatihanMVVM
{
public
class
MyHistoryContext : HistoryContext
{
public
MyHistoryContext(DbConnection dbConnection,
string
defaultSchema)
:
base
(dbConnection, defaultSchema)
{
}
protected
override
void
OnModelCreating(System.Data.Entity.DbModelBuilder modelBuilder)
{
base
.OnModelCreating(modelBuilder);
modelBuilder.Entity<HistoryRow>().Property(p => p.MigrationId).HasMaxLength(100).IsRequired();
modelBuilder.Entity<HistoryRow>().Property(p => p.ContextKey).HasMaxLength(200).IsRequired();
}
}
public
class
ModelConfiguration : DbConfiguration
{
public
ModelConfiguration()
{
SetHistoryContext(
"MySql.Data.MySqlClient"
, (c, s) =>
new
MyHistoryContext(c, s));
}
}
}
15. Ubah kode ItemPenjualanViewModel untuk menambah class SimpanCOmmand dan propertinya pada view model
using
System;
using
System.Collections.Generic;
using
System.Linq;
using
System.Text;
using
System.ComponentModel;
using
System.Windows.Input;
using
System.Windows;
namespace
LatihanMVVM
{
public
class
ItemPenjualanViewModel : INotifyPropertyChanged
{
...
private
ICommand simpanCommand;
...
public
ICommand SimpanCommand
{
get
{
if
(
this
.simpanCommand ==
null
)
{
this
.simpanCommand =
new
SimpanCommand(
this
);
}
return
this
.simpanCommand;
}
}
}
public
class
SimpanCommand : ICommand
{
private
ItemPenjualanViewModel viewModel;
public
SimpanCommand(ItemPenjualanViewModel viewModel)
{
this
.viewModel = viewModel;
}
public
event
EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public
bool
CanExecute(
object
parameter)
{
return
viewModel.Model.Total() > 0;
}
public
void
Execute(
object
parameter)
{
using
(
var
db =
new
LatihanContext())
{
db.Database.Log = Console.Write;
db.DaftarItemPenjualan.Add(viewModel.Model);
db.SaveChanges();
MessageBox.Show(
"Data berhasil disimpan ke database"
);
}
}
}
}
16. Lakukan Binding pada button simpan dengan mengubah kode pada MainWindow.xaml
...
<
Button
Content
=
"Simpan"
...
Command
=
"{Binding SimpanCommand}"
/>
...
17. Generate table dengan Package Manager Console lalu ketik Enable-Migrations, setelah itu akan otomatis terbuat folder MigrationsKlik Tools > NuGet Package Manager > Package Manager Console
18. Pada Package Manager Console, ketikkan Add-Migration, akan otomatis terbuat file migration
19. Pada Package Manager Console, ketikkan Update-Database, maka akan dibuatkan database sesuai tabel yang sudah kita buat
20. Selesai, begini aplikasi ketika dijalankan
Komentar
Posting Komentar