הדגמה פשוטה של MVVM ב-C# WPF
-
הדגמה פשוטה של MVVM
עיין כאן להסבר על המושג MVVM:
להרחבה על הנושא עיין כאןהיה לי צורך להדגים את המודל mvvm עבור ידיד אז יצרתי את הפרוייקט דלהלן על בסיס כתבה זו (הפרוייקט רחוק מלהיות מושלם אבל הוא מספיק בשביל הדגמה לדעתי):
התוכנה מיישמת מחשבון (כלשהו) שיניתי קצת מהכתבה לצורך ההדגמה.
- קוד ל-view
<Window x:Class="WpfTestProject.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:WpfTestProject" mc:Ignorable="d" Background="WhiteSmoke" SizeToContent="WidthAndHeight" FocusManager.FocusedElement="{Binding ElementName=FirstValueTextBox}"> <Window.DataContext> <local:CalculatorViewModel/> </Window.DataContext> <Window.InputBindings> <KeyBinding Key="A" Modifiers="Control" Command="{Binding AddCommand}"/> <KeyBinding Key="S" Modifiers="Control" Command="{Binding SubTractCommand}"/> <KeyBinding Key="T" Modifiers="Control" Command="{Binding TimesCommand}"/> <KeyBinding Key="D" Modifiers="Control" Command="{Binding DivideCommand}"/> <KeyBinding Key="P" Modifiers="Control" Command="{Binding PercentCommand}"/> </Window.InputBindings> <Window.Resources> <Style TargetType="TextBox"> <Setter Property="Margin" Value="5"/> <Setter Property="HorizontalContentAlignment" Value="Center"/> <Setter Property="VerticalContentAlignment" Value="Center"/> <Setter Property="BorderBrush" Value="LightGray"/> </Style> <Style TargetType="TextBlock"> <Setter Property="Margin" Value="5"/> <Setter Property="VerticalAlignment" Value="Center"/> </Style> <Style TargetType="Label"> <Setter Property="Margin" Value="5"/> <Setter Property="HorizontalContentAlignment" Value="Center"/> <Setter Property="VerticalContentAlignment" Value="Center"/> <Setter Property="BorderBrush" Value="LightGray"/> <Setter Property="BorderThickness" Value="1"/> <Setter Property="Background" Value="White"/> </Style> <Style TargetType="Button"> <Setter Property="Margin" Value="5"/> <Setter Property="Background" Value="{x:Null}"/> <Setter Property="BorderBrush" Value="LightGray"/> <Setter Property="Height" Value="38"/> <Setter Property="Width" Value="{Binding Path=Height, RelativeSource={RelativeSource Self}}"/> </Style> </Window.Resources> <StackPanel> <TextBlock Text="Calculator" HorizontalAlignment="Center" FontSize="34" Foreground="BlueViolet"/> <Grid Margin="5,10,5,5" KeyboardNavigation.TabNavigation="Cycle"> <Grid.ColumnDefinitions> <ColumnDefinition Width="*"/> <ColumnDefinition Width="auto"/> <ColumnDefinition Width="*"/> <ColumnDefinition Width="auto"/> <ColumnDefinition Width="*"/> </Grid.ColumnDefinitions> <TextBox x:Name="FirstValueTextBox" Grid.Column="0" Text="{Binding FirstValue}" /> <TextBlock Text="{Binding MathMethod}" Grid.Column="1"/> <TextBox x:Name="SecondValueTextBox" Grid.Column="2" Text="{Binding SecondValue}"/> <TextBlock Text="=" Grid.Column="3" VerticalAlignment="Center" Margin="5"/> <Label Grid.Column="4" Margin="5" Content="{Binding ResultValue, BindsDirectlyToSource=True}"/> </Grid> <StackPanel Orientation="Horizontal" Margin="5"> <Button Content="+" Command="{Binding AddCommand}"/> <Button Content="-" Command="{Binding SubTractCommand}"/> <Button Content="*" Command="{Binding TimesCommand}"/> <Button Content="/" Command="{Binding DivideCommand}"/> <Button Content="%" Command="{Binding PercentCommand}"/> </StackPanel> </StackPanel> </Window>
- קודים המהווים בסיס ל-viewmodel
using System; using System.Windows.Input; namespace WpfTestProject { public abstract class ICommandBase : ICommand { public event EventHandler CanExecuteChanged; public virtual bool CanExecute(object parameter) { return true; } public abstract void Execute(object parameter); protected void OnCanExecuteChanged() { CanExecuteChanged?.Invoke(this, new EventArgs()); } } public class RelayCommand : ICommandBase { private Action commandTask; public RelayCommand(Action action) { commandTask = action; } public override void Execute(object parameter) { commandTask(); } } } public class INotifyPropertyChangedBase : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; protected void OnPropertyChanged(string propertyName) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } }
- ה-viewmodel
using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Input; namespace WpfTestProject { public class CalculatorViewModel : INotifyPropertyChangedBase { #region members string _mathMethod; double _firstValue; double _secondValue; double _result; #endregion #region properties public string MathMethod { get => _mathMethod; set { _mathMethod = value; OnPropertyChanged(nameof(MathMethod)); } } public double FirstValue { get => _firstValue; set => _firstValue = value; } public double SecondValue { get => _secondValue; set => _secondValue = value; } public double ResultValue { get => _result; set { _result = value; OnPropertyChanged(nameof(ResultValue)); } } #endregion #region Commands public ICommand AddCommand { get { //return plusCommand; return new RelayCommand(Add); } } public ICommand SubTractCommand { get { return new RelayCommand(SubTract); } } public ICommand TimesCommand { get { return new RelayCommand(Times); } } public ICommand PercentCommand { get { return new RelayCommand(Percent); } } public ICommand DivideCommand { get { return new RelayCommand(Divide); } } #endregion #region Methods public void Add() { MathMethod = "+"; ResultValue = FirstValue + SecondValue; return; } public void SubTract() { MathMethod = "-"; ResultValue = FirstValue - SecondValue; } public void Times() { MathMethod = "*"; ResultValue = FirstValue * SecondValue; } public void Divide() { MathMethod = "/"; ResultValue = FirstValue / SecondValue; } public void Percent() { MathMethod = "%"; ResultValue = FirstValue * SecondValue; } #endregion } }
- שמתם לב? ה-model חסר.... בתוכנה זו לא היה צורך ב-model בעיקרון ה-model היה יכול להיות אחד משני דברים. או class עם מבנה נתונים. או class עם קוד חיצוני.
-
יש לכם הערות? אנא כתבו אותם לתועלת כולם!
הערה: אישית אני ראיתי תועלת גדולה ב-mvvm, למרות שביישום של commands לא כל כך ראיתי תועלת בפרוייקטים שלי כי לרוב זה לא היה נצרך ורק הפך את הקוד למסורבל, בכל אופן הדוגמא דלהלן כוללת אותם לצורך ההדגמה ואפשר לראות כיצד הם 'מחליקים' את פעולת התוכנה, כמו"כ הוספתי קיצורי מקשים דרך ה-commands מה שמדגים את השימושיות שלהם.