Implementeer ICommand patroon met RelayCommand voor MVVM
- Voeg RelayCommand class toe voor herbruikbare ICommand implementatie - Vervang button click event handler door AddProductCommand in MainViewModel - Update XAML om Command binding te gebruiken in plaats van Click event - Verwijder business logic uit code-behind (MainWindow.xaml.cs) - Los DataContext duplicatie op (was twee keer MainViewModel instantie) Dit maakt de applicatie beter testbaar en volgt proper MVVM principes. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
62
Commands/RelayCommand.cs
Normal file
62
Commands/RelayCommand.cs
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
using System;
|
||||||
|
using System.Windows.Input;
|
||||||
|
|
||||||
|
namespace MVVM_DEMO.Commands
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A command whose sole purpose is to relay its functionality to other objects by invoking delegates.
|
||||||
|
/// The default return value for the CanExecute method is 'true'.
|
||||||
|
/// </summary>
|
||||||
|
public class RelayCommand : ICommand
|
||||||
|
{
|
||||||
|
private readonly Action<object?> _execute;
|
||||||
|
private readonly Func<object?, bool>? _canExecute;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Occurs when changes occur that affect whether or not the command should execute.
|
||||||
|
/// </summary>
|
||||||
|
public event EventHandler? CanExecuteChanged
|
||||||
|
{
|
||||||
|
add { CommandManager.RequerySuggested += value; }
|
||||||
|
remove { CommandManager.RequerySuggested -= value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new command that can always execute.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="execute">The execution logic.</param>
|
||||||
|
public RelayCommand(Action<object?> execute) : this(execute, null)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new command.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="execute">The execution logic.</param>
|
||||||
|
/// <param name="canExecute">The execution status logic.</param>
|
||||||
|
public RelayCommand(Action<object?> execute, Func<object?, bool>? canExecute)
|
||||||
|
{
|
||||||
|
_execute = execute ?? throw new ArgumentNullException(nameof(execute));
|
||||||
|
_canExecute = canExecute;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines whether this command can execute in its current state.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="parameter">Data used by the command. If the command does not require data to be passed, this object can be set to null.</param>
|
||||||
|
/// <returns>true if this command can be executed; otherwise, false.</returns>
|
||||||
|
public bool CanExecute(object? parameter)
|
||||||
|
{
|
||||||
|
return _canExecute == null || _canExecute(parameter);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Executes the command.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="parameter">Data used by the command. If the command does not require data to be passed, this object can be set to null.</param>
|
||||||
|
public void Execute(object? parameter)
|
||||||
|
{
|
||||||
|
_execute(parameter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,6 +5,8 @@ using System.ComponentModel;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows.Input;
|
||||||
|
using MVVM_DEMO.Commands;
|
||||||
using MVVM_DEMO.Models;
|
using MVVM_DEMO.Models;
|
||||||
|
|
||||||
namespace MVVM_DEMO.ViewModels
|
namespace MVVM_DEMO.ViewModels
|
||||||
@@ -28,6 +30,9 @@ namespace MVVM_DEMO.ViewModels
|
|||||||
{
|
{
|
||||||
_products = new ObservableCollection<Product>();
|
_products = new ObservableCollection<Product>();
|
||||||
LoadData();
|
LoadData();
|
||||||
|
|
||||||
|
// Initialize commands
|
||||||
|
AddProductCommand = new RelayCommand(ExecuteAddProduct, CanExecuteAddProduct);
|
||||||
}
|
}
|
||||||
|
|
||||||
// read data
|
// read data
|
||||||
@@ -46,5 +51,28 @@ namespace MVVM_DEMO.ViewModels
|
|||||||
public string productName { get; set; }
|
public string productName { get; set; }
|
||||||
public int productPrice { get; set; }
|
public int productPrice { get; set; }
|
||||||
|
|
||||||
|
// Commands
|
||||||
|
public ICommand AddProductCommand { get; set; }
|
||||||
|
|
||||||
|
// Command methods
|
||||||
|
private void ExecuteAddProduct(object? parameter)
|
||||||
|
{
|
||||||
|
Random random = new Random();
|
||||||
|
int randomPrice = random.Next(10, 100);
|
||||||
|
|
||||||
|
Products.Add(new Product
|
||||||
|
{
|
||||||
|
ProductName = $"Product {Products.Count + 1}",
|
||||||
|
Price = randomPrice
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool CanExecuteAddProduct(object? parameter)
|
||||||
|
{
|
||||||
|
// You can add validation logic here
|
||||||
|
// For now, always allow adding products
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
Content="Add Product"
|
Content="Add Product"
|
||||||
Width="100px"
|
Width="100px"
|
||||||
Height="25px"
|
Height="25px"
|
||||||
Click="btnAddProduct_Click" />
|
Command="{Binding AddProductCommand}" />
|
||||||
<Label Content="Selected Product Details"
|
<Label Content="Selected Product Details"
|
||||||
FontWeight="Bold"
|
FontWeight="Bold"
|
||||||
FontSize="16"
|
FontSize="16"
|
||||||
|
|||||||
@@ -18,12 +18,10 @@ namespace MVVM_DEMO
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public partial class MainWindow : Window
|
public partial class MainWindow : Window
|
||||||
{
|
{
|
||||||
MainViewModel viewModel = new MainViewModel();
|
|
||||||
|
|
||||||
public MainWindow()
|
public MainWindow()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
this.DataContext = viewModel;
|
// ViewModel is already set in XAML via Window.DataContext
|
||||||
comboBox.SelectionChanged += ComboBox_SelectionChanged;
|
comboBox.SelectionChanged += ComboBox_SelectionChanged;
|
||||||
// initial selection
|
// initial selection
|
||||||
if (comboBox.Items.Count > 0)
|
if (comboBox.Items.Count > 0)
|
||||||
@@ -35,25 +33,15 @@ namespace MVVM_DEMO
|
|||||||
private void ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
private void ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||||
{
|
{
|
||||||
// display selected product details
|
// display selected product details
|
||||||
if (comboBox.SelectedItem != null)
|
if (comboBox.SelectedItem != null && DataContext is MainViewModel viewModel)
|
||||||
{
|
{
|
||||||
viewModel.productName= ((Product)comboBox.SelectedItem).ProductName;
|
viewModel.productName = ((Product)comboBox.SelectedItem).ProductName;
|
||||||
viewModel.productPrice = (int)((Product)comboBox.SelectedItem).Price;
|
viewModel.productPrice = (int)((Product)comboBox.SelectedItem).Price;
|
||||||
viewModel.OnPropertyChanged("productName");
|
viewModel.OnPropertyChanged("productName");
|
||||||
viewModel.OnPropertyChanged("productPrice");
|
viewModel.OnPropertyChanged("productPrice");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void btnAddProduct_Click(object sender, RoutedEventArgs e)
|
// btnAddProduct_Click removed - now using Command binding in XAML
|
||||||
{
|
|
||||||
// toevoegen van een product in het viewmodel
|
|
||||||
Product p = new Product();
|
|
||||||
p.ProductName = $"Product {viewModel.Products.Count + 1}";
|
|
||||||
// generate a random price between 10 and 100
|
|
||||||
Random rand = new Random();
|
|
||||||
p.Price = rand.Next(10, 100);
|
|
||||||
viewModel.Products.Add(p);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user