728x90
WPF(Windows Presentation Foundation)에서 Command는 MVVM(Model-View-ViewModel) 디자인 패턴을 사용할 때 사용되는 중요한 요소 중 하나입니다. Command는 UI에서 발생하는 이벤트와 실행 로직(메서드 또는 기능) 사이의 결합을 제거하고, 코드를 더 모듈화하고 유연하게 만들어줍니다.
Command를 사용하는 주요 이유 중 하나는 코드의 재사용성과 유지보수성을 높이는 데에 있습니다. 일반적으로, UI 요소(예: Button)에 직접적으로 클릭 이벤트 핸들러를 연결하는 대신 Command를 사용하여 해당 이벤트를 처리합니다.
예제를 통해 배워보겠습니다.
구성은 아래그림처럼 되어있습니다.
그리고 비동기 command를 사용하기 위해서는 nuget패키지를 하나 설치해야합니다.
nuget패키지 관리자에서 아래 패키지를 설치합니다.
설치가 완료되었다면 아래 xaml,클래스에서 코드를 입력하면 됩니다.
MainWindow.xaml
<Window x:Class="WpfTriggerAndCommand.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:WpfTriggerAndCommand"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<StackPanel>
<ProgressBar Height="20" Value="{Binding ProgressValue}"></ProgressBar>
<TextBox x:Name="textBox1"></TextBox>
<Button Content="버튼" Command="{Binding Command}" CommandParameter="{Binding ElementName=textBox1,Path=Text}"></Button>
</StackPanel>
</Grid>
</Window>
MainWindow.cs
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;
using WpfTriggerAndCommand.ViewModels;
namespace WpfTriggerAndCommand
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
MainViewModel viewModel;
public MainWindow()
{
InitializeComponent();
viewModel = new MainViewModel();
//데이터를 뷰모델과 연결
DataContext = viewModel;
}
}
}
MainViewModel.cs
using Microsoft.Toolkit.Mvvm.Input;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using WpfTriggerAndCommand.Commands;
namespace WpfTriggerAndCommand.ViewModels
{
internal class MainViewModel : INotifyPropertyChanged
{
private int progressValue;
public ICommand Command { get; set; }
public MainViewModel()
{
//동기식
//Command = new RelayComnmand<object>(ExcuteButton, CanButton);
//비동기식
Command = new AsyncRelayCommand(ExcuteButton2);
//task로 wraping되기에 Task로 참조할수 있음
Task t = ExcuteButton2();
}
public int ProgressValue
{
get { return progressValue; }
set
{
progressValue = value;
NotifyPropertyChanged(nameof(ProgressValue));
}
}
bool CanButton(object param)
{
if(param == null)
{
return true;
}
return param.ToString().Equals("aaa")?true:false;
}
void ExcuteButton(object param)
{
//비동기작업 실행
int w = 0;
Task task1 = Task.Run(() =>
{
for(int i = 0; i < 10; i++)
{
ProgressValue = i;
}
});
Task task2 = Task.Run(() =>
{
for (int i = 0; i < 50; i++)
{
ProgressValue = i;
w = i;
}
});
//앞서 작업이 끝날때까지 해당 코드에서 대기함
task2.Wait();
MessageBox.Show(w + ""); //49 출력
}
//async를 사용하면 비동기 실행이 가능하며 await 키워드를 사용가능
//async를 사용하면 메인스레드를 정지시키지 않고 작업을 기다림
public async Task ExcuteButton2()
{
int w = 0;
//Task안의 제너레이터는 리턴 유형
Task<int> task1 = Task.Run(() =>
{
int j = 0;
for (int i = 0; i < 50; i++)
{
ProgressValue = i;
j = i;
}
return j;
});
w = await task1;
MessageBox.Show(w + ""); //49 출력
}
public event PropertyChangedEventHandler? PropertyChanged;
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}
RelayCommand.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
namespace WpfTriggerAndCommand.Commands
{
internal class RelayCommand<T> : ICommand
{
readonly Action<T> _execute;
readonly Predicate<T> _canexecute;
public RelayCommand(Action<T> action, Predicate<T> predicate)
{
_execute = action;
_canexecute = predicate;
}
//CanExecute에 위임할 수 없을때도 생성자 생성 가능
public RelayCommand(Action<T> action) : this(action, null)
{
}
public event EventHandler? CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public bool CanExecute(object? parameter)
{
return _canexecute == null ? true : _canexecute((T)parameter);
}
public void Execute(object? parameter)
{
_execute((T)parameter);
}
}
}
'C# Programming > WPF' 카테고리의 다른 글
[WPF] 디자인 깨질때 해결방법 (0) | 2024.05.16 |
---|---|
[WPF] Settings.settings 만들기 (0) | 2024.05.16 |
[WPF] 트리거(Trigger) (0) | 2024.05.16 |
[WPF] 스타일(Xaml 리소스) (0) | 2024.05.16 |
[WPF] 모델 생성과 바인딩 (0) | 2024.05.16 |