이 설명서는 보관되지만 유지 되지 않습니다.

컨트롤 콘텐츠 모델 개요

Visual Studio 2008

업데이트: 2007년 11월

이 항목에서는 Control에서 상속되는 클래스에 사용되는 콘텐츠 모델에 대해 설명합니다. 콘텐츠 모델은 컨트롤에 포함될 수 있는 개체 형식을 지정합니다. 이 항목에서 "컨트롤"이라는 용어는 해당 클래스 계층 구조 어딘가에 Control 클래스를 포함하는 클래스로 제한됩니다. 이 항목에서 설명하는 네 가지 콘텐츠 모델은 Control에서 상속되는 다음과 같은 네 가지 클래스에 의해 정의됩니다.

이러한 네 가지 클래스는 WPF에 있는 대부분의 컨트롤에 대한 기본 클래스로 사용됩니다. 이러한 콘텐츠 모델을 사용하는 클래스는 동일한 형식의 콘텐츠를 포함하고 동일한 방식으로 콘텐츠를 처리할 수 있습니다. ContentControl 또는 ContentControl에서 상속되는 클래스에 포함될 수 있는 모든 개체 형식은 나머지 세 가지 콘텐츠 모델을 포함하는 컨트롤에 포함될 수 있습니다. 다음 그림에서는 이미지와 일부 텍스트를 포함하는 각 콘텐츠 모델의 컨트롤을 하나씩 보여 줍니다.

Button, GroupBox, Listbax, TreeViewItem

이 항목에는 다음 단원이 포함되어 있습니다.

  • 사전 요구 사항
  • ContentControl
  • HeaderedContentControl
  • ItemsControl
  • HeaderedItemsControl
  • 관련 항목

이 항목에서는 사용자가 WPF에 대해 기본적으로 이해하고 있고 응용 프로그램에 컨트롤을 추가하는 방법을 알고 있는 것으로 가정합니다. 자세한 내용은 Windows Presentation Foundation 시작Controls 개요를 참조하십시오.

네 가지 콘텐츠 모델 중 가장 간단한 모델은 Content 속성을 포함하는 ContentControl입니다. Content 속성의 형식은 Object이므로 ContentControl에 포함할 수 있는 사항에 제한이 없습니다. XAML(Extensible Application Markup Language) 또는 코드를 사용하여 Content를 설정할 수 있습니다.

다음 컨트롤은 ContentControl 콘텐츠 모델을 사용합니다.

다음 예제에서는 Content를 다음 중 하나로 설정하여 네 가지 Button 컨트롤을 만드는 방법을 보여 줍니다.

참고:

예제 XAML(Extensible Application Markup Language) 버전은 각 단추의 콘텐츠 주위에 <Button.Content> 태그를 사용할 수 있지만 반드시 이렇게 해야 하는 것은 아닙니다. 자세한 내용은 XAML 개요를 참조하십시오.

<!--Create a Button with a string as its content.-->
<Button>This is string content of a Button</Button>

<!--Create a Button with a DateTime object as its content.-->
<Button xmlns:sys="clr-namespace:System;assembly=mscorlib">
  <sys:DateTime>2004/3/4 13:6:55</sys:DateTime>
</Button>

<!--Create a Button with a single UIElement as its content.-->
<Button>
  <Rectangle Height="40" Width="40" Fill="Blue"/>
</Button>

<!--Create a Button with a panel that contains multiple objects 
as its content.-->
<Button>
  <StackPanel>
    <Ellipse Height="40" Width="40" Fill="Blue"/>
    <TextBlock TextAlignment="Center">Button</TextBlock>
  </StackPanel>
</Button>


// Create a Button with a string as its content.
Button stringContent = new Button();
stringContent.Content = "This is string content of a Button";

// Create a Button with a DateTime object as its content.
Button objectContent = new Button();
DateTime dateTime1 = new DateTime(2004, 3, 4, 13, 6, 55);

objectContent.Content = dateTime1;

// Create a Button with a single UIElement as its content.
Button uiElementContent = new Button();

Rectangle rect1 = new Rectangle();
rect1.Width = 40;
rect1.Height = 40;
rect1.Fill = Brushes.Blue;
uiElementContent.Content = rect1;

// Create a Button with a panel that contains multiple objects 
// as its content.
Button panelContent = new Button();
StackPanel stackPanel1 = new StackPanel();
Ellipse ellipse1 = new Ellipse();
TextBlock textBlock1 = new TextBlock();

ellipse1.Width = 40;
ellipse1.Height = 40;
ellipse1.Fill = Brushes.Blue;

textBlock1.TextAlignment = TextAlignment.Center;
textBlock1.Text = "Button";

stackPanel1.Children.Add(ellipse1);
stackPanel1.Children.Add(textBlock1);

panelContent.Content = stackPanel1;


다음 그림에서는 이전 예제에서 만든 네 개의 단추를 보여 줍니다.

네 단추

HeaderedContentControlContentControl에서 Content 속성을 상속하며 형식이 ObjectHeader 속성을 정의합니다. Header는 컨트롤의 머리글을 제공합니다. ContentControlContent 속성과 마찬가지로 Header는 어떤 형식이든 될 수 있습니다. WPF는 HeaderedContentControl에서 상속되는 세 가지 컨트롤을 제공합니다.

다음 예제에서는 두 개의 TabItem 개체를 포함하는 TabControl(ItemsControl)을 만듭니다. 첫 번째 TabItem의 경우 HeaderContent 모두에 풍부한 콘텐츠가 포함되어 있으며 HeaderEllipseTextBlock을 포함하는 StackPanel로 설정되고 ContentTextBlockLabel을 포함하는 StackPanel로 설정됩니다. 두 번째 TabItemHeader는 문자열로 설정되고 Content는 단일 TextBlock으로 설정됩니다.

<TabControl>
  <TabItem>
    <TabItem.Header>
      <StackPanel Orientation="Horizontal">
        <Ellipse Width="10" Height="10" Fill="DarkGray"/>
        <TextBlock>Tab 1</TextBlock>
      </StackPanel>
    </TabItem.Header>
    <StackPanel>
      <TextBlock>Enter some text</TextBlock>
      <TextBox Name="textBox1" Width="50"/>
    </StackPanel>
  </TabItem>
  <TabItem Header="Tab 2">
    <!--Bind TextBlock.Text to the TextBox on the first
    TabItem.-->
    <TextBlock Text="{Binding ElementName=textBox1, Path=Text}"/>
  </TabItem>
</TabControl>


다음 그림에서는 이전 예제에서 만든 TabControl을 보여 줍니다.

TabControl

ItemsControl에서 상속되는 컨트롤에는 개체 컬렉션이 포함됩니다. ItemsControl의 예로는 ListBox를 들 수 있습니다. ItemsSource 속성 또는 Items 속성을 사용하여 ItemsControl을 채울 수 있습니다.

ItemsSource 속성

ItemsControlItemsSource 속성을 통해 IEnumerableItemsControl의 콘텐츠로 구현하는 모든 형식을 사용할 수 있습니다. ItemsSource는 일반적으로 데이터 컬렉션을 표시하거나 ItemsControl을 컬렉션 개체에 바인딩하는 데 사용됩니다.

다음 예제에서는 단순 문자열 컬렉션인 MyData라는 클래스를 만듭니다.

public class MyData : ObservableCollection<string>
{
    public MyData()
    {
        Add("Item 1");
        Add("Item 2");
        Add("Item 3");
    }
}


다음 예제에서는 ItemsSourceMyData에 바인딩합니다.

<!--Create an instance of MyData as a resource.-->
<src:MyData x:Key="dataList"/>


...


<ListBox ItemsSource="{Binding Source={StaticResource dataList}}"/>


ListBox listBox1 = new ListBox();
MyData listData = new MyData();
Binding binding1 = new Binding();

binding1.Source = listData;
listBox1.SetBinding(ListBox.ItemsSourceProperty, binding1);


다음 그림에서는 이전 예제에서 만든 ListBox를 보여 줍니다.

ListBox

데이터 바인딩에 대한 자세한 내용은 데이터 바인딩 개요를 참조하십시오.

Items 속성

IEnumerable을 구현하여 ItemsControl을 채우는 개체를 사용하지 않으려면 Items 속성을 사용하여 항목을 추가합니다. ItemsControl의 항목에는 서로 다른 여러 형식을 포함할 수 있습니다. 예를 들어 ListBox에 문자열인 항목과 Image인 항목을 포함할 수 있습니다.

참고:

ItemsSource 속성이 설정되면 Items 속성을 사용하여 ItemCollection을 읽을 수 있지만 ItemCollection에서 항목을 추가하거나 수정할 수는 없습니다. ItemsSource 속성을 null 참조(Visual Basic에서는 Nothing)로 설정하면 컬렉션이 제거되고 Items(빈 ItemCollection)가 다시 사용됩니다.

다음 예제에서는 네 가지 서로 다른 항목 형식이 포함된 ListBox를 만듭니다.

<!--Create a ListBox that contains a string, a Rectangle,
     a Panel, and a DateTime object. These items can be accessed
     via the Items property.-->
<ListBox xmlns:sys="clr-namespace:System;assembly=mscorlib"
         Name="simpleListBox">

  <!-- The <ListBox.Items> element is implicitly used.-->
  This is a string in a ListBox

  <sys:DateTime>2004/3/4 13:6:55</sys:DateTime>

  <Rectangle Height="40" Width="40"  Fill="Blue"/>

  <StackPanel Name="itemToSelect">
    <Ellipse Height="40" Fill="Blue"/>
    <TextBlock>Text below an Ellipse</TextBlock>
  </StackPanel>

  <TextBlock>String in a TextBlock</TextBlock>
  <!--</ListBox.Items>-->
</ListBox>


// Add a String to the ListBox.
listBox1.Items.Add("This is a string in a ListBox");

// Add a DateTime object to a ListBox.
DateTime dateTime1 = new DateTime(2004, 3, 4, 13, 6, 55);

listBox1.Items.Add(dateTime1);

// Add a Rectangle to the ListBox.
Rectangle rect1 = new Rectangle();
rect1.Width = 40;
rect1.Height = 40;
rect1.Fill = Brushes.Blue;
listBox1.Items.Add(rect1);

// Add a panel that contains multpile objects to the ListBox.
Ellipse ellipse1 = new Ellipse();
TextBlock textBlock1 = new TextBlock();

ellipse1.Width = 40;
ellipse1.Height = 40;
ellipse1.Fill = Brushes.Blue;

textBlock1.TextAlignment = TextAlignment.Center;
textBlock1.Text = "Text below an Ellipse";

stackPanel1.Children.Add(ellipse1);
stackPanel1.Children.Add(textBlock1);

listBox1.Items.Add(stackPanel1);


다음 그림에서는 이전 예제에서 만든 ListBox를 보여 줍니다.

네 형식의 콘텐츠가 있는 ListBox

항목 컨테이너 클래스

WPF와 함께 제공되는 각 ItemsControl에는 ItemsControl의 항목을 나타내는 해당 클래스가 들어 있습니다. 다음 표에서는 WPF와 함께 제공되는 ItemsControl 개체 목록 및 해당 항목 컨테이너를 보여 줍니다.

ItemsControl의 각 항목에 대해 항목 컨테이너를 명시적으로 만들 수 있지만 반드시 이렇게 해야 하는 것은 아닙니다. ItemsControl에서 항목 컨테이너를 만들지 여부는 주로 시나리오에 따라 달라집니다. 예를 들어 데이터를 ItemsSource 속성에 바인딩하는 경우 항목 컨테이너를 명시적으로 만들지 않습니다. 여기서 고려해야 할 주요 사항은 다음과 같습니다.

  • ItemCollection의 개체 형식은 사용자가 항목 컨테이너를 명시적으로 만드는지 여부에 따라 달라집니다.

  • 항목 컨테이너를 명시적으로 만들지 않아도 항목 컨테이너를 가져올 수 있습니다.

  • 항목 컨테이너가 명시적으로 만들어지는지 여부에 관계없이 TargetType이 항목 컨테이너로 설정된 Style이 적용됩니다.

  • 명시적으로 만들어진 항목 컨테이너만 논리적 트리의 일부가 되므로 속성 상속은 암시적으로 만들어진 항목 컨테이너와 명시적으로 만들어진 항목 컨테이너에 대해 서로 다르게 동작합니다.

이 점을 보여 주기 위해 다음 예제에서는 두 개의 ListBox 컨트롤을 만듭니다. 이 예제에서는 첫 번째 ListBox에 대해 ListBoxItem 개체를 만들지만 두 번째 ListBox에 대해서는 해당 개체를 만들지 않습니다. 두 번째 경우에 ListBoxItemListBox의 각 항목에 대해 암시적으로 만들어집니다.

<!--Explicitly create a ListBoxItem for each item in the ListBox-->
<ListBox xmlns:sys="clr-namespace:System;assembly=mscorlib"
         Name="listBoxItemListBox">
  <!-- The <ListBox.Items> element is implicitly used.-->
  <ListBoxItem>
    This is a string in a ListBox
  </ListBoxItem>
  <ListBoxItem>
    <sys:DateTime>2004/3/4 13:6:55</sys:DateTime>
  </ListBoxItem>
  <ListBoxItem>
    <Rectangle Height="40" Width="40" Fill="Blue"/>
  </ListBoxItem>
  <ListBoxItem>
    <StackPanel>
      <Ellipse Height="40" Width="40" Fill="Blue"/>
      <TextBlock>Text below an Ellipse</TextBlock>
    </StackPanel>
  </ListBoxItem>
  <!--</ListBox.Items>-->
</ListBox>


...


<!--Create a ListBox that contains a string, a Rectangle,
     a Panel, and a DateTime object. These items can be accessed
     via the Items property.-->
<ListBox xmlns:sys="clr-namespace:System;assembly=mscorlib"
         Name="simpleListBox">

  <!-- The <ListBox.Items> element is implicitly used.-->
  This is a string in a ListBox

  <sys:DateTime>2004/3/4 13:6:55</sys:DateTime>

  <Rectangle Height="40" Width="40"  Fill="Blue"/>

  <StackPanel Name="itemToSelect">
    <Ellipse Height="40" Fill="Blue"/>
    <TextBlock>Text below an Ellipse</TextBlock>
  </StackPanel>

  <TextBlock>String in a TextBlock</TextBlock>
  <!--</ListBox.Items>-->
</ListBox>


ItemCollectionListBox마다 다릅니다. 첫 번째 ListBoxItems 속성에 있는 각 항목은 ListBoxItem이지만 두 번째 ListBox에서는 형식이 다릅니다. 다음 예제에서는 두 개의 ListBox 컨트롤에 있는 항목을 반복하고 각 항목의 형식을 검사하여 이를 확인합니다.

Console.WriteLine("Items in simpleListBox:");
foreach (object item in simpleListBox.Items)
{
    Console.WriteLine(item.GetType().ToString());
}

Console.WriteLine("\rItems in listBoxItemListBox:");

foreach (object item in listBoxItemListBox.Items)
{
    Console.WriteLine(item.GetType().ToString());
}


...


/*
Items in simpleListBox:
System.String
System.Windows.Shapes.Rectangle
System.Windows.Controls.StackPanel
System.DateTime

Items in listBoxItemListBox:
System.Windows.Controls.ListBoxItem
System.Windows.Controls.ListBoxItem
System.Windows.Controls.ListBoxItem
System.Windows.Controls.ListBoxItem
*/


다음 그림에서는 이전 예제에서 만든 두 개의 ListBox 컨트롤을 보여 줍니다.

명시적 및 암시적 항목 컨테이너 비교

항목에 대한 항목 컨테이너가 필요하지만 사용자 응용 프로그램에서 이를 명시적으로 만들지 않은 경우가 종종 있습니다. 특정 항목과 연결된 항목 컨테이너를 가져오려면 ContainerFromItem 메서드를 사용합니다. 다음 예제에서는 ListBoxItem이 명시적으로 만들어지지 않은 경우 항목과 연결된 항목 컨테이너를 가져오는 방법을 보여 줍니다. 이 예제에서는 itemToSelect라는 개체가 ListBoxItem이 아니며 ListBox(simpleListBox)에 추가되어 있는 것으로 가정합니다.

ListBoxItem lbi =
    simpleListBox.ItemContainerGenerator.ContainerFromItem(itemToSelect) 
    as ListBoxItem;

if (lbi != null)
{
    lbi.IsSelected = true;
}


TargetType이 항목 컨테이너로 설정된 스타일은 암시적 및 명시적으로 만들어진 항목 컨테이너에 모두 적용됩니다. 다음 예제에서는 ListBoxItem의 콘텐츠를 가로 방향으로 가운데에 맞추는 ListBoxItem에 대한 리소스로 Style을 만듭니다. 이러한 스타일이 ListBox 개체에 적용되면 두 개의 ListBox 개체에 있는 항목이 가운데에 맞춰집니다.

<!--Create a Style as a Resource.-->
<Style TargetType="ListBoxItem">
  <Setter Property="HorizontalContentAlignment" Value="Center"/>
</Style>


다음 그림에서는 이전 예제의 스타일이 적용된 두 개의 ListBox 컨트롤을 보여 줍니다.

두 개의 ListBox 컨트롤

스타일과 항목 컨테이너에 있어 속성 상속이 작동하는 방식은 논리적 트리의 구성 방식과 관련되어 있습니다. 항목 컨테이너를 명시적으로 만들면 항목 컨테이너가 논리적 트리의 일부가 되며 항목 컨테이너를 만들지 않으면 항목 컨테이너가 논리적 트리의 일부가 되지 않습니다. 다음 그림에서는 이전 예제에 나오는 두 개의 ListBox 컨트롤에 대한 논리적 트리의 차이점을 보여 줍니다.

두 ListBox 개체에 대한 시각적 트리

Visual 클래스에서 상속되는 개체는 해당 논리적 부모로부터 속성 값을 상속합니다. 다음 예제에서는 두 개의 TextBlock 컨트롤이 포함된 ListBox를 만들고 ListBoxForeground 속성을 파란색으로 설정합니다. 첫 번째 TextBlocktextBlock1은 명시적으로 만들어진 ListBoxItem에 포함되고 두 번째 TextBlocktextBlock2는 해당 항목에 포함되지 않습니다. 이 예제에서는 ListBoxItemForeground를 녹색으로 설정하는 ListBoxItem에 대한 Style도 정의합니다.

<!--Create a Style as a Resource.-->
<Style TargetType="ListBoxItem">
  <Setter Property="Foreground" Value="Green"/>
</Style>


...


<ListBox Foreground="Blue">
  <ListBoxItem>
    <TextBlock Name="textBlock1">TextBlock in a ListBoxItem.</TextBlock>
  </ListBoxItem>
  <TextBlock Name="textBlock2">TextBlock not in a ListBoxItem.</TextBlock>
</ListBox>


다음 그림에서는 이전 예제에서 만든 ListBox를 보여 줍니다.

ListBox에 있는 두 개의 ListBoxItem

TextBlock 컨트롤이 해당 논리적 부모로부터 Foreground 속성을 상속받기 때문에 textBlock1의 문자열은 녹색이고 textBlock2의 문자열은 파란색입니다. textBox1의 논리적 부모는 ListBoxItem이고 textBox2의 논리적 부모는 ListBox입니다. 자세한 내용은 속성 값 상속을 참조하십시오.

HeaderedItemsControlItemsControl 클래스에서 상속됩니다. HeaderedItemsControlHeader 속성을 정의합니다. 이 속성은 HeaderedContentControlHeader 속성과 동일한 규칙을 따릅니다. WPF는 HeaderedItemsControl에서 상속되는 세 가지 컨트롤을 제공합니다.

다음 예제에서는 TreeViewItem을 만듭니다. TreeView에는 TreeViewItem 1이라는 레이블이 지정된 단일 TreeViewItem과 다음 항목이 포함되어 있습니다.

참고:

RectangleStackPanelVisual 클래스에서 상속되므로 이 예제에서는 마지막 두 항목에 대해 TreeViewItem 개체를 명시적으로 만듭니다. TreeViewItem에 대한 기본 스타일은 Foreground 속성을 설정합니다. 자식 개체는 명시적으로 만들어진 TreeViewItem에서 속성 값을 상속받습니다. 일반적으로 이것이 적절한 동작입니다.

<TreeView xmlns:sys="clr-namespace:System;assembly=mscorlib"
          Margin="10">
  <TreeViewItem Header="TreeViewItem 1" IsExpanded="True">
    TreeViewItem 1a
    <sys:DateTime>2004/3/4 13:6:55</sys:DateTime>
    <TreeViewItem>
      <TreeViewItem.Header>
        <Rectangle Height="10" Width="10" Fill="Blue"/>
      </TreeViewItem.Header>
    </TreeViewItem>
    <TreeViewItem>
      <TreeViewItem.Header>
        <StackPanel Orientation="Horizontal">
          <Ellipse Width="10" Height="10" Fill="DarkGray"/>
          <TextBlock >TreeViewItem 1d</TextBlock>
        </StackPanel>
      </TreeViewItem.Header>
    </TreeViewItem>
  </TreeViewItem>
</TreeView>


표시: