다음을 통해 공유


Windows 데이터 바인딩 개요

이 항목에서는 컨트롤(또는 다른 UI 요소)을 단일 항목에 바인딩하거나 항목 컨트롤을 Windows 앱 SDK 앱의 항목 컬렉션에 바인딩하는 방법을 보여 줍니다. 또한 항목의 렌더링을 제어하고 선택 항목을 기반으로 세부 정보 보기를 구현하며, 표시할 데이터를 변환하는 방법을 보여 줍니다. 자세한 내용은 데이터 바인딩 심층 분석을 참조하세요.

전제 조건

이 토픽에서는 기본 Windows 앱 SDK 앱을 만드는 방법을 알고 있다고 가정합니다. 첫 Windows 앱 SDK 앱을 만드는 방법에 대한 지침은 첫 번째 WinUI 3(Windows 앱 SDK) 프로젝트 만들기를 참조하세요.

프로젝트 만들기

새로운 비어 있는 앱, 패키지됨(데스크톱의 WinUI 3) C# 프로젝트를 만듭니다. 이름을 "Quickstart"로 지정합니다.

단일 항목에 바인딩

모든 바인딩은 바인딩 대상과 바인딩 소스로 구성됩니다. 일반적으로 대상은 컨트롤 또는 기타 UI 요소의 속성이고, 소스는 클래스 인스턴스(데이터 모델 또는 뷰 모델)의 속성입니다. 이 예제에서는 컨트롤을 단일 항목에 바인딩하는 방법을 보여 줍니다. 대상은 TextBlockText 속성입니다. 소스는 오디오 녹음을 나타내는 Recording 이라는 단순 클래스의 인스턴스를 나타냅니다. 먼저 클래스를 살펴보겠습니다.

프로젝트에 새 클래스를 추가하고 클래스 이름을 Recording(으)로 지정합니다.

namespace Quickstart
{
    public class Recording
    {
        public string ArtistName { get; set; }
        public string CompositionName { get; set; }
        public DateTime ReleaseDateTime { get; set; }
        public Recording()
        {
            ArtistName = "Wolfgang Amadeus Mozart";
            CompositionName = "Andante in C for Piano";
            ReleaseDateTime = new DateTime(1761, 1, 1);
        }
        public string OneLineSummary
        {
            get
            {
                return $"{CompositionName} by {ArtistName}, released: "
                    + ReleaseDateTime.ToString("d");
            }
        }
    }
    public class RecordingViewModel
    {
        private Recording defaultRecording = new Recording();
        public Recording DefaultRecording { get { return defaultRecording; } }
    }
}

다음으로 마크업 창을 나타내는 클래스에서 바인딩 소스 클래스를 노출합니다. MainWindow.xaml.csRecordingViewModel 형식의 속성을 추가하면 됩니다.

namespace Quickstart
{
    public sealed partial class MainWindow : Window
    {
        public MainWindow()
        {
            this.InitializeComponent();
            ViewModel = new RecordingViewModel();
        }
        public RecordingViewModel ViewModel{ get; set; }
    }
}

마지막 조각은 ViewModel.DefaultRecording.OneLineSummary 속성에 TextBlock을(를) 바인딩하는 것입니다.

<Window x:Class="Quickstart.MainWindow" ... >
    <Grid>
        <TextBlock Text="{x:Bind ViewModel.DefaultRecording.OneLineSummary}"
    HorizontalAlignment="Center"
    VerticalAlignment="Center"/>
    </Grid>
</Window>

다음은 결과입니다.

textblock 바인딩

항목 컬렉션에 바인딩

비즈니스 개체 컬렉션에 바인딩하는 것이 일반적인 시나리오입니다. C#에서는 INotifyPropertyChangedINotifyCollectionChanged 인터페이스를 구현하므로 데이터 바인딩을 위해 일반 ObservableCollection<T> 클래스가 좋은 컬렉션 선택입니다. 이러한 인터페이스는 항목이 추가 또는 변경되거나 목록 자체의 속성이 변경될 경우 바인딩에 대한 변경 알림을 제공합니다. 또한 바인딩된 컨트롤을 컬렉션에 있는 개체의 속성 변경 사항으로 업데이트하려면 비즈니스 개체에서도 INotifyPropertyChanged을(를) 구현해야 합니다. 자세한 내용은 데이터 바인딩 심층 분석을 참조하세요.

다음 예제에서는 ListViewRecording 개체의 컬렉션에 바인딩합니다. 먼저 컬렉션을 뷰 모델에 추가합니다. 이러한 새 멤버를 RecordingViewModel 클래스에 추가하기만 합니다.

public class RecordingViewModel
{
    ...
    private ObservableCollection<Recording> recordings = new ObservableCollection<Recording>();
    public ObservableCollection<Recording> Recordings{ get{ return recordings; } }
    public RecordingViewModel()
    {
        recordings.Add(new Recording(){ ArtistName = "Johann Sebastian Bach",
            CompositionName = "Mass in B minor", ReleaseDateTime = new DateTime(1748, 7, 8) });
        recordings.Add(new Recording(){ ArtistName = "Ludwig van Beethoven",
            CompositionName = "Third Symphony", ReleaseDateTime = new DateTime(1805, 2, 11) });
        recordings.Add(new Recording(){ ArtistName = "George Frideric Handel",
            CompositionName = "Serse", ReleaseDateTime = new DateTime(1737, 12, 3) });
    }
}

그런 다음 ListViewViewModel.Recordings 속성에 바인딩합니다.

<Window x:Class="Quickstart.MainWindow" ... >
    <Grid>
        <ListView ItemsSource="{x:Bind ViewModel.Recordings}"
        HorizontalAlignment="Center" VerticalAlignment="Center"/>
    </Grid>
</Window>

Recording 클래스에 대한 데이터 템플릿을 아직 제공하지 않았으므로 UI 프레임워크에서 수행할 수 있는 최상의 작업은 ListView의 각 항목에 대해 ToString을 호출하는 것입니다. ToString의 기본 구현은 형식 이름을 반환하는 것입니다.

목록 보기 1 바인딩

이 문제를 해결하기 위해 OneLineSummary 값을 반환하도록 ToString을 재정의하거나, 데이터 템플릿을 제공할 수 있습니다. 데이터 템플릿 옵션은 보다 일반적이면서 더 유연한 솔루션입니다. 콘텐츠 컨트롤의 ContentTemplate 속성 또는 항목 컨트롤의 ItemTemplate 속성을 사용하여 데이터 템플릿을 지정합니다. 결과에 대한 그림과 함께 Recording에 대한 데이터 템플릿을 디자인할 수 있는 두 가지 방법은 다음과 같습니다.

<ListView ItemsSource="{x:Bind ViewModel.Recordings}"
HorizontalAlignment="Center" VerticalAlignment="Center">
    <ListView.ItemTemplate>
        <DataTemplate x:DataType="local:Recording">
            <TextBlock Text="{x:Bind OneLineSummary}"/>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

목록 보기 2 바인딩

<ListView ItemsSource="{x:Bind ViewModel.Recordings}"
HorizontalAlignment="Center" VerticalAlignment="Center">
    <ListView.ItemTemplate>
        <DataTemplate x:DataType="local:Recording">
            <StackPanel Orientation="Horizontal" Margin="6">
                <SymbolIcon Symbol="Audio" Margin="0,0,12,0"/>
                <StackPanel>
                    <TextBlock Text="{x:Bind ArtistName}" FontWeight="Bold"/>
                    <TextBlock Text="{x:Bind CompositionName}"/>
                </StackPanel>
            </StackPanel>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

목록 보기 3 바인딩

XAML 구문에 대한 자세한 내용은 XAML을 사용하여 UI 만들기를 참조하세요. 컨트롤 레이아웃에 대한 자세한 내용은 XAML을 사용하여 레이아웃 정의를 참조하세요.

자세히 보기 추가

ListView 항목에서 Recording 개체의 모든 세부 정보를 표시할 수 있습니다. 그러나 이러한 정보는 많은 공간을 차지합니다. 따라서 대신 항목을 식별하는 데 충분한 데이터만 표시한 다음, 사용자가 선택한 경우 세부 정보 보기라는 UI의 별도 부분에 선택한 항목의 모든 세부 정보를 표시할 수 있습니다. 이 정렬을 마스터/세부 정보 보기 또는 목록/세부 정보 보기라고도 합니다.

두 가지 방법이 있습니다. 세부 정보 보기를 ListViewSelectedItem 속성에 바인딩할 수 있습니다. 또는 CollectionViewSource를 사용할 수 있습니다. 이 경우 ListView 및 세부 정보 뷰를 모두 CollectionViewSource에 바인딩합니다(그러면 현재 선택한 항목이 자동으로 처리됨). 두 기술 모두 아래에 나와 있으며, 둘 다 그림과 동일한 결과를 제공합니다.

참고

지금까지 이 항목에서는 {x:Bind} 마크업 확장만 사용했지만 아래에서 살펴볼 두 기술에는 모두 보다 유연한(그러나 성능이 낮은) {Binding} 확장이 필요합니다.

먼저, 다음은 SelectedItem 기술입니다. C# 애플리케이션의 경우 필요한 유일한 변경 내용은 마크업입니다.

<Window x:Class="Quickstart.MainWindow" ... >
    <Grid>
        <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
            <ListView x:Name="recordingsListView" ItemsSource="{x:Bind ViewModel.Recordings}">
                <ListView.ItemTemplate>
                    <DataTemplate x:DataType="local:Recording">
                        <StackPanel Orientation="Horizontal" Margin="6">
                            <SymbolIcon Symbol="Audio" Margin="0,0,12,0"/>
                            <StackPanel>
                                <TextBlock Text="{x:Bind CompositionName}"/>
                            </StackPanel>
                        </StackPanel>
                    </DataTemplate>
                </ListView.ItemTemplate>
            </ListView>
            <StackPanel DataContext="{Binding SelectedItem, ElementName=recordingsListView}"
            Margin="0,24,0,0">
                <TextBlock Text="{Binding ArtistName}"/>
                <TextBlock Text="{Binding CompositionName}"/>
                <TextBlock Text="{Binding ReleaseDateTime}"/>
            </StackPanel>
        </StackPanel>
    </Grid>
</Window>

CollectionViewSource 기술의 경우 먼저 CollectionViewSource을(를) 창 리소스로 추가합니다.

<Window.Resources>
    <CollectionViewSource x:Name="RecordingsCollection" Source="{x:Bind ViewModel.Recordings}"/>
</Window.Resources>

그런 다음 CollectionViewSource를 사용하도록 ListView(더 이상 이름을 지정할 필요 없음)와 세부 정보 보기에 대한 바인딩을 조정합니다. 세부 정보 보기를 CollectionViewSource에 직접 바인딩하면 컬렉션 자체에서 경로를 찾을 수 없는 바인딩에서 현재 항목에 바인딩할 수 있습니다. CurrentItem 속성을 바인딩 경로로 지정할 필요는 없습니다(모호한 경우에는 지정할 수 있음).

...
<ListView ItemsSource="{Binding Source={StaticResource RecordingsCollection}}">
...
<StackPanel DataContext="{Binding Source={StaticResource RecordingsCollection}}" ...>
...

다음은 각 경우의 동일한 결과입니다.

목록 보기 4 바인딩

표시할 데이터 값 필터링 또는 변환

위 렌더링에는 한 가지 문제가 있습니다. ReleaseDateTime 속성은 단순한 날짜가 아니라 DateTime입니다. 따라서 필요한 것보다 더 정확하게 표시됩니다. 한 가지 해결 방법은 ReleaseDateTime.ToString("d")에 해당하는 값을 반환하는 Recording 클래스에 문자열 속성을 추가하는 것입니다. 이 속성의 이름을 ReleaseDate(으)로 지정하여 날짜 및 시간이 아니라 날짜가 반환됨을 표시합니다. ReleaseDateAsString(으)로 이름을 지정하면 문자열을 반환함을 나타냅니다.

보다 유연한 해결 방법은 값 변환기라는 것을 사용하는 것입니다. 다음은 사용자 고유의 값 변환기를 작성하는 방법에 대한 예제입니다. Recording.cs 소스 코드 파일에 아래 코드를 추가합니다.

public class StringFormatter : Microsoft.UI.Xaml.Data.IValueConverter
{
    // This converts the value object to the string to display.
    // This will work with most simple types.
    public object Convert(object value, Type targetType,
        object parameter, string language)
    {
        // Retrieve the format string and use it to format the value.
        string formatString = parameter as string;
        if (!string.IsNullOrEmpty(formatString))
        {
            return string.Format(formatString, value);
        }

        // If the format string is null or empty, simply
        // call ToString() on the value.
        return value.ToString();
    }

    // No need to implement converting back on a one-way binding
    public object ConvertBack(object value, Type targetType,
        object parameter, string language)
    {
        throw new NotImplementedException();
    }
}

이제 StringFormatter의 인스턴스를 페이지 리소스로 추가하고, ReleaseDateTime 속성을 표시하는 TextBlock의 바인딩에 사용할 수 있습니다.

<Window.Resources>
    <local:StringFormatter x:Key="StringFormatterValueConverter"/>
</Window.Resources>
...
<TextBlock Text="{Binding ReleaseDateTime,
    Converter={StaticResource StringFormatterValueConverter},
    ConverterParameter=Released: \{0:d\}}"/>
...

위에서 볼 수 있듯이 서식 유연성을 위해 태그를 사용하여 형식 문자열을 변환기에 변환기 매개 변수로 전달합니다. 이 항목에 표시된 코드 예에서 C# 값 변환기는 해당 매개 변수를 사용합니다.

다음은 결과입니다.

사용자 지정 서식을 사용하여 날짜 표시

참고 항목