hoony's web study

728x90
반응형


WPF가 대세이면서두 어쩌면 제일 개발자의 기본은 데이터바인딩 아닐까요?
MSDN에 모처럼 좋은 자료가 있어서 발췌해서 올립니다.

저자: Shawn Wildermuth

2006 년 5 월

적용 대상:
   Microsoft Windows Presentation Foundation

요약: XAML 베이스의 데이터 바인딩을 사용하여, Microsoft Windows Presentation Foundation 프로젝트에서 데이터 조작 방법을 설명합니다.

목차

시작
XAML 바인드 개요
마무리
참고 자료

시작

Microsoft Windows Presentation Foundation (WPF/코드명Avalon)를 사용하여 리치 클라이언트용 사용자 인터페이스를 전혀 새로운 방법으로 개발할 수 있습니다. WPF 에서는 유저인터페이스의 설계가 처음으로 코드와 분리됩니다. ASP.NET과 같이 마크 업과 코드가 일반적으로 다른 파일에 존재하는 것을 의미합니다. 다만 이러한 분리는 컴파일 할 때만 입니다. 마크업 파일은 코드로 변환되고 원래의 코드 파일과 조합되어서 응용프로그램이 작성됩니다.

마이크로소프트는 설계를 쉽게 할 수 있도록 XAML이라는 리치한 마크업 언어를 개발했습니다. XAML는 XML 베이스의 마크업 언어이며, 2-D 및 3-D 도면, 애니메이션, 컨트롤 함유, 컨트롤과 문서의 플로라는 다양한 사용자 인터페이스 개념과 리치한 데이터 바인드 모델을 네이티브로 지원하는 응용 프로그램을 개발을 위한 새로운 모델 있니다. 이 글에서는 WPF 의 데이터 바인드 개요를 설명합니다. 이 글은 독자가 WPF 에 대한 어느 정도의 지식을 가지고 있다는 것을 전제로 쓰여져 있습니다. WPF의 개요가 궁금하신 분은 Hitchhiker's Guide to WPF Beta 1 (영문)를 참조하세요.

데이터 바인딩을 사용하는 이유

WPF를 처음 시작할 때, 프로젝트의 대부분의 데이터 조작을 실행하는 코드만 쓰는 것이 간단하다고 생각할지도 모릅니다. 하지만 XAML 베이스의 데이터 바인딩에 익숙해지면 훨씬 더 편리하다는 것을 알 수 있을 것입니다. 간단한 예를 봅시다.

그림 1은 단순한 WPF 프로젝트용의 사용자 인터페이스를 보여줍니다. 이것은 RSS 피드의 에디터이며, 사용자가 피드를 표시하고 편집할 수 있습니다.

Click here for larger image

그림 1. RSS 에디터의 예 (그림을 클릭하면 크게 표시됩니다.)

다음의 XAML 코드를 보면 에디터의 레이아웃이 비교적 단순하다는 것을 알 수 있습니다.

<Window x:Class="ExampleCS.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="ExampleCS"
    Loaded="Window1_Loaded"
    >
  <StackPanel>
    <TextBlock HorizontalAlignment="Center" 
          FontWeight="Bold">
      BlogEditor
    </TextBlock>
    <StackPanel Orientation="Horizontal" 
           HorizontalAlignment="Center">
      <ListBox Name="entryListBox" 
          Height="300" 
          SelectionChanged="entryListBox_Changed"/>
      <Grid Width="500" Margin="5">
        <Grid.ColumnDefinitions>
          <ColumnDefinition Width="50" />
          <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
          <RowDefinition Height="25" />
          <RowDefinition Height="25" />
          <RowDefinition Height="25" />
          <RowDefinition Height="*" />
          <RowDefinition Height="25" />
        </Grid.RowDefinitions>
        <TextBlock Grid.Row="0" Grid.Column="0">Title:</TextBlock>
        <TextBox Grid.Row="0" Grid.Column="1" Name="titleText" />
        <TextBlock Grid.Row="1" Grid.Column="0">Url:</TextBlock>
        <TextBox Grid.Row="1" Grid.Column="1" Name="urlText" />
        <TextBlock Grid.Row="2" Grid.Column="0">Date:</TextBlock>
        <TextBox Grid.Row="2" Grid.Column="1" Name="dateText" />
        <TextBlock Grid.Row="3" Grid.Column="0">Body:</TextBlock>
        <TextBox Grid.Row="3" Grid.Column="1" 
            Name="bodyText" 
            TextWrapping="Wrap" />
        <Button Grid.Row="4" 
                  Grid.ColumnSpan="2" 
                  Grid.Column="1"
            Click="updateButton_Click">
          Update
        </Button>
      </Grid>
    </StackPanel>
  </StackPanel>
</Window>

굵은 글씨로 나타난 이벤트 처리기에 주목해 주세요. 코드 대부분은 이 부분에서 실행되어 RSS 피드를 읽어 WPF 컨트롤을 입력합니다.

C#

XmlDocument blog = new XmlDocument();
const string BLOGURL = @"z:\adoguy.RSS";

public Window1()
{
  InitializeComponent();
  blog.Load(BLOGURL);
}

void Window1_Loaded(object sender, RoutedEventArgs e) 
{
  FillListBox();
}

void FillListBox()
{
  entryListBox.Items.Clear();

  XmlNodeList nodes = blog.SelectNodes("//item");
  foreach (XmlNode node in nodes)
  {
    ListBoxItem item = new ListBoxItem();
    item.Tag = node;
    item.Content = node["title"].InnerText;
    entryListBox.Items.Add(item);
  }
}

Visual Basic .NET

  Dim blog As New XmlDocument
  Const BLOGURL As String = "z:\adoguy.RSS"

  Public Sub New()
    InitializeComponent()
    blog.Load(BLOGURL)
  End Sub

  Sub Window1_Loaded(ByVal sender As Object, _
                     ByVal e As RoutedEventArgs) 
    FillListBox()

  End Sub

  Sub FillListBox()

    entryListBox.Items.Clear()

    Dim nodes As XmlNodeList = blog.SelectNodes("//item")

    For Each node As XmlNode In nodes

      Dim item As New ListBoxItem
      item.Tag = node
      item.Content = node("title").InnerText
      entryListBox.Items.Add(item)

    Next

  End Sub

이 코드에서는 RSS 피드가 있는 XML 문서를 읽고, ListBox의 모든 엔트리 타이틀을 쓰고 있습니다.

다음은 ListBox에서 선택 동작을 지정합니다.

C#

void entryListBox_Changed(object sender, RoutedEventArgs e)
{
  if (entryListBox.SelectedIndex != -1)
  {
    XmlNode node = ((ListBoxItem)entryListBox.SelectedItem).Tag as XmlNode;
    if (node != null)
    {
      titleText.Text = node["title"].InnerText;
      urlText.Text = node["guid"].InnerText;
      dateText.Text = node["pubDate"].InnerText;
      bodyText.Text = node["description"].InnerText;
    }
  }
}

Visual Basic .NET

  Sub entryListBox_Changed(ByVal sender As Object, _
                           ByVal e As SelectionChangedEventArgs) 

    If entryListBox.SelectedIndex <> -1 Then

      Dim node As XmlNode = CType(entryListBox.SelectedItem, ListBoxItem).Tag
      If Not node Is Nothing Then

        titleText.Text = node("title").InnerText
        urlText.Text = node("guid").InnerText
        dateText.Text = node("pubDate").InnerText
        bodyText.Text = node("description").InnerText

      End If

    End If

  End Sub

ListBox가 변경되었을 때, 선택된 RSS 피드 항목의 내부 텍스트를 구하여 TextBox에 기록합니다. 또 ListBoxItem 와 함께 노드 복사본를 보존하여, 각 이벤트 처리기에 도달하기 위한 캐스팅이 필요하다는 점에 주의하세요.

마지막으로 Update 버튼이 클릭되었을 때의 동작을 지정합니다.

C#

void updateButton_Click(object sender, RoutedEventArgs e)
{
  if (entryListBox.SelectedIndex != -1)
  {
    XmlNode node = ((ListBoxItem)entryListBox.SelectedItem).Tag as XmlNode;
    if (node != null)
    {
      node["title"].InnerText = titleText.Text;
      node["guid"].InnerText = urlText.Text;
      node["pubDate"].InnerText = dateText.Text;
      node["description"].InnerText = bodyText.Text;

      blog.Save(BLOGURL);

      FillListBox();
    }
  }
}

Visual Basic .NET

  Sub updateButton_Click(ByVal sender As Object, _
                         ByVal e As RoutedEventArgs)

    If entryListBox.SelectedIndex <> -1 Then

      Dim node As XmlNode = CType(entryListBox.SelectedItem, ListBoxItem).Tag

      If Not node Is Nothing Then

        node("title").InnerText = titleText.Text
        node("guid").InnerText = urlText.Text
        node("pubDate").InnerText = dateText.Text
        node("description").InnerText = bodyText.Text

        blog.Save(BLOGURL)

        FillListBox()

      End If

    End If

  End Sub

여기에서는 새로운 정보를 사용하여 노드를 갱신하여, XML 문서를 보존하고, 타이틀이 변경되었을 경우에는ListBox 가 재기입 하도록 합니다. 꽤 작고 단순한 응용 프로그램이지만, 대량의 코드를 필요로 합니다. XAML의 데이터 바인드를 사용하면, 더 간단하게 됩니다. 다음은 XAML의 데이터 바인딩을 사용하여, 같은 프로젝트를 XAML로 쓴 예를 나타냅니다.

<StackPanel 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  >
  <StackPanel.Resources>
    <XmlDataProvider x:Key="RssFeed" Source="z:\adoguy.RSS" />
  </StackPanel.Resources>
  <TextBlock HorizontalAlignment="Center" 
      FontWeight="Bold">
    Blog Editor
  </TextBlock>
  <StackPanel Orientation="Horizontal" 
    HorizontalAlignment="Center">
    <ListBox Name="entryListBox" 
        Height="300" 
        ItemsSource="{Binding Source={StaticResource RssFeed}, XPath=//item}"
    >
      <ListBox.ItemTemplate>
        <DataTemplate>
          <TextBlock Text="{Binding XPath=title}" />
        </DataTemplate>
      </ListBox.ItemTemplate>
    </ListBox>
    <Grid Width="500" 
        Margin="5" 
        DataContext="{Binding ElementName=entryListBox, Path=SelectedItem}" >
      <Grid.ColumnDefinitions>
        <ColumnDefinition Width="50" />
        <ColumnDefinition Width="*" />
      </Grid.ColumnDefinitions>
      <Grid.RowDefinitions>
        <RowDefinition Height="25" />
        <RowDefinition Height="25" />
        <RowDefinition Height="25" />
        <RowDefinition Height="*" />
        <RowDefinition Height="25" />
      </Grid.RowDefinitions>
      <TextBlock Grid.Row="0" Grid.Column="0">Title:</TextBlock>
      <TextBox Grid.Row="0" Grid.Column="1" 
          Name="titleText" 
          Text="{Binding XPath=title}" />
      <TextBlock Grid.Row="1" Grid.Column="0">Url:</TextBlock>
      <TextBox Grid.Row="1" Grid.Column="1" 
          Name="urlText" 
          Text="{Binding XPath=guid}" />
      <TextBlock Grid.Row="2" Grid.Column="0">Date:</TextBlock>
      <TextBox Grid.Row="2" Grid.Column="1" 
          Name="dateText" 
          Text="{Binding XPath=pubDate}" />
      <TextBlock Grid.Row="3" Grid.Column="0">Body:</TextBlock>
      <TextBox Grid.Row="3" Grid.Column="1" 
          Name="bodyText" 
          TextWrapping="Wrap" 
          Text="{Binding XPath=description}" />
      <Button Grid.Row="4" Grid.ColumnSpan="2" Grid.Column="1" >
          Update
      </Button>
    </Grid>
  </StackPanel>
</StackPanel>

XAML은 부속되는 코드 없이 동작합니다. 그림2는 XAML 만으로 동작하는 응용 프로그램의 예입니다 (XAMLPad 를 사용).

Click here for larger image

그림 2. XAMLPad의 RSS 에디터 (그림을 클릭하면 크게 표시됩니다.)

의아하게 생각할지도 모르겠지만, 이유는 XAML 바인딩을 사용하여 대부분의 처리를 자동적으로 실행하기 때문입니다. XAML의 개개의 기능은 다음에 자세히 설명하고, 데이터 바인드의 각 부분을 검증하여 그 원리를 설명합니다.

우선 XmlDataProvider 오브젝트를 작성해, 에디터에 XML 문서를 읽어 관리합니다.

<XmlDataProvider x:Key="RssFeed" Source="z:\adoguy.RSS" />

이렇게 하여 Z: 드라이브에서 XML 문서를 폼에 기록된 순서대로 읽어 들이도록 XAML 에 지시합니다.

다음은 ListBox를 바인드 합니다.

<ListBox Name="entryListBox" 
        Height="300" 
        ItemsSource="{Binding Source={StaticResource RssFeed}, XPath=//item}"
    >

이렇게하여 XAML에게 RssFeed의 리소스를, 그것을 데이터 소스로서 사용할 수 있도록 리스트 박스에 지시합니다. 게다가 바인드 하는 항목의 리스트 (이 경우, 문서내의 모든 항목 요소)를 XPath식에서 취득하여 리스트 박스에 지시합니다.

다음은 데이터 템플릿을 지정하여 리스트 박스의 항목으로 무엇을 표시하는지를 지정합니다.

<DataTemplate>
  <TextBlock Text="{Binding XPath=title}" />
</DataTemplate>

각 항목의 TextBlock 오브젝트를 작성하여, XPath를 사용하여 TextBlock에 표시할 내용을 판단하도록 ListBox 에 지시합니다.

다음은 모든 상세를 포함한 그리드를 바인드 합니다.

<Grid Width="500" 
        Margin="5" 
        DataContext="{Binding ElementName=entryListBox, Path=SelectedItem}" >

여기에서는 ListBox 의 특정 항목에 컨테이너 (이 경우 Grid)를 바인드 하도록 XAML 에 지시하고 있습니다. 외부의 데이터가 아닌, XAML 문서내의 컨트롤에 바인드 하기 위해서, Source 가 아닌 ElementName를 사용합니다. DataContext를 설정함으로써 Grid 안의 모든 컨트롤이 같은 오브젝트 (이 경우 SelectedItem)로 설정되도록 합니다.

다음은 각 TextBox를 각각 필요한 XML 문서의 부분에 바인드 합니다.

<TextBlock Grid.Row="0" Grid.Column="0">Title:</TextBlock>
      <TextBox Grid.Row="0" Grid.Column="1" 
          Name="titleText" 
          Text="{Binding XPath=title}" />
      <TextBlock Grid.Row="1" Grid.Column="0">Url:</TextBlock>
      <TextBox Grid.Row="1" Grid.Column="1" 
          Name="urlText" 
          Text="{Binding XPath=guid}" />
      <TextBlock Grid.Row="2" Grid.Column="0">Date:</TextBlock>
      <TextBox Grid.Row="2" Grid.Column="1" 
          Name="dateText" 
          Text="{Binding XPath=pubDate}" />
      <TextBlock Grid.Row="3" Grid.Column="0">Body:</TextBlock>
      <TextBox Grid.Row="3" Grid.Column="1" 
          Name="bodyText" 
          TextWrapping="Wrap" 
          Text="{Binding XPath=description}" />

이미 DataContext 를 설정하고 있기 때문에, XPath 식을 지정하는 것만으로 개개의 필요한 RSS 피드를 취득할 수 있습니다.

이상의 내용은 한번에 모든 것을 이해하기는 어려울지도 모릅니다. 모든 것을 한 번에 기억할 필요는 없습니다. 다음의 항에서는 상기의 예에 나온 다양한 개념을 알기 쉬운 형태로 하나씩 소개합니다.

XAML바인딩 개요

Binding 오브젝트의 작용을 나타내는 단순한 예를 나타냅니다. 다음의 매우 단순한 XAML 문서를 봐 주세요.

<Window 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  >
  <Canvas>
    <TextBox Text="This is a TextBox" />
    <TextBlock Canvas.Top="25" >Test</TextBlock>
  </Canvas>
</Window>

그림3 의 이 문서는 두 개의 컨트롤이 있는 단순한 캔버스를 작성합니다.

그림 3. 단순한 XAML 캔버스

TextBlock을 바인드 하고, TextBox 텍스트가 입력된 대로 표시하고 싶다고 가정합니다. 두개의 오브젝트를 연결시키는 Binding 오브젝트가 필요합니다. 우선 TextBox 에 이름을 붙여 요소의 이름으로 참조할 수 있도록 합니다.

<TextBox Name="theTextBox" />

다음은 TextBlockText 요소에 Binding 를 추가해야 합니다.

<TextBlock Canvas.Top="25">
  <TextBlock.Text>
    <Binding ElementName="theTextBox" Path="Text" />
  </TextBlock.Text>
</TextBlock>

이렇게 하여 TextBlockText를 사용자가 theTextBox 컨트롤에 입력한 내용으로 설정하도록 지시합니다.

이상을 정리하면, 다음의 코드가 됩니다.

<Window 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  >
  <Canvas>
    <TextBox Name="theTextBox" Text="Hello" />
    <TextBlock Canvas.Top="25">
      <TextBlock.Text>
        <Binding ElementName="theTextBox" Path="Text" />
      </TextBlock.Text>
    </TextBlock>
  </Canvas>
</Window>

이 XAML는 그림4와 같이 TextBox에 입력된 내용을 반영해 TextBlock를 변경하는 폼을 작성합니다.

그림 4. 바인드 된 컨트롤

첫 바인드가 성공했지만 이 XML구문은 약간 장황합니다. 좀 더 간편한 방법이 있을 것입니다.

바인드 간략 표기 사용

앞의 예에서는 속성에 Binding 요소를 추가하여 데이터 바인딩을 작성하는 방법이었습니다. 이와 같이 단순한 예서는 이러한 방법의 데이터 바인딩을 실시하는 것이 그다지 귀찮게 느껴지지 않습니다. 그러나, XAML 문서가 커지면, 이러한 장황한 구문이 번거로워질 수도 있습니다. 이 문제를 줄이기 위해서 XAML는 바인드 구문의 간략화 버전을 지원합니다.

예를 들어, 간략 표기를 사용하면 앞의 예는 다음과 같이 됩니다.

<Window 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  >
  <Canvas>
    <TextBox Name="theTextBox" Text="Hello" />
    <TextBlock Canvas.Top="25"
               Text="{Binding ElementName=theTextBox, Path=Text}" />
  </Canvas>
</Window>

간략화 구문은 중괄호 ({})로 전후로 묶고, Binding 에서 시작하여 바인드의 속성으로 이름/값을 지정합니다. 이 간략화 구문의 목적은 적은 키스트로크(keystroke)로, 읽기 쉬운 형태로의 데이터바인드를 지정하기 위해서입니다. 앞으로는 간략화 구문 사용하겠습니다.

바인딩 소스

지금까지는 바인딩의 모든 예로 별도의 컨트롤 소스를 사용했습니다. 그러나 XAML 베이스의 대부분의 프로젝트에서는 다른 컨트롤 이외의 소스에 바인드하게 됩니다. 대부분의 데이터 바인딩에서 중요한 것이 Source 속성입니다. 지금까지의 예에서는 Source 속성을 사용하는 대신에 ElementName 속성을 사용하여 컨트롤에 바인드 하고 있습니다. 대부분의 응용 프로그램에서는 XML 오브젝트나 .NET 오브젝트 등 보다 중요한 소스에 바인드 해야 한다고 생각합니다. XAML는 데이터 Provider 오브젝트로 이것을 지원 합니다. XAML 에는 ObjectDataProviderXmlDataProvider 의 두종류의 데이터 공급자를 내장 하고 있습니다. ObjectDataProvider와 .NET 오브젝트와의 사이의 바인드에 사용하여, XmlDataProvider 는 XML fragment 및 문서와의 바인딩에 사용합니다. 데이터 공급자는 모든 XAML 컨테이너의 리소스 섹션에서 지정 가능합니다.

XmlDataProvider 사용

다음은 XmlDataProvider 오브젝트를 사용하는 예를 나타냅니다.

<StackPanel 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  >
  <StackPanel.Resources>
    <XmlDataProvider x:Key="FavoriteColors">
      <x:XData>
        <Colors xmlns="">
          <Color>Blue</Color> 
          <Color>Black</Color> 
          <Color>Green</Color> 
          <Color>Red</Color> 
        </Colors>
      </x:XData>
    </XmlDataProvider>
  </StackPanel.Resources>
  <TextBlock HorizontalAlignment="Center" 
             FontWeight="Bold">
    XML Example
  </TextBlock>
  <ListBox Width="200" Height="300" 
           ItemsSource="{Binding Source={StaticResource FavoriteColors}, 
           XPath=/Colors/Color}">
  </ListBox>
</StackPanel>

StackPanel의 리소스안에 XmlDataProvider 오브젝트가 있습니다. x:KeyBinding 오브젝트내에서 이것을 참조하기 위해 사용하는 이름을 말합니다. 공급자의 내부에는 데이터 바인드의 소스로 사용하기 위해서 XML 를 인 라인으로 작성합니다. 인 라인 데이터를 사용하려면, 코드에 나타나듯이, 그 데이터를 XData 요소로 묶을 필요가 있습니다. ListBox Binding 에서 이 공급자를 바인드 Source 로 지정합니다. 데이터 소스가 XAML 문서내에 존재하는 경우, 코드에 나타나듯이 그 오브젝트는 정적 리소스로 지정할 필요가 있습니다. 마지막으로 XPath 스테이트먼트를 사용하고, ListBox에 쓰기 위해서 필요한 XML 문서내의 집합을 지정합니다. 이 코드에 의해, 그림5 의 폼이 생성됩니다.

그림 5. XML 의 데이터 바인딩

같은 폼을 작성하기 위해, 공급자가 패스 또는 URL를 사용하여 XML 의 소스를 검색하도록 지정할 수도 있습니다. XmlDataProviderSource 속성을 지정합니다.

<XmlDataProvider x:Key="FavoriteColors" 
                 Source="D:\Writing\msdn\avalondatabindingpt1\xaml\colors.xml"
/>

XmlDataProviderSource 속성에는 표준적인 URL를 지정하고, RSS 등의 XML API 에 신속히 액세스 할 수도 있습니다.

<StackPanel 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  >
  <StackPanel.Resources>
    <XmlDataProvider x:Key="MyRSS" 
      Source="http://adoguy.com/RSS"
    />
  </StackPanel.Resources>
  <TextBlock HorizontalAlignment="Center" 
             FontWeight="Bold">
    XML Example
  </TextBlock>
  <ListBox Width="500" Height="300" 
           ItemsSource="{Binding Source={StaticResource MyRSS}, 
           XPath=//item/title}">
  </ListBox>
</StackPanel>

RSS 피드를 호출하여, 그림6 과 같이 ListBox에서 블로그 토픽 목록을 빠르게 리스트 하는 페이지를 작성할 수 있습니다.

그림 6. 블로그의 토픽 목록

ObjectDataProvider 사용

.NET 오브젝트에의 바인드가 필요하게 되는 경우가 있습니다. ObjectDataProvider 데이터 공급자를 사용하면, .NET 데이터형의 바인드를 작성할 수 있습니다.

예를 들어 다음과 같이, .NET로 단순한 문자열 집합을 작성할 수 있습니다.

public class MyStrings : List<String>
{
  public MyStrings()
  {
    this.Add("Hello");
    this.Add("Goodbye");
    this.Add("Heya");
    this.Add("Cya");
  }
}

또는

Public Class MyStrings
  Inherits List(Of String)

  Public Sub New()
    Me.Add("Hello")
    Me.Add("Goodbye")
    Me.Add("Heya")
    Me.Add("Cya")
  End Sub

End Class

XAML 문서내의 처리 명령을 사용하여, CLR 오브젝트의 네임 스페이스 전체를 문서 지원 대상 타입에 추가할 수도 있습니다. 그 네임 스페이스를 xmlns 선언으로 지정합니다. 예를 들어, 다음과 같이 네임 스페이스 전체의 클래스를 XAML 에 대응 붙일 수 있습니다.

<Window 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Simple Source Binding"
    xmlns:local="clr-namespace:XamlExamples"
    x:Class="XamlExamples.SimpleSource"
 >
  <!-- ... -->
</Window>

외부 어셈블리에서 클래스를 가져오려면, xmlns 선언을 지정할 수 있는데 단지 다음과 같은 어셈블리명을 지정합니다.

<Window 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Simple Source Binding"
    xmlns:sys="clr-namespace:System,assembly=mscorlib"
    x:Class="XamlExamples.SimpleSource"
 >
  <!-- ... -->
</Window>

타입을 가져오기 한 후 ObjectDataProvider 를 사용하여, 어느 쪽에서든 데이터 소스를 지정할 수 있습니다.

<Window 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Simple Source Binding"
    xmlns:local="clr-namespace:XamlExamples"
    x:Class="XamlExamples.SimpleSource"
 >
  <Window.Resources>
    <ObjectDataProvider x:Key="MyStringData" 
                        ObjectType="{x:Type local:MyStrings}" />
  </Window.Resources>  
    <StackPanel>
      <TextBlock HorizontalAlignment="Center" 
               FontWeight="Bold">
      Simple Source Example
    </TextBlock>
    <ListBox Name="theListBox" Width="200" Height="300" 
      ItemsSource="{Binding Source={StaticResource MyStringData}}"/>
  </StackPanel>
</Window>

다음과 같이 XAML 요소를 네임 스페이스의 이름 및 사용하는 타입과 함께 지정해 리소스를 작성할 수도 있습니다.

<Window 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Simple Source Binding"
    xmlns:local="clr-namespace:XamlExamples"
    x:Class="XamlExamples.SimpleSource"
 >
  <Window.Resources>
    <local:MyStrings x:Key="MyStringData" />
  </Window.Resources>  
    <StackPanel>
      <TextBlock HorizontalAlignment="Center" 
               FontWeight="Bold">
      Simple Source Example
    </TextBlock>
    <ListBox Name="theListBox" Width="200" Height="300" 
      ItemsSource="{Binding Source={StaticResource MyStringData}}"/>
  </StackPanel>
</Window>

이 구문의 동작은 ObjectDataSource 와 같지만, 조금 더 간단하게 사용할 수 있습니다. 네임 스페이스를 가져와, 클래스의 이름 (예를 들어 MyStrings)을 지정하여, 데이터 소스의 클래스를 참조하는 리소스를 추가할 수 있습니다. 데이터 바인드는 앞서 예와 같습니다. XAML 코드에서는 데이터 소스인 것만이 문제가 되지, 데이터 소스가 어떠한 종류인지는 문제되지 않습니다.

바인딩 모드

대부분의 경우 Binding은 양방향의 바인딩을 요구합니다. Binding 오브젝트는 표1과 같이, 다양한 용도에 다양한 모드를 지원하고 있습니다.

표 1. 지원 되는 바인딩 모드

바인딩 모드 설명
TwoWay 바운드 컨트롤 또는 바인딩의 소스 변화, 또는 양방향으로 변경 가능합니다. (이것이 디폴트 모드입니다).
OneWay 소스에서 컨트롤 변화만 가능합니다. 소스가 변경되면, 바인드 컨트롤의 데이터가 변경됩니다.
OneTime 시작 시에만 데이터가 바인드 되어 컨트롤에 처음 데이터가 기록된 이후의 소스의 변경은 무시됩니다.

다음과 같이 마크 업에 모드를 포함하는 것만으로 모드를 지정할 수 있습니다.

{Binding ElementName=theTextBox, Path=Text, Mode=OneTime}

쌍방향 바인드가 어떻게 동작하는지를 확인하는 하나의 방법은 서로 바인드 된 두 개의 텍스트 박스가 있는 캔버스를 작성하는 것입니다.

<Window    
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  >
  <Canvas>
    <TextBox Name="theTextBox" Text="Hello" />
    <TextBox Canvas.Top="25"
             Text="{Binding ElementName=theTextBox, Path=Text, Mode=TwoWay}" />
  </Canvas>
</Window>

이 코드를 SDK에 부속의 XAMLPad 툴에 붙이면, 소스 텍스트 박스는 입력된 내용을 반영하고, 바인드 된 텍스트 박스를 갱신하지만, 바인드처의 컨트롤로부터 소스 컨트롤의 갱신은 바인드처의 컨트롤이 포커스를 잃었을 때만 행해집니다. ModeOneWay 또는 OneTime 으로 변경하면, 이러한 모드에 의한 바인드 동작의 변화를 확인할 수 있습니다.

바인드 타이밍 제어

Mode 외에 바인드에 의해 변경이 요구되는 타이밍도 지정할 수 있습니다. 여기에서는 pdateSourceTrigger 를 사용합니다. UpdateSourceTrigger 타입을 지정하여, 바인드가 특정의 타이밍에서만 변경할 수 있도록 지정할 수 있습니다.

{Binding ElementName=theTextBox, Path=Text, UpdateSourceTrigger=LostFocus}

UpdateSourceTrigger 속성은 소스 변경에 의해서 갱신되는 타이밍을 지정합니다. 이것은 Mode=TwoWay 의 바인드(디폴트)와 병용 하는 경우만 유효합니다. UpdateSourceTrigger로 지정할 수 있는 값은 표2와 같습니다.

표 2. UpdateSourceTrigger 값

UpdateSourceTrigger 설명
Explicit BindingExpression.UpdateSource 메소드를 명시적으로 호출했을 경우만, 소스가 갱신됩니다.
LostFocus 바인드 된 컨트롤이 포커스를 잃었을 때, 소스가 갱신됩니다.
PropertyChanged 속성이 변경될 때마다, 소스에 변경이 갱신됩니다. 이것이 디폴트입니다.

DataContext 사용

이 글로 마지막에 소개하는 개념은 DataContext의 사용법입니다. DataContext는 어떤 종류의 컨테이너내의 모든 컨트롤이 공통의 오브젝트에 바인드 지정을 목적으로 사용합니다.

예를 들어 다음의 예에서는 XML 문서내의 특정 노드에 있는 값과 텍스트를 Canvas를 작성합니다.

<StackPanel 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  >
  <StackPanel.Resources>
    <XmlDataProvider x:Key="FavoriteColors">
      <Colors xmlns="">
        <Color ID="1">Blue</Color> 
        <Color ID="2">Black</Color> 
        <Color ID="3">Green</Color> 
        <Color ID="4">Red</Color> 
      </Colors>
    </XmlDataProvider>
  </StackPanel.Resources>
  <TextBlock HorizontalAlignment="Center" 
             FontWeight="Bold">
    XML DataContext Example
  </TextBlock>
  <Canvas DataContext="{Binding Source={StaticResource FavoriteColors}, 
                        XPath='/Colors/Color[@ID=2]'}">
    <TextBlock Text="{Binding XPath=@ID}" />
    <TextBlock Canvas.Top="25" Text="{Binding XPath=.}" />
  </Canvas>
</StackPanel>

DataContext 를 XML 문서 (및 특정 XPath 식)에 설정하여, Canvas에서 Source가 없는 컨트롤에는 컨테이너의 DataContext를 사용하도록 지시합니다. 이 방법으로 XPath 식을 지정하여 TextBlock를 바인드 할 수 있습니다. 각 TextBlockXPath 식은 상대적인 XPath 식이라는 점을 알아둬야 합니다. 이것은 오브젝트를 바인드 하는 경우도 같습니다.

<Window 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Simple Source Binding"
    x:Class="XamlExamples.SimpleSource"
  >
  <Window.Resources>
    <ObjectDataProvider TypeName="XamlExamples.MyStrings, XamlExamples"
                        x:Key="MyStringData" />
  </Window.Resources>  
    <StackPanel>
      <TextBlock HorizontalAlignment="Center" 
               FontWeight="Bold">
      Object DataContext Example
    </TextBlock>
    <Canvas DataContext="{Binding Source={StaticResource MyStringData}}">
      <TextBlock Text="{Binding Path=Length}" />
      <TextBlock Canvas.Top="25" Text="{Binding Path=Item[0]}" />
    </Canvas>
  </StackPanel>
</Window>

XML대신에 오브젝트를 사용하는 것은 XPath 식 대신에 Path 식을 사용한다는 의미입니다.

마무리

이상 Binding 오브젝트에 의한 XAML로의 직접적인 데이터 바인딩에 대해서, 간략화 버전과 긴 버전의 두 가지를 모두 설명했습니다. XML 또는 오브젝트 데이터 공급자를 사용하는 것으로, 응용 프로그램 안의 다양한 타입의 오브젝트에 바인드 할 수 있습니다. 또 Binding 오브젝트의 ElementName 구문을 사용하고, 다른 컨트롤에 바인드 하는 방법도 설명했습니다. 다음의 파트에서는 지금까지 정보에 근거하여 사용자 독자적인 오브젝트 또는 .NET 데이터 컨테이너 (예를 들어 DataSourcesDataSets)를 사용하여 실제의 데이터베이스 데이터에 바인드 하는 방법을 설명하겠습니다.
출처 : http://www.microsoft.com/korea/msdn/netframework/using/documentation/aa480224.aspx


728x90

공유하기

facebook twitter kakaoTalk kakaostory naver band
loading