[WPF] WPF DevExpress 실습
- C#/WPF
- 2022. 6. 17. 21:48
목적
- WPF DevExpress를 학습하고 실습합니다.
DevExpress BindableBase
- INotifyPropertyChanged interface 및 GetProperty 및 SetProperty Method로 Binding 가능한 Property를 쉽게 구현할 수 있는 기능을 지원하는 추상클래스이다.
- GetProperty Method : Property 이름을 기반으로 값을 가져온다.
- SetProperty Method : Property 이름을 키로 사용하여 UI에 값을 알려준다.
DevExpress ViewModelBase
- 런타임 및 디자인 타임 모드에 대해 개별적으로 속성 초기화
- View 내에 등록된 액세스 서비스
- View-Model 간에 데이터 전달
- Command Property 없이 Command 가능
요구사항
- 3장 프로젝트와 동일한 요구사항입니다.
실습
Converter
- MouseEventConverter.cs
using DevExpress.Mvvm.UI;
using DevExpress.Xpf.Grid;
using System.Windows.Input;
namespace MVVM.Converter
{
public class MouseEventConverter : EventArgsConverterBase<MouseEventArgs>
{
//MouseEvent를 받을 Convert 를 구현한다.
protected override object Convert(object sender, MouseEventArgs args)
{
var grid = sender as GridControl;
return args.GetPosition(grid);
}
}
}
Interface
- IDialogView.cs
namespace MVVM
{
public interface IDialogView
{
bool? ShowDialog();
bool? DialogResult { get; set; }
void Show();
void Close();
}
}
- IWindowView.cs
using System.Windows;
namespace MVVM
{
public interface IWindowView
{
void Show();
void Close();
Visibility Visibility { get; set; }
}
}
Model
- Person.cs
using DevExpress.Mvvm;
namespace MVVM
{
//BindableBase 클래스는
//Binding 가능한 Property 를 쉽게 구현할 수 있는 기능을 지원하는 추상 클래스이다.
public class Person : BindableBase
{
public string Name
{
get { return GetProperty(() => Name); }
set { SetProperty(() => Name, value); }
}
public bool Gender
{
get { return GetProperty(() => Gender); }
set { SetProperty(() => Gender, value); }
}
public string PhoneNumber
{
get { return GetProperty(() => PhoneNumber); }
set { SetProperty(() => PhoneNumber, value); }
}
public string Address
{
get { return GetProperty(() => Address); }
set { SetProperty(() => Address, value); }
}
public Person()
{
}
public Person(Person input)
{
Address = input.Address;
Name = input.Name;
PhoneNumber = input.PhoneNumber;
Gender = input.Gender;
}
}
}
View
- AddView.xaml
<dx:DXWindow x:Class="MVVM.AddView"
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:MVVM"
xmlns:dxlc="http://schemas.devexpress.com/winfx/2008/xaml/layoutcontrol"
xmlns:dx="http://schemas.devexpress.com/winfx/2008/xaml/core"
mc:Ignorable="d" Name="AddViewParam"
d:DataContext="{d:DesignInstance local:AddView}"
Title="{Binding Path=Caption,
UpdateSourceTrigger=PropertyChanged,
Mode=TwoWay}"
Height="300" Width="300"
WindowStartupLocation="CenterScreen"
WindowStyle="ToolWindow">
<dxlc:LayoutControl Orientation="Vertical" Padding="4">
<dxlc:LayoutGroup Orientation="Vertical">
<dxlc:LayoutItem Label="이름" VerticalAlignment="Top">
<TextBox Text="{Binding Path=PersonData.Name, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"/>
</dxlc:LayoutItem>
<dxlc:LayoutItem Label="성별" VerticalAlignment="Top">
<TextBox Text="{Binding Path=PersonData.Gender, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"/>
</dxlc:LayoutItem>
<dxlc:LayoutItem Label="전화번호" VerticalAlignment="Top">
<TextBox Text="{Binding Path=PersonData.PhoneNumber, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"/>
</dxlc:LayoutItem>
<dxlc:LayoutItem Label="주소" VerticalAlignment="Stretch">
<TextBox Text="{Binding Path=PersonData.Address, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"/>
</dxlc:LayoutItem>
</dxlc:LayoutGroup>
<dxlc:LayoutGroup VerticalAlignment="Bottom" HorizontalAlignment="Right"
Header="20">
<Button Content="확인"
Command="{Binding Path=OkCommand}"
CommandParameter="{Binding ElementName=AddViewParam}"
Width="75"/>
<Button Content="취소"
Command="{Binding Path=CancelCommand}"
CommandParameter="{Binding ElementName=AddViewParam}"
Width="75"/>
</dxlc:LayoutGroup>
</dxlc:LayoutControl>
</dx:DXWindow>
- AddView.xaml.cs
using DevExpress.Xpf.Core;
namespace MVVM
{
/// <summary>
/// AddView.xaml에 대한 상호 작용 논리
/// </summary>
public partial class AddView : DXWindow, IDialogView
{
public AddView(AddViewModel viewModel)
{
InitializeComponent();
this.DataContext = viewModel;
}
}
}
- MainView.xaml
<dx:DXWindow x:Class="MVVM.MainView"
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:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:dxlc="http://schemas.devexpress.com/winfx/2008/xaml/layoutcontrol"
xmlns:dxg="http://schemas.devexpress.com/winfx/2008/xaml/grid"
xmlns:dxmvvm="http://schemas.devexpress.com/winfx/2008/xaml/mvvm"
xmlns:dx="http://schemas.devexpress.com/winfx/2008/xaml/core"
xmlns:local="clr-namespace:MVVM"
xmlns:cv="clr-namespace:MVVM.Converter"
mc:Ignorable="d"
d:DataContext="{d:DesignInstance local:MainViewModel}"
Title="주소록 관리 V0.1" Height="328" Width="570"
WindowStartupLocation="CenterScreen" Name="MainViewParam">
<dxlc:LayoutControl Orientation="Vertical" Padding="4">
<dxg:GridControl EnableSmartColumnsGeneration="True"
Name="PersonParam"
ItemsSource="{Binding Path=Persons,
UpdateSourceTrigger=PropertyChanged,
Mode=OneWay}">
<dxmvvm:Interaction.Behaviors>
<dxmvvm:EventToCommand EventName="MouseDoubleClick"
Command="{Binding Path=ModifyCommand}"
CommandParameter="{Binding ElementName=PersonParam,
Path=SelectedItem}"/>
<dxmvvm:EventToCommand EventName="MouseMove"
Command="{Binding Path=MouseMoveCommand}"
PassEventArgsToCommand="True">
<dxmvvm:EventToCommand.EventArgsConverter>
<cv:MouseEventConverter/>
</dxmvvm:EventToCommand.EventArgsConverter>
</dxmvvm:EventToCommand>
</dxmvvm:Interaction.Behaviors>
<dxg:GridControl.Columns>
<dxg:GridColumn Header="이름" FieldName="Name" ReadOnly="True"
HorizontalHeaderContentAlignment="Center"/>
<dxg:GridColumn Header="성별" FieldName="Gender" ReadOnly="True"
HorizontalHeaderContentAlignment="Center"/>
<dxg:GridColumn Header="전화번호" FieldName="PhoneNumber" ReadOnly="True"
HorizontalHeaderContentAlignment="Center"/>
<dxg:GridColumn Header="주소" FieldName="Address" ReadOnly="True"
HorizontalHeaderContentAlignment="Center"/>
</dxg:GridControl.Columns>
<dxg:GridControl.View>
<dxg:TableView AllowPerPixelScrolling="False"
AllowHorizontalScrollingVirtualization="False"
AllowCascadeUpdate="False"
AllowEditing="False"
ShowAutoFilterRow="False"
ShowTotalSummary="False"
ShowGroupPanel="False"
UseAnimationWhenExpanding="False"
NewItemRowPosition="None"
ScrollingMode="Smart"
AutoWidth="True"
NavigationStyle="Row"
FadeSelectionOnLostFocus="False"/>
</dxg:GridControl.View>
</dxg:GridControl>
<dxlc:LayoutGroup VerticalAlignment="Bottom" Header="24">
<dxlc:LayoutGroup HorizontalAlignment="Left" VerticalAlignment="Center">
<dxlc:LayoutItem Label="Mouse X : ">
<TextBox Text="{Binding Path=MouseX, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
Width="50"/>
</dxlc:LayoutItem>
<dxlc:LayoutItem Label="Mouse Y : ">
<TextBox Text="{Binding Path=MouseY, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
Width="50"/>
</dxlc:LayoutItem>
</dxlc:LayoutGroup>
<dxlc:LayoutGroup HorizontalAlignment="Right">
<Button Command="{Binding Path=AddCommand}"
Content="추가" Width="75"/>
<Button Command="{Binding Path=ModifyCommand}"
CommandParameter="{Binding ElementName=PersonParam, Path=SelectedItem}"
Content="변경" Width="75"/>
<Button Command="{Binding Path=DeleteCommand}"
CommandParameter="{Binding ElementName=PersonParam, Path=SelectedItem}"
Content="삭제" Width="75"/>
<Button Command="{Binding Path=ExitCommand}"
CommandParameter="{Binding ElementName=MainViewParam}"
Content="종료" Width="75"/>
</dxlc:LayoutGroup>
</dxlc:LayoutGroup>
</dxlc:LayoutControl>
</dx:DXWindow>
- MainView.xaml.cs
using DevExpress.Xpf.Core;
namespace MVVM
{
///
/// MainView.xaml에 대한 상호 작용 논리
///
public partial class MainView : DXWindow, IWindowView
{
public MainView(MainViewModel viewModel)
{
InitializeComponent();
this.DataContext = viewModel;
}
}
}
## **ViewModel**
* **AddView.cs**
```c#
using DevExpress.Mvvm;
using System.Windows.Input;
namespace MVVM
{
// ViewModelBase를 상속 받는다.
// 데이터를 ViewModel에 전달하는데 사용하는 interface.
public class AddViewModel : ViewModelBase
{
public enum ViewType
{
Add,
Modify
}
public string Caption
{
get { return GetProperty(() => Caption); }
set { SetProperty(() => Caption, value); }
}
public Person PersonData { get; set; }
public ICommand OkCommand { get; private set; }
public ICommand CancelCommand { get; private set; }
public AddViewModel(Person Data = null, ViewType type = ViewType.Add)
{
if (type == ViewType.Add)
{
Caption = "추가";
}
else if (type == ViewType.Modify)
{
Caption = "변경";
}
else
{
Caption = "추가";
}
PersonData = Data;
OkCommand = new DelegateCommand<IDialogView>(view => _okCommandAction(view));
CancelCommand = new DelegateCommand<IDialogView>(view => _cancelCommandAction(view));
}
private void _okCommandAction(IDialogView view)
{
view.DialogResult = true;
view.Close();
}
private void _cancelCommandAction(IDialogView view)
{
view.DialogResult = false;
view.Close();
}
}
}
- MainView.cs
using DevExpress.Mvvm;
using System;
using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Input;
namespace MVVM
{
public class MainViewModel : ViewModelBase
{
public ObservableCollection<Person> Persons { get; set; }
public ICommand AddCommand { get; set; }
public ICommand DeleteCommand { get; set; }
public ICommand ModifyCommand { get; set; }
public ICommand ExitCommand { get; set; }
public ICommand MouseMoveCommand { get; set; }
private readonly IMessageBoxService _messageBoxService;
private readonly Func<Person, AddViewModel.ViewType, IDialogView> _createAddView;
public string MouseX
{
get { return GetProperty(() => MouseX); }
set { SetProperty(() => MouseX, value); }
}
public string MouseY
{
get { return GetProperty(() => MouseY); }
set { SetProperty(() => MouseY, value); }
}
public MainViewModel(IMessageBoxService messageBoxService
, Func<Person, AddViewModel.ViewType, IDialogView> createAddView)
{
_messageBoxService = messageBoxService;
_createAddView = createAddView;
Persons = new ObservableCollection<Person>();
_initCommand(); ;
_initTestData();
}
private void _initTestData()
{
Persons.Add(new Person() { Address = "test1", Name = "홍길동1", Gender = true, PhoneNumber = "11111" });
Persons.Add(new Person() { Address = "test2", Name = "홍길동2", Gender = true, PhoneNumber = "22222" });
Persons.Add(new Person() { Address = "test3", Name = "홍길동3", Gender = true, PhoneNumber = "33333" });
Persons.Add(new Person() { Address = "test4", Name = "홍길동4", Gender = true, PhoneNumber = "44444" });
}
private void _initCommand()
{
AddCommand = new DelegateCommand(_addCommandAction);
DeleteCommand = new DelegateCommand<Person>(data => _deleteCommandAction(data));
ModifyCommand = new DelegateCommand<Person>(data => _modifyCommandAction(data));
ExitCommand = new DelegateCommand<IWindowView>(view => _exitCommandAction(view));
MouseMoveCommand = new DelegateCommand<Point>(args => _mouseMoveCommand(args));
}
private void _mouseMoveCommand(Point currentPoint)
{
MouseX = $"{currentPoint.X}";
MouseY = $"{currentPoint.Y}";
}
private void _exitCommandAction(IWindowView view)
{
view.Close();
}
private void _modifyCommandAction(Person selectedItem)
{
if (selectedItem == null)
{
_messageBoxService.Show("선택된 데이터가 없습니다.", "주소록 v0.1", MessageBoxButton.OK, MessageBoxImage.Information);
return;
}
var modifyData = new Person(selectedItem);
IDialogView view = _createAddView(modifyData, AddViewModel.ViewType.Modify);
if (true == view.ShowDialog())
{
var selectedIndex = Persons.IndexOf(selectedItem);
Persons[selectedIndex] = modifyData;
}
}
private void _deleteCommandAction(Person selectedItem)
{
if (selectedItem == null)
{
_messageBoxService.Show("선택된 데이터가 없습니다.", "주소록 v0.1", MessageBoxButton.OK, MessageBoxImage.Information);
return;
}
var result = _messageBoxService.Show("선택된 데이터가 삭제 하시겠습니까?", "주소록 v0.1", MessageBoxButton.OKCancel, MessageBoxImage.Question);
if (result == MessageBoxResult.Cancel)
return;
Persons.Remove(selectedItem);
}
private void _addCommandAction()
{
var addData = new Person();
IDialogView view = _createAddView(addData, AddViewModel.ViewType.Add);
if (true == view.ShowDialog())
{
Persons.Add(addData);
}
}
}
}
Etc
- App.xaml
<Application x:Class="MVVM.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:MVVM">
<Application.Resources>
</Application.Resources>
</Application>
- App.xaml.cs
using DevExpress.Mvvm;
using DevExpress.Xpf.Core;
using System.Windows;
namespace MVVM
{
/// <summary>
/// App.xaml에 대한 상호 작용 논리
/// </summary>
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
ApplicationThemeHelper.ApplicationThemeName = Theme.VS2019DarkName;
IMessageBoxService messageBoxService = new DXMessageBoxService();
MainViewModel mainViewModel = new MainViewModel(messageBoxService, _createAddView);
MainView mainView = new MainView(mainViewModel);
mainView.Show();
}
protected override void OnExit(ExitEventArgs e)
{
base.OnExit(e);
}
private IDialogView _createAddView(Person modifyData, AddViewModel.ViewType type = AddViewModel.ViewType.Add)
{
IMessageBoxService messageBoxService = new DXMessageBoxService();
var viewModel = new AddViewModel(modifyData, type);
return new AddView(viewModel);
}
}
}
- 실행결과
728x90
'C# > WPF' 카테고리의 다른 글
[WPF] WPF DevExpress.ReactiveUI 실습 (0) | 2022.06.17 |
---|---|
2장. WPF MVVM 실습 (2) | 2022.06.16 |
1장. WPF Binding 이용하여 프로젝트 실습 (0) | 2022.06.16 |
[WPF] WPF 점선 그리기 (0) | 2022.01.06 |
[WPF 기본 문법] WPF TextBlock, Button 컨트롤 Style 사용하기 (0) | 2021.12.28 |
이 글을 공유하기