연습: WPF Designer를 사용하여 간단한 WPF 응용 프로그램 만들기

업데이트: 2010년 12월

이 연습에서는 WPF Designer를 사용하여 간단한 WPF(Windows Presentation Foundation) 응용 프로그램을 만드는 방법을 보여 줍니다.

이 연습에서는 다음 작업을 수행합니다.

  • 프로젝트를 만듭니다.

  • 레이아웃을 만듭니다.

  • 레이아웃에 컨트롤을 추가합니다.

  • 레이아웃 관련 속성을 설정합니다.

  • 데이터 소스를 만듭니다.

  • 데이터 소스에 연결합니다.

  • 컨트롤 속성을 바인딩합니다.

작업이 끝나면 파일 시스템을 탐색할 수 있는 간단한 응용 프로그램이 완성됩니다. 응용 프로그램의 사용자 인터페이스는 XAML(Extensible Application Markup Language)로 구현됩니다. 자세한 내용은 WPF의 XAML을 참조하십시오. 다음 그림에서는 응용 프로그램의 모양을 보여 줍니다.

FolderExplorer 트리 보기 및 목록 보기

참고

Visual Studio 2010 내에서 실행되는 이 연습의 실습 버전은 WPF Simple Application Walkthrough에서 제공됩니다.

사전 요구 사항

이 연습을 완료하려면 다음 구성 요소가 필요합니다.

  • Visual Studio 2010.

프로젝트 만들기

첫 번째 단계는 응용 프로그램의 프로젝트를 만드는 것입니다.

프로젝트를 만들려면

  1. Visual Basic 또는 Visual C#에서 FolderExplorer라는 새 WPF 응용 프로그램 프로젝트를 만듭니다. 자세한 내용은 방법: 새 WPF 응용 프로그램 프로젝트 만들기를 참조하십시오.

    WPF Designer에 MainWindow.xaml이 열립니다.

  2. 디자인 뷰에서 창을 선택합니다. 자세한 내용은 방법: 디자인 화면의 요소 선택 및 이동을 참조하십시오.

  3. 속성 창에서 Title 속성 값을 Folder Explorer로 설정합니다.

레이아웃 만들기

레이아웃은 응용 프로그램의 주 창에 컨트롤이 정렬되는 방식을 정의합니다. 다음 단계에서는 응용 프로그램의 컨트롤이 포함될 레이아웃 요소를 생성하는 방법을 보여 줍니다.

레이아웃을 만들려면

  1. 창의 루트 Grid 컨트롤을 선택합니다.

  2. 모눈에 두 번째 행을 추가합니다. 자세한 내용은 방법: 표에 행 및 열 추가를 참조하십시오.

  3. 모눈에 두 번째 열을 추가합니다.

레이아웃에 컨트롤 추가

이제 정의된 레이아웃을 컨트롤로 채울 수 있습니다.

레이아웃에 컨트롤을 추가하려면

  1. 도구 상자에서 TreeView 컨트롤을 모눈의 첫 번째 셀로 끌어 놓습니다.

  2. 도구 상자에서 ListView 컨트롤을 모눈의 첫 번째 행과 두 번째 열을 차지하는 셀로 끌어 놓습니다.

  3. 도구 상자에서 ListView 컨트롤을 모눈의 두 번째 행과 두 번째 열을 차지하는 셀로 끌어 놓습니다.

레이아웃 관련 속성 설정

다음 단계에서는 컨트롤의 레이아웃 관련 속성을 설정하는 방법을 보여 줍니다. 각 컨트롤의 속성을 설정함에 따라 레이아웃의 모양이 최종 응용 프로그램과 비슷해집니다.

레이아웃 관련 속성을 설정하려면

  1. TreeView 컨트롤을 선택합니다.

  2. 속성 창에서 속성을 다음과 같이 설정합니다.

    Property

    Grid.ColumnSpan

    1

    Grid.RowSpan

    2

    Height

    Auto

    HorizontalAlignment

    Stretch

    Margin

    0,0,0,0

    VerticalAlignment

    Stretch

    Width

    Auto

    첫 번째 모눈 열에 맞고 두 모눈 행을 차지하도록 TreeView 컨트롤의 크기가 조정됩니다.

  3. ListView 컨트롤을 모두 선택합니다.

  4. 속성 창에서 속성을 다음과 같이 설정합니다.

    Property

    Grid.ColumnSpan

    1

    Grid.RowSpan

    1

    Height

    Auto

    HorizontalAlignment

    Stretch

    Margin

    0,0,0,0

    VerticalAlignment

    Stretch

    Width

    Auto

    개별 모눈 셀에 맞도록 ListView 컨트롤의 크기가 조정됩니다.

    디자인 뷰의 레이아웃

  5. 문서 개요 창을 엽니다. 자세한 내용은 WPF 문서의 요소 계층 탐색를 참조하십시오.

  6. 표의 ColumnDefinitions 노드를 확장합니다.

  7. 첫 번째 ColumnDefinition 항목을 선택합니다.

    문서 개요 창

  8. 속성 창에서 Width 속성을 *로 설정합니다.

  9. 문서 개요 창에서 두 번째 ColumnDefinition을 선택합니다.

  10. 속성 창에서 Width 속성을 2*로 설정합니다.

    첫 번째 열은 창 너비의 3분의 1을 차지하고 두 번째 열은 3분의 2를 차지하도록 열 크기가 조정됩니다.

  11. 문서 개요 창에서 표의 RowDefinitions 노드를 확장합니다.

  12. 첫 번째 RowDefinition 항목을 선택합니다.

  13. 속성 창에서 Height 속성을 *로 설정합니다.

  14. 문서 개요 창에서 두 번째 RowDefinition을 선택합니다.

  15. 속성 창에서 Height 속성을 *로 설정합니다.

    창 높이의 절반을 차지하도록 행 크기가 조정됩니다.

  16. 솔루션을 빌드하고 실행합니다.

  17. 창 크기를 조정하여 TreeViewListView 컨트롤의 크기가 동적으로 조정되는지 확인합니다.

데이터 소스 만들기

FolderExplorer 응용 프로그램의 데이터 소스는 Folder라는 클래스입니다. 이 클래스는 간단한 파일 시스템 모델을 제공합니다. 각 Folder 인스턴스에는 SubFolders 및 Files 컬렉션이 있습니다.

데이터 소스를 만들려면

  1. FolderExplorer 프로젝트에 Folder라는 새 클래스를 추가합니다. 자세한 내용은 방법: 새 프로젝트 항목 추가를 참조하십시오.

  2. Folder 소스 코드 파일의 내용을 다음 코드로 바꿉니다.

    Imports System
    Imports System.IO
    Imports System.Linq
    Imports System.Collections.Generic
    Imports System.Collections.ObjectModel
    Imports System.Text
    
    Public Class Folder
        Private _folder As DirectoryInfo
        Private _subFolders As ObservableCollection(Of Folder)
        Private _files As ObservableCollection(Of FileInfo)
    
        Public Sub New() 
            Me.FullPath = "c:\"
    
        End Sub 'New
    
    
        Public ReadOnly Property Name() As String 
            Get
                Return Me._folder.Name
            End Get
        End Property
    
    
        Public Property FullPath() As String 
            Get
                Return Me._folder.FullName
            End Get
    
            Set
                If Directory.Exists(value) Then
                    Me._folder = New DirectoryInfo(value)
                Else
                    Throw New ArgumentException("must exist", "fullPath")
                End If
            End Set
        End Property
    
        ReadOnly Property Files() As ObservableCollection(Of FileInfo)
            Get
                If Me._files Is Nothing Then
                    Me._files = New ObservableCollection(Of FileInfo)
    
                    Dim fi As FileInfo() = Me._folder.GetFiles()
    
                    Dim i As Integer
                    For i = 0 To fi.Length - 1
                        Me._files.Add(fi(i))
                    Next i
                End If
    
                Return Me._files
            End Get
        End Property
    
        ReadOnly Property SubFolders() As ObservableCollection(Of Folder)
    
            Get
                If Me._subFolders Is Nothing Then
                    Try
    
                    Me._subFolders = New ObservableCollection(Of Folder)
    
                        Dim di As DirectoryInfo() = Me._folder.GetDirectories()
    
                        Dim i As Integer
                        For i = 0 To di.Length - 1
                            Dim newFolder As New Folder()
                            newFolder.FullPath = di(i).FullName
                            Me._subFolders.Add(newFolder)
                        Next i
                    Catch ex As Exception
    
                        System.Diagnostics.Trace.WriteLine(ex.Message)
    
                    End Try
                End If
    
                Return Me._subFolders
            End Get
        End Property
    End Class
    
    using System;
    using System.IO;
    using System.Linq;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Text;
    
    namespace FolderExplorer
    {
        public class Folder
        {
            private DirectoryInfo _folder;
            private ObservableCollection<Folder> _subFolders;
            private ObservableCollection<FileInfo> _files;
    
            public Folder()
            {
                this.FullPath = @"c:\";
            }
    
            public string Name
            {
                get
                {
                    return this._folder.Name;
                }
            }
    
            public string FullPath
            {
                get
                {
                    return this._folder.FullName;
                }
    
                set
                {
                    if (Directory.Exists(value))
                    {
                        this._folder = new DirectoryInfo(value);
                    }
                    else
                    {
                        throw new ArgumentException("must exist", "fullPath");
                    }
                }
            }
    
            public ObservableCollection<FileInfo> Files
            {
                get
                {
                    if (this._files == null)
                    {
                        this._files = new ObservableCollection<FileInfo>();
    
                        FileInfo[] fi = this._folder.GetFiles();
    
                        for (int i = 0; i < fi.Length; i++)
                        {
                            this._files.Add(fi[i]);
                        }
                    }
    
                    return this._files;
                }
            }
    
            public ObservableCollection<Folder> SubFolders
            {
                get
                {
                    if (this._subFolders == null)
                    {
                        this._subFolders = new ObservableCollection<Folder>();
    
                        DirectoryInfo[] di = this._folder.GetDirectories();
    
                        for (int i = 0; i < di.Length; i++)
                        {
                            Folder newFolder = new Folder();
                            newFolder.FullPath = di[i].FullName;
                            this._subFolders.Add(newFolder);
                        }
                    }
    
                    return this._subFolders;
                }
            }
        }
    }
    

데이터 소스에 연결

WPF 컨트롤은 데이터 바인딩을 통해 데이터 소스에 연결됩니다. 다음 절차에서는 ObjectDataProvider를 선언하고 바인딩하는 방법을 보여 줍니다.

데이터 소스에 연결하려면

  1. WPF Designer에서 MainWindow.xaml을 엽니다. 

  2. XAML 뷰에서 다른 xmlns 매핑을 사용하여 <Window> 태그에 다음 XAML을 삽입합니다. 자세한 내용은 방법: 네임스페이스를 XAML로 가져오기를 참조하십시오.

    xmlns:my="clr-namespace:FolderExplorer"
    
  3. 여는 <Window> 태그와 여는 <Grid> 태그 사이에 다음 XAML을 삽입합니다.

        <Window.Resources>
    
            <ObjectDataProvider x:Key="RootFolderDataProvider" >
                <ObjectDataProvider.ObjectInstance>
                    <my:Folder FullPath="c:\"/>
                </ObjectDataProvider.ObjectInstance>
            </ObjectDataProvider>
    
            <HierarchicalDataTemplate 
                DataType    = "{x:Type my:Folder}"
                ItemsSource = "{Binding Path=SubFolders}">
                <TextBlock Text="{Binding Path=Name}" />
            </HierarchicalDataTemplate>
    
        </Window.Resources>
    
    
  4. <TreeView> 태그를 다음 XAML로 바꿉니다.

            <TreeView Grid.ColumnSpan="1" Grid.RowSpan="2" Margin="0,0,0,0" Name="treeView1" >
                <TreeViewItem ItemsSource="{Binding Path=SubFolders, Source={StaticResource RootFolderDataProvider}}" Header="Folders"  />
            </TreeView>
    

컨트롤 속성 바인딩

컨트롤의 속성을 다른 컨트롤에 바인딩하여 속성을 자동으로 업데이트할 수 있습니다.

컨트롤 속성을 바인딩하려면

  1. XAML 뷰에서 두 <ListView> 태그를 모두 다음 XAML로 바꿉니다.

            <ListView Name="listView1" 
            ItemsSource="{Binding Path=SelectedItem.SubFolders, ElementName=treeView1, Mode=OneWay}" 
            Grid.Column="1" 
            Grid.RowSpan="1" />
    
            <ListView Name="listView2" 
            ItemsSource="{Binding Path=SelectedItem.Files, ElementName=treeView1, Mode=OneWay}" 
            Grid.Column="1" 
            Grid.Row="1" />
    
  2. 솔루션을 빌드하고 실행합니다.

  3. Folders 항목을 확장하여 C: 드라이브의 폴더를 표시합니다.

  4. 하위 폴더를 클릭하고 두 ListView 컨트롤의 내용을 살펴 봅니다.

    하위 폴더는 위쪽 ListView 컨트롤에 표시되고 파일은 아래쪽 ListView 컨트롤에 표시됩니다.

다음 단계

  • 현재 FolderExplorer 응용 프로그램은 기본 스타일로 표시됩니다. 직접 만든 스타일을 적용하여 응용 프로그램의 모양과 동작을 변경할 수 있습니다.

  • 또한 Visual Studio는 WPF 응용 프로그램을 디버깅하기 위한 다양한 도구를 제공합니다. 자세한 내용은 연습: 디자인 타임에 WPF 사용자 지정 컨트롤 디버깅을 참조하십시오.

참고 항목

작업

방법: 연결된 이벤트 사용

연습: 디자인 타임에 WPF 사용자 지정 컨트롤 디버깅

개념

분할된 뷰: WPF 디자인 화면과 XAML을 동시에 보기

WPF 문서의 요소 계층 탐색

기타 리소스

WPF Designer에서의 컨트롤 작업

변경 기록

날짜

변경 내용

이유

2010년 12월

Added link to WPF Simple Application Walkthrough.

향상된 기능 관련 정보