2021년 11월 21일 일요일

WPF Command의 이해 및 Command, 데이터바인딩 실습, WPF교육, WPF학원

 

WPF Command의 이해 및 Command, 데이터바인딩 실습, WPF교육, WPF학원

http://ojc.asia/bbs/board.php?bo_table=WPF&wr_id=173 


WPF Command의 이해 및 Command, 데이터바인딩 실습

WPF Command의 이해 및 Command, 데이터바인딩 실습전통적인 이벤트 기반 프로그래밍에서 컨트롤에 이벤트 핸들러 메소드를 코드 비하인드에서 연결하여 사용자의 이벤트를 처리했다. 그러나 이방식

ojc.asia


https://www.youtube.com/watch?v=68nzzq_bew0&list=PLxU-iZCqT52Cmj47aKB1T-SxI33YL7rYS&index=16&t=1s 


https://www.youtube.com/watch?v=OTMyi2XrVyw&list=PLxU-iZCqT52Cmj47aKB1T-SxI33YL7rYS&index=15&t=3s 

  • 전통적인 이벤트 기반 프로그래밍에서 컨트롤에 이벤트 핸들러 메소드를 코드 비하인드에서 연결하여 사용자의 이벤트를 처리했다. 그러나 이방식은 이벤트처리 핸들러를 재사용하거나 단위 테스트를 어렵게 한다.
  • XAML UI에서 버튼을 클릭시 MVVM에서는 Click 이벤트 핸들러를 이용하기 보다는 Commamd를 이용하기를 권장한다. 여러 버튼에서 하나의 Command를 공유할 수 있으므로 모든 컨트롤마다 Click 이벤트를 만드는 방법 보다는 효율적이기 때문이다.
  • WPF의 명령(Command)은 ICommand 인터페이스를 구현하여 만들며 ICommand는 Execute 및 CanExecute라는 두 가지 메서드와 CanExecuteChanged 이벤트를 제공한다. 
  • Execute 메서드는 실제 처리해야 하는 작업을 기술하고 CanExecute 메소드에서는 Execute 메소드의 코드를 실행할지 여부를 결정하는 코드를 기술한다. CanExecute가 false를 리턴하면 Execute 메소드는 호출되지 않는다.
  • 즉 CanExecute 메소드는 명령을 사용 가능하게 하거나 사용 불가능하게 할 때 사용되며 명령을 사용할 수 있는지 여부를 확인하기 위해 WPF에 의해 호출된다. 이 메소드는 키보드 GET포커스, LOST포커스, 마우스 업 등과 같은 UI 상호 작용 중에 대부분 발생한다. 
  • 사용자 정의 명령의 경우 CanExucute 메서드가 대부분의 시나리오에서 호출되지는 않으므로 어떤 조건에 따라 버튼을 활성화, 비활성화 해야 할 수도 있는데 ICommand 구현체에서 CanExecuteChanged 이벤트를 CommandManager의 RequerySuggested 이벤트에 연결하면 된다.
  • CanExecute 메소드가 호출되어 CanExecute의 상태가 변경되면 CanExecuteChanged 이벤트가 발생해야 하며,  WPF는 CanExecute를 호출하고 Command에 연결된 컨트롤의 상태를 변경한다.


// CanExecuteChanged 이벤트는 해당 ICommand에 바인딩 된 

// 모든 명령 소스(예 : Button 또는 MenuItem)에 

// CanExecute에 의해 반환 된 값이 변경 되었음을 알린다.


// 커맨드 소스는 일반적으로 상태를 적절히 업데이트해야 하는데

// 예를 들면 CanExecute()가 false를 반환하면 버튼이 비활성화 된다).


// CommandManager.RequerySuggested 이벤트는 CommandManager가 명령 실행에 

// 영향을 줄 수있는 변경 사항이 있다고 생각할 때마다 발생하며 이때마다 

// CanExecute가 호출된다.


// 예를 들어, 이는 포커스의 변화 일 수 있는데. 이 이벤트가 많이 발생한다.

// 따라서 본질적으로 이 코드의 역할은 CommandManager가 명령 실행 기능이 변경되었다고 생각할 때마다(실제로 변경되지 않은 경우에도) CanExecuteChanged를 발생시키는 것이다.

public event EventHandler CanExecuteChanged

{

            add { CommandManager.RequerySuggested += value; }

            remove { CommandManager.RequerySuggested -= value; } 

}

  • CommandManager.RequerySuggested 이벤트는 CanExecute 메서드를 강제로 실행할 수 있다. 
  • CanExecuteChanged 이벤트는 CommandManager의 RequerySuggested에 위임되어 모든 종류의 UI 상호작용을 통해 변경사항이 호출되는 정확한 알림을 제공한다.
  • RequerySuggested 이벤트의 CommandManager.InvalidateRequerySuggested()를 호출하여 CommandManager의 RequerySuggested 이벤트를 발생하도록 할 수도 있는데 다음 예제를 참조 하자.
  • Command 패턴에서는 몇가지 주체가 있는데 서비스를 요청하는 클라이언트(손님), 명령을 서술하는 Command Object(주문서), 명령을 요청하는 Command Invoker(웨이터), 특정 명령을 실제 처리하는 Command Receiver(Target, 요리사)가 있다.

[먼저 간단한 예제를 만들고 이해를 해보자.] 

  • 프로젝트 명 : CommandExam
  • [실행화면]
  • Model : [Emp.cs]

namespace CommandExam

{

    class Emp

    {

        public string Ename { getset; }

        public string Job { getset; }

public override string ToString()

        {

            return "[" + Ename + "," + Job + "]";

        }

    } 

}


  • Command Object : [RelayCommand.cs]



using System;

using System.Windows.Input;


namespace CommandExam

{

    class RelayCommand : ICommand

    {

        #region Variables

        Func<object, bool> canExecute;

        Action<object> executeAction;     

        #endregion


        #region Construction/Initialization

        public RelayCommand(Action<object> executeAction) : this(executeAction, null)

        {

        }


        public RelayCommand(Action<object> executeAction, Func<objectbool> canExecute)

        {

            //if (executeAction == null) throw new ArgumentNullException("Execute Action was null for ICommanding Operation.");

            //this.executeAction = executeAction;

            this.executeAction = executeAction ?? throw new ArgumentNullException("Execute Action was null for ICommanding Operation.");

            this.canExecute = canExecute;

        }

        #endregion


        #region ICommand Member

//CommandManager.RequerySuggested 이벤트가 호출될 때마다 실행

//즉 CanExecuteChanged 이벤트가 호출될 때마다 실행

        public bool CanExecute(object param)

        {

            // 사원이름을 입력하지 않으면 Add 버튼은 비활성화 된다.

            if (param?.ToString().Length == 0) return false;

            bool result = this.canExecute == null ? true : this.canExecute.Invoke(param);

            return result;

        }


        public void Execute(object param)

        {

            //System.Windows.MessageBox.Show(param.ToString());

            this.executeAction.Invoke(param);

        }

        public event EventHandler CanExecuteChanged

        {

            add { CommandManager.RequerySuggested += value; }

            remove { CommandManager.RequerySuggested -= value; }

        }

        #endregion

    }

}


  • Command Receiver : [MainWindowViewModel]


using System.Collections.ObjectModel;

using System.ComponentModel;

using System.Runtime.CompilerServices;


namespace CommandExam

{

    class MainWindowViewModel : INotifyPropertyChanged

    {

        public Emp _SelectedEmp;

        public Emp SelectedEmp

        {

            get

            {

                return _SelectedEmp;

            }

            set

            {

                _SelectedEmp = value;

                OnPropertyChanged("SelectedEmp");

            }

        }


        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged([CallerMemberName] string Pname = null)

        {

            PropertyChanged?.Invoke(thisnew PropertyChangedEventArgs(Pname));

        }


        public RelayCommand AddEmpCommand { getset; }


// 항목을 추가 하거나 제거할 때 알림을 제공 하는 컬렉션 클래스

        public ObservableCollection<Emp> Emps { getset; }


        public MainWindowViewModel()

        {

            Emps = new ObservableCollection<Emp>();

            Emps.Add(new Emp { Ename = "홍길동", Job = "Salesman" });

            Emps.Add(new Emp { Ename = "김길동", Job = "Clerk" });

            Emps.Add(new Emp { Ename = "정길동", Job = "Manager" });

            Emps.Add(new Emp { Ename = "박길동", Job = "Salesman" });

            Emps.Add(new Emp { Ename = "성길동", Job = "Clerk" });

            AddEmpCommand = new RelayCommand(AddEmp);

        }


        public void AddEmp(object param)

        {

            Emps.Add(new Emp { Ename = param.ToString(),Job="New Job"});

        }

    }

}


  • Client : [MainWindow.xaml], 여기서 Button은 Command Invoker


<Window x:Class="CommandExam.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:CommandExam"

        mc:Ignorable="d"

        Title="MainWindow" SizeToContent="Width">

    <Window.DataContext>

        <local:MainWindowViewModel/>

    </Window.DataContext>

    <StackPanel>

        <TextBlock>사원 이름을 입력하세요.</TextBlock>

        <TextBox x:Name="txtName"  Text=”{Binding SelectedEmp.Ename}”/>

        <Button Command="{Binding AddEmpCommand}" CommandParameter="{Binding Text, ElementName=txtName}">Add</Button>

        <ListBox ItemsSource="{Binding Emps}" 

                 SelectedItem="{Binding SelectedEmp}"

                 DisplayMemberPath="Ename"

                 x:Name="empListBox"/>

        <Label x:Name="label" Content="{Binding SelectedItem, ElementName=empListBox}" 

               HorizontalAlignment="Center" 

               Height="40" 

               Margin="10,0,0,0" Width="137"/>    

</StackPanel>

</Window>


  • 위 예제에서 Command Invoker는 MainWindow.xaml의 버튼 이며  Command Target(Receiver)은 MainWindowViewModel, ConcreteCommand Object는 RelayCommand 객체이다.


#MVVM#COMMAND패턴#WPFMVVM#MVVM이란#WPF강좌#WPF교육#WPF동영상#WPF학원

MVVM, Command패턴, WPFMVVM, MVVM이란, WPF강좌, WPF교육, WPF동영상, WPF학원

MVVM, Command패턴, WPFMVVM, MVVM이란, WPF강좌, WPF교육, WPF동영상, WPF학원

(WPF학원, WPF교육)WPF MVVM(Model-View-ViewModel) 이란?


https://www.youtube.com/watch?v=GAw8eSawrvE&list=PLxU-iZCqT52Cmj47aKB1T-SxI33YL7rYS&index=20&t=11s 


https://www.youtube.com/watch?v=K3v-A5d2fNI&list=PLxU-iZCqT52Cmj47aKB1T-SxI33YL7rYS&index=21&t=4s 

  • Model : 비즈니스 로직과 데이터를 캡슐화 한것이다.
  • View : 사용자가 보게 되는 화면을 정의하는 것이다.(XAML)
  • ViewModel : View를 나타내주기 위한 Model이며  프리젠테이션 로직과 뷰를 위한 데이터를 캡슐화하고 있다. 뷰와 뷰가 요구하는 모델 클래스들 간의 상호작용을 조직할 책임이 있으며 뷰가 표시하는 데이터와 ICommand를 구현한 것이다. View보다는 Model과 유사하게 디자인 되며, View에 바인딩 될 때 가장 강력하다. 
  • Model-View-ViewModel(MVVM) 패턴에 기반하여 XAML을 탄생시켰으며 기본 패턴은 View와 Model 이다(즉 ViewModel). XAML은 사용자 인터페이스와 (*.xaml) 기본데이터(Model)와의 연결은 코드 비하인드 C#(*.cs)으로 가능하도록 완벽한 분리를 해놓았다. View와 ViewModel은 XAML XML파일의 Data Binding 정의를 통해 연결될 수도 있으며 View(XAML)에 대한 BindingContext(DataContext, 소스객체)는 일반적으로 ViewModel의 인스턴스 이다.
  • Model-View-ViewModel(MVVM)



 

Model : 비즈니스 로직과 데이터를 캡슐화 한것이다.

View : 사용자가 보게 되는 화면을 정의하는 것이다.

ViewModel : View를 나타내주기 위한 Model이며  프리젠테이션 로직과 뷰를 위한 데이터를 캡슐화하고 있다. 뷰와 뷰가 요구하는 모델 클래스들 간의 상호작용을 조직할 책임이 있으며 뷰가 표시하는 데이터와 Command를 구현한 것이다. View보다는 Model과 유사하게 디자인 되며, View의 바인딩 될 때 가장 강력하다. ViewModel의 Property에 뷰가 바인딩 된다.


  • MVVM 패턴에서 모델은 데이터를 보유하는 단순한 클래스 객체로 속성 및 속성 유효성 검사 만 포함해야 한다. 데이터 가져 오기, 데이터 저장, 클릭 이벤트, 복잡한 계산, 비즈니스 규칙 또는 그와 같은 것들에 대한 책임이 없다. 
  • 뷰는 데이터를 표시하는 데 사용되는 UI 이며 뷰 모델(ViewModel)은 대부분의 코드 숨김, 데이터 액세스, 클릭 이벤트, 복잡한 계산, 비즈니스 규칙 유효성 검사 등이 여기에 해당되며 일반적으로 뷰(VIEW)를 반영하도록 빌드된다. 
  • 예를 들어 뷰에 객체를 담기위한 ListBox, 선택된 객체 및 저장 버튼이 있으면 ViewModel에 ObservableCollection ObectList, Model SelectedObject 및 ICommand SaveCommand가 있다.
#MVVM, #COMMAND패턴, #WPFMVVM, #MVVM이란, #WPF강좌, #WPF교육, #WPF동영상, #WPF학원


MVVM, Command패턴, WPFMVVM, MVVM이란, WPF강좌, WPF교육, WPF동영상, WPF학원

(C#교육동영상)C# ADO.NET 실습 ODP.NET/ODAC 설치 오라클 함수 호출 실습, C#학원, WPF학원, 닷넷학원, 자바학원

  (C#교육동영상)C# ADO.NET 실습  ODP.NET/ODAC 설치  오라클 함수 호출 실습, C#학원, WPF학원, 닷넷학원, 자바학원 https://www.youtube.com/watch?v=qIPU85yAlzc&list=PLxU-i...