티스토리 뷰

반응형

2022.09.06 - [WPF .NET] - MVVM Pattern을 사용하는 개발자를 위한 안내v1.0 part9-2 StyleSelector

2022.08.31 - [WPF .NET] - MVVM Pattern을 사용하는 개발자를 위한 안내 v1.0 part9-1 DataTemplateSelector

2022.08.08 - [WPF .NET] - MVVM Pattern을 사용하는 개발자를 위한 안내 v1.0 part8-3 Template

2022.08.02 - [WPF .NET] - MVVM Pattern을 사용하는 개발자를 위한 안내 v1.0 part8-2 Template

2022.07.21 - [WPF .NET] - MVVM Pattern을 사용하는 개발자를 위한 안내 v1.0 part8-1 Template

2022.07.13 - [WPF .NET] - MVVM Pattern을 사용하는 개발자를 위한 안내 v1.0 part7 Behavior

2022.07.05 - [WPF .NET] - MVVM Pattern을 사용하는 개발자를 위한 안내 V1.0 part6 Command

2022.06.27 - [WPF .NET] - MVVM Pattern을 사용하는 개발자를 위한 안내 V1.0 part5 Converter

2022.06.15 - [WPF .NET] - MVVM Pattern을 사용하는 개발자를 위한 안내 V1.0 part4-2 Data Binding

2022.06.13 - [WPF .NET] - MVVM Pattern을 사용하는 개발자를 위한 안내 V1.0 part4-1 Data Binding

2022.06.07 - [WPF .NET] - MVVM Pattern을 사용하는 개발자를 위한 안내 V1.0 part3-3

2022.06.02 - [WPF .NET] - MVVM Pattern을 사용하는 개발자를 위한 안내 V1.0 part3-2

2022.05.30 - [WPF .NET] - MVVM Pattern을 사용하는 개발자를 위한 안내 V1.0 part3-1

2022.05.11 - [WPF .NET] - MVVM Pattern을 사용하는 개발자를 위한 안내 v1.0 part2

2022.05.09 - [WPF .NET] - MVVM Pattern을 사용하는 개발자를 위한 안내 v1.0 part1

MVVM Pattern에서 가장 중요하면서, 어려워하는 부분 중에 하나로 자세하게 설명하도록 하겠습니다.

1. Data Binding concepts

바인딩을 하기위해서는 반드시 아래의 구성 요소들이 필요합니다.

  • 구성
    • target object​ (대상 객체)
      • Control, Custom Behavior etc.
      • 주로 컨트롤이 대상 객체가되지만, Behavior나 CollectionViewSource 등 XAML에서 표현할 수 있는 대부분의 객체가 대상 객체가 될 수 있습니다.
    • target property (대상 속성)
      • 대상 객체의 의존성 속성(Dependency Property)만 대상 속성이 될 수 있습니다.
      • 컨트롤의 대부분의 속성은 의존성 속성이지만, DataGrid의 SelectedItems 속성은 의존성 속성이 아니기 때문에, 바인딩을 할 수 없습니다.
      • Behavior나 사용자 클래스에서 Dependency Property를 만들어서 대상 속성으로 사용할 수 있습니다.
    • A binding source (바인딩 원본)
      • ViewModel, StaticResource, Control
      • 바인딩 원본은 다른 컨트롤 객체, ViewModel 객체, ResourceDicinary의 객체 등 object(객체)만 될 수 있습니다.
    • A path
      • 바인딩 원본에서 연결하려는 정확한 프로퍼티명
      • 프로퍼티가 INotifyPropertyChanged 이벤트를 발생시킬 수 있다면, 값이 변경되었을 때 대상 객체의 속성이 함께 변경됩니다.
      • EditMember.Id라고 입력하면, ViewModel에 EditMember 프로퍼티의 Id라는 프로퍼티를 이야기합니다.

2. Direction of the data flow

  • Mode
    • OneTime
      • 한번만 바인딩되며, 거의 사용하지 않습니다.
    • OneWay
      • 바인딩 원본에서 대상 속성으로만 값이 전달됩니다.
      • 대상 속성값이 변경되어도, 바인딩 원본의 값에 영향을 주지 않습니다.
    • TwoWay
      • 바인딩 원본과 대상 속성 양방향으로 값이 전달됩니다.
    • OneWayToSource
      • 대상 속성에서 바인딩 원본으로만 값이 전달됩니다.
      • WPF에서만 제공됩니다.
  • Detect source changes
    • OneWay, TwoWay
      • Source -> Target
      • INotifyPropertyChanged 이벤트가 발생될 때 값이 전달됩니다.
    • TwoWay
      • Target -> Source
      • UpdateTrigger에 지정된 이벤트가 발생할 때 값이 전달됩니다.

3. What triggers source updates

  • UpdateSourceTrigger
    • Default
      • 컨트롤에 따라 기본 이벤트가 다름
      • UpdateSourceTrigger를 지정하지 않는 경우 Default가 사용됩니다.
    • Explict
      • 코드를 이용해서 명시적으로 업데이트
      • TwoWay에서 바인딩 원본을 선택적으로 업데이트를 해야하는 경우 사용됩니다.
    • LostFocus
      • 이벤트 발생했을 때 업데이트
      • TextBox.Text 프로퍼티의 기본 값입니다.
    • PropertyChanged
      • Target Property가 변경되었을 때
      • 일반적인 컨트롤 프로퍼티의 기본 값입니다.

4. Binding Source

  • 반드시 아래 4가지 중 1가지 방법만으로 바인딩 원본을 정해야 합니다.
  •  DataContext
    • 기본 바인딩 소스가 되는 프로퍼티입니다. 주로 ViewModel과 Model 객체가 입력됩니다.
    • <DataGridTextColumn Binding="{Binding Name}" Header="Name" />
  • Source
    • 특정 위치있는 객체를 지정하기 위해서 사용합니다.
    • StaticResource의 객체를 지정하는데 주로 사용됩니다.
    • <TextBlock Text="{Binding Source={StaticResource DR}, Path=[wrd_Hello]}" />
  • RelativeSource (WPF Only)
    • Style, ControlTemplate, ItemTemplate 등을 만들 때 사용됩니다.
    • Visual Tree의 현재 컨트롤의 Parent 컨트롤 중 특정 컨트롤을 찾아 프로퍼티를 이용합니다.
    • <WrapPanel Width="{Binding RelativeSource={RelativeSource AncestorType=ScrollContentPresenter}, Path=ActualWidth}" />
  • ElementName
    • 다른 컨트롤의 x:Name을 사용해서 대상 객체로 지정하고, 프로퍼티를 사용합니다.
    • <TextBox Text="{Binding ElementName=listBox, Path=SelectedItem.ID />

5. DataContext를 바인딩 원본으로 사용하기

아래와 같은 화면이 있고, 이 화면 각 컨트롤들에 바인딩을 하려고 한다고 가정해 보겠습니다.

여러분은 뷰에는 하나의 뷰모델이 존재한다는 것을 알고 있기 때문에 하나의 뷰모델을 만들었고, 뷰모델은 DataContext에 넣어야 한다고 배웠기 때문에 아마, DataContext에 어떻게든 넣었을 것입니다. 그렇쵸?

그런데, Window.DataContext에 MainViewModel을 객체화 시켜서 넣었는데..다른 컨트롤들은 어떻게 MainViewModel의 속성을 사용하는 것일까요?

그 이유는 WPF의 속성 값 상속이란 기능을 이용하기 때문입니다.

  • 우린 Window.DataContext 한곳에만 넣었지만, Window 하위 컨트롤들이 상위 컨트롤의 DataContext 값을 이용할 수 있게됩니다. 
  • ComboBox.DataContext는 Window.DataContext 값을 사용할 수 있지만, ComboBoxItem은 그 것을 사용할 수 없습니다. DataGrid도 동일하게 동작합니다. 그 이유는... 아시죠?
  • 만약, Grid.DataContext에 PopupViewModel 객체를 만들어서 입력한다면, Grid와 그 하위 컨트롤들은 더 이상 MainViewModel을 사용하지 않게됩니다.

소스와 함께 비교해 보도록 하겠습니다.

  • MainViewModel을 Window.DataContext에 입력합니다.
  • DataGrid의 ItemsSource="{Binding People}" 이라고 바인딩을 했으니 DataContext가 Binding Source로 사용됩니다.
  • DataGrid.DataContext는 Window.DataContext를 사용할 수 있습니다.
  • Window.DataContext는 처음에 MainViewModel을 객체화해서 넣어 놓았으니..
  • People은 MainViewModel의 People라는 속성 값을 이용하게되는 것입니다.
  • People은 IList<Person> 형이기 때문에, 여러개의 Person을 가지고 있고, DataGrid는 DataGridRow라는 녀석에게 Person 하나 하나를 표시하도록 하기 때문에
  • DataGridRow.DataContext는 Person 객체가 들어가 있게됩니다.

제 능력으로는 더 이상 자세한 설명을 할 수 없을 것 같습니다. 흑흑

그래도, DataContext를 바인딩 소스로 사용하는 것에 대해서 이해가 않되는 부분은 리플로 남겨주시면 답변드리겠습니다.

여기서 설명하지 않은 내용 중 한가지는 Window.DataContext에 MainViewModel을 객체화해서 넣는 부분인데.. 그동안 제 소스를 보신 분들은 아실 것이라고 생각되서 이번에는 설명을 추가하지 않았습니다~

6. 소스

WpfTest/BindingSample at master · kaki104/WpfTest (github.com)

 

GitHub - kaki104/WpfTest

Contribute to kaki104/WpfTest development by creating an account on GitHub.

github.com

 

반응형
댓글