달력

2

« 2025/2 »

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
2016. 10. 24. 11:18

Base Elements (기본 요소) 프로그래밍/WPF2016. 10. 24. 11:18

Base Elements



Base Elements Overview


https://msdn.microsoft.com/ko-kr/library/ms743618(v=vs.110).aspx

https://msdn.microsoft.com/en-us/library/ms743618(v=vs.110).aspx


A high percentage of classes in Windows Presentation Foundation (WPF) are derived from four classes which are commonly referred to in the SDK documentation as the base element classes. These classes are UIElementFrameworkElementContentElement, and FrameworkContentElement. The DependencyObject class is also related, because it is a common base class of both UIElement and ContentElement

Base Element APIs in WPF Classes

Both UIElement and ContentElement are derived from DependencyObject, through somewhat different pathways. The split at this level deals with how a UIElement or ContentElement are used in a user interface and what purpose they serve in an application. UIElement also has Visual in its class hierarchy, which is a class that exposes the lower-level graphics support underlying the Windows Presentation Foundation (WPF). Visual provides a rendering framework by defining independent rectangular screen regions. In practice, UIElement is for elements that will support a larger object model, are intended to render and layout into regions that can be described as rectangular screen regions, and where the content model is deliberately more open, to allow different combinations of elements. ContentElement does not derive from Visual; its model is that a ContentElementwould be consumed by something else, such as a reader or viewer that would then interpret the elements and produce the complete Visual for Windows Presentation Foundation (WPF) to consume. Certain UIElement classes are intended to be content hosts: they provide the hosting and rendering for one or more ContentElement classes (DocumentViewer is an example of such a class). ContentElement is used as base class for elements with somewhat smaller object models and that more address the text, information, or document content that might be hosted within a UIElement.

Framework-Level and Core-Level

UIElement serves as the base class for FrameworkElement, and ContentElement serves as the base class for FrameworkContentElement. The reason for this next level of classes is to support a WPF core level that is separate from a WPF framework level, with this division also existing in how the APIs are divided between the PresentationCore and PresentationFramework assemblies. The WPF framework level presents a more complete solution for basic application needs, including the implementation of the layout manager for presentation. The WPF core level provides a way to use much of WPF without taking the overhead of the additional assembly. The distinction between these levels very rarely matters for most typical application development scenarios, and in general you should think of the WPF APIs as a whole and not concern yourself with the difference between WPF framework level and WPF core level. You might need to know about the level distinctions if your application design chooses to replace substantial quantities of WPF framework level functionality, for instance if your overall solution already has its own implementations of user interface (UI) composition and layout.

Choosing Which Element to Derive From

The most practical way to create a custom class that extends WPF is by deriving from one of the WPF classes where you get as much as possible of your desired functionality through the existing class hierarchy. This section lists the functionality that comes with three of the most important element classes to help you decide which class to inherit from.

If you are implementing a control, which is really one of the more common reasons for deriving from a WPF class, you probably want to derive from a class that is a practical control, a control family base class, or at least from the Control base class. For some guidance and practical examples, see Control Authoring Overview.

If you are not creating a control and need to derive from a class that is higher in the hierarchy, the following sections are intended as a guide for what characteristics are defined in each base element class.

If you create a class that derives from DependencyObject, you inherit the following functionality:

If you create a class that derives from UIElement, you inherit the following functionality in addition to that provided by DependencyObject:

  • Basic support for animated property values. For more information, see Animation Overview.

  • Basic input event support, and commanding support. For more information, see Input Overview and Commanding Overview.

  • Virtual methods that can be overridden to provide information to a layout system.

If you create a class that derives from FrameworkElement, you inherit the following functionality in addition to that provided by UIElement:

  • Support for styling and storyboards. For more information, see Style and Storyboards Overview.

  • Support for data binding. For more information, see Data Binding Overview.

  • Support for dynamic resource references. For more information, see XAML Resources.

  • Property value inheritance support, and other flags in the metadata that help report conditions about properties to framework services such as data binding, styles, or the framework implementation of layout. For more information, see Framework Property Metadata.

  • The concept of the logical tree. For more information, see Trees in WPF.

  • Support for the practical WPF framework-level implementation of the layout system, including an OnPropertyChanged override that can detect changes to properties that influence layout.

If you create a class that derives from ContentElement, you inherit the following functionality in addition to that provided by DependencyObject:

If you create a class that derives from FrameworkContentElement, you get the following functionality in addition to that provided by ContentElement:

  • Support for styling and storyboards. For more information, see Style and Animation Overview.

  • Support for data binding. For more information, see Data Binding Overview.

  • Support for dynamic resource references. For more information, see XAML Resources.

  • Property value inheritance support, and other flags in the metadata that help report conditions about properties to framework services like data binding, styles, or the framework implementation of layout. For more information, see Framework Property Metadata.

  • You do not inherit access to layout system modifications (such as ArrangeOverride). Layout system implementations are only available on FrameworkElement. However, you inherit an OnPropertyChanged override that can detect changes to properties that influence layout and report these to any content hosts.

Content models are documented for a variety of classes. The content model for a class is one possible factor you should consider if you want to find an appropriate class to derive from. For more information, see WPF Content Model.

Other Base Classes

DispatcherObject

DispatcherObject provides support for the WPF threading model and enables all objects created for WPF applications to be associated with a Dispatcher. Even if you do not derive from UIElementDependencyObject, or Visual, you should consider deriving from DispatcherObject in order to get this threading model support. For more information, see Threading Model.

Visual

Visual implements the concept of a 2D object that generally requires visual presentation in a roughly rectangular region. The actual rendering of a Visual happens in other classes (it is not self-contained), but the Visual class provides a known type that is used by rendering processes at various levels. Visual implements hit testing, but it does not expose events that report hit-testing positives (these are in UIElement). For more information, see Visual Layer Programming.

Freezable

Freezable simulates immutability in a mutable object by providing the means to generate copies of the object when an immutable object is required or desired for performance reasons. The Freezable type provides a common basis for certain graphics elements such as geometries and brushes, as well as animations. Notably, a Freezable is not a Visual; it can hold properties that become subproperties when the Freezable is applied to fill a property value of another object, and those subproperties might affect rendering. For more information, see Freezable Objects Overview.

Animatable 

Animatable is a Freezable derived class that specifically adds the animation control layer and some utility members so that currently animated properties can be distinguished from nonanimated properties.

Control is the intended base class for the type of object that is variously termed a control or component, depending on the technology. In general, WPF control classes are classes that either directly represent a UI control or participate closely in control composition. The primary functionality that Control enables is control templating.





Freezable Objects Overview


This topic describes how to effectively use and create Freezable objects, which provide special features that can help improve application performance. Examples of freezable objects include brushes, pens, transformations, geometries, and animations.

This topic contains the following sections:

What Is a Freezable?

Freezable is a special type of object that has two states: unfrozen and frozen. When unfrozen, a Freezable appears to behave like any other object. When frozen, a Freezable can no longer be modified.

Freezable provides a Changed event to notify observers of any modifications to the object. Freezing a Freezable can improve its performance, because it no longer needs to spend resources on change notifications. A frozen Freezable can also be shared across threads, while an unfrozen Freezable cannot.

Although the Freezable class has many applications, most Freezable objects in Windows Presentation Foundation (WPF) are related to the graphics sub-system.

The Freezable class makes it easier to use certain graphics system objects and can help improve application performance. Examples of types that inherit from Freezable include the BrushTransform, and Geometry classes. Because they contain unmanaged resources, the system must monitor these objects for modifications, and then update their corresponding unmanaged resources when there is a change to the original object. Even if you don't actually modify a graphics system object, the system must still spend some of its resources monitoring the object, in case you do change it.

For example, suppose you create a SolidColorBrush brush and use it to paint the background of a button.

Button myButton = new Button();
SolidColorBrush myBrush = new SolidColorBrush(Colors.Yellow);
myButton.Background = myBrush;  

When the button is rendered, the WPF graphics sub-system uses the information you provided to paint a group of pixels to create the appearance of a button. Although you used a solid color brush to describe how the button should be painted, your solid color brush doesn't actually do the painting. The graphics system generates fast, low-level objects for the button and the brush, and it is those objects that actually appear on the screen.

If you were to modify the brush, those low-level objects would have to be regenerated. The freezable class is what gives a brush the ability to find its corresponding generated, low-level objects and to update them when it changes. When this ability is enabled, the brush is said to be "unfrozen."

A freezable's Freeze method enables you to disable this self-updating ability. You can use this method to make the brush become "frozen," or unmodifiable.

System_CAPS_noteNote

Not every Freezable object can be frozen. To avoid throwing an InvalidOperationException, check the value of the Freezable object's CanFreezeproperty to determine whether it can be frozen before attempting to freeze it.

if (myBrush.CanFreeze)
{
    // Makes the brush unmodifiable.
    myBrush.Freeze();
}

When you no longer need to modify a freezable, freezing it provides performance benefits. If you were to freeze the brush in this example, the graphics system would no longer need to monitor it for changes. The graphics system can also make other optimizations, because it knows the brush won't change.

System_CAPS_noteNote

For convenience, freezable objects remain unfrozen unless you explicitly freeze them.

Using Freezables

Using an unfrozen freezable is like using any other type of object. In the following example, the color of a SolidColorBrush is changed from yellow to red after it's used to paint the background of a button. The graphics system works behind the scenes to automatically change the button from yellow to red the next time the screen is refreshed.

Button myButton = new Button();
SolidColorBrush myBrush = new SolidColorBrush(Colors.Yellow);
myButton.Background = myBrush;  


// Changes the button's background to red.
myBrush.Color = Colors.Red;

Freezing a Freezable

To make a Freezable unmodifiable, you call its Freeze method. When you freeze an object that contains freezable objects, those objects are frozen as well. For example, if you freeze a PathGeometry, the figures and segments it contains would be frozen too.

A Freezable can't be frozen if any of the following are true:

  • It has animated or data bound properties.

  • It has properties set by a dynamic resource. (See the XAML Resources for more information about dynamic resources.)

  • It contains Freezable sub-objects that can't be frozen.

If these conditions are false, and you don't intend to modify the Freezable, then you should freeze it to gain the performance benefits described earlier.

Once you call a freezable's Freeze method, it can no longer be modified. Attempting to modify a frozen object causes an InvalidOperationException to be thrown. The following code throws an exception, because we attempt to modify the brush after it's been frozen.

Button myButton = new Button();
SolidColorBrush myBrush = new SolidColorBrush(Colors.Yellow);          

if (myBrush.CanFreeze)
{
    // Makes the brush unmodifiable.
    myBrush.Freeze();
}

myButton.Background = myBrush;  

try {

    // Throws an InvalidOperationException, because the brush is frozen.
    myBrush.Color = Colors.Red;
}catch(InvalidOperationException ex)
{
    MessageBox.Show("Invalid operation: " + ex.ToString());
}

To avoid throwing this exception, you can use the IsFrozen method to determine whether a Freezable is frozen.

Button myButton = new Button();
SolidColorBrush myBrush = new SolidColorBrush(Colors.Yellow);

if (myBrush.CanFreeze)
{
    // Makes the brush unmodifiable.
    myBrush.Freeze();
}            

myButton.Background = myBrush;


if (myBrush.IsFrozen) // Evaluates to true.
{
    // If the brush is frozen, create a clone and
    // modify the clone.
    SolidColorBrush myBrushClone = myBrush.Clone();
    myBrushClone.Color = Colors.Red;
    myButton.Background = myBrushClone;
}
else
{
    // If the brush is not frozen,
    // it can be modified directly.
    myBrush.Color = Colors.Red;
}


In the preceding code example, a modifiable copy was made of a frozen object using the Clone method. The next section discusses cloning in more detail.

Note   Because a frozen freezable cannot be animated, the animation system will automatically create modifiable clones of frozen Freezableobjects when you try to animate them with a Storyboard. To eliminate the performance overhead caused by cloning, leave an object unfrozen if you intend to animate it. For more information about animating with storyboards, see the Storyboards Overview.

Freezing from Markup

To freeze a Freezable object declared in markup, you use the PresentationOptions:Freeze attribute. In the following example, a SolidColorBrush is declared as a page resource and frozen. It is then used to set the background of a button.

<Page 
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:PresentationOptions="http://schemas.microsoft.com/winfx/2006/xaml/presentation/options" 
  xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
  mc:Ignorable="PresentationOptions">

  <Page.Resources>

    <!-- This resource is frozen. -->
    <SolidColorBrush 
      x:Key="MyBrush"
      PresentationOptions:Freeze="True" 
      Color="Red" />
  </Page.Resources>


  <StackPanel>

    <Button Content="A Button" 
      Background="{StaticResource MyBrush}">
    </Button>

  </StackPanel>
</Page>

To use the Freeze attribute, you must map to the presentation options namespace: http://schemas.microsoft.com/winfx/2006/xaml/presentation/optionsPresentationOptions is the recommended prefix for mapping this namespace:

xmlns:PresentationOptions="http://schemas.microsoft.com/winfx/2006/xaml/presentation/options" 

Because not all XAML readers recognize this attribute, it's recommended that you use the mc:Ignorable Attribute to mark the Presentation:Freeze attribute as ignorable:

xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="PresentationOptions"

For more information, see the mc:Ignorable Attribute page.

"Unfreezing" a Freezable

Once frozen, a Freezable can never be modified or unfrozen; however, you can create an unfrozen clone using the Clone or CloneCurrentValuemethod.

In the following example, the button's background is set with a brush and that brush is then frozen. An unfrozen copy is made of the brush using the Clone method. The clone is modified and used to change the button's background from yellow to red.

Button myButton = new Button();
SolidColorBrush myBrush = new SolidColorBrush(Colors.Yellow);

// Freezing a Freezable before it provides
// performance improvements if you don't
// intend on modifying it. 
if (myBrush.CanFreeze)
{
    // Makes the brush unmodifiable.
    myBrush.Freeze();
}


myButton.Background = myBrush;  

// If you need to modify a frozen brush,
// the Clone method can be used to
// create a modifiable copy.
SolidColorBrush myBrushClone = myBrush.Clone();

// Changing myBrushClone does not change
// the color of myButton, because its
// background is still set by myBrush.
myBrushClone.Color = Colors.Red;

// Replacing myBrush with myBrushClone
// makes the button change to red.
myButton.Background = myBrushClone;
System_CAPS_noteNote

Regardless of which clone method you use, animations are never copied to the new Freezable.

The Clone and CloneCurrentValue methods produce deep copies of the freezable. If the freezable contains other frozen freezable objects, they are also cloned and made modifiable. For example, if you clone a frozen PathGeometry to make it modifiable, the figures and segments it contains are also copied and made modifiable.

Creating Your Own Freezable Class

A class that derives from Freezable gains the following features.

  • Special states: a read-only (frozen) and a writable state.

  • Thread safety: a frozen Freezable can be shared across threads.

  • Detailed change notification: Unlike other DependencyObjects, Freezable objects provide change notifications when sub-property values change.

  • Easy cloning: the Freezable class has already implemented several methods that produce deep clones.

Freezable is a type of DependencyObject, and therefore uses the dependency property system. Your class properties don't have to be dependency properties, but using dependency properties will reduce the amount of code you have to write, because the Freezable class was designed with dependency properties in mind. For more information about the dependency property system, see the Dependency Properties Overview.

Every Freezable subclass must override the CreateInstanceCore method. If your class uses dependency properties for all its data, you're finished.

If your class contains non-dependency property data members, you must also override the following methods:

You must also observe the following rules for accessing and writing to data members that are not dependency properties:

  • At the beginning of any API that reads non-dependency property data members, call the ReadPreamble method.

  • At the beginning of any API that writes non-dependency property data members, call the WritePreamble method. (Once you've called WritePreamble in an API, you don't need to make an additional call to ReadPreamble if you also read non-dependency property data members.)

  • Call the WritePostscript method before exiting methods that write to non-dependency property data members.

If your class contains non-dependency-property data members that are DependencyObject objects, you must also call the OnFreezablePropertyChanged method each time you change on of their values, even if you're setting the member to null.

System_CAPS_noteNote

It's very important that you begin each Freezable method you override with a call to the base implementation.

For an example of a custom Freezable class, see the Custom Animation Sample.





Alignment, Margins, and Padding Overview


The FrameworkElement class exposes several properties that are used to precisely position child elements. This topic discusses four of the most important properties: HorizontalAlignmentMarginPadding, and VerticalAlignment. The effects of these properties are important to understand, because they provide the basis for controlling the position of elements in Windows Presentation Foundation (WPF) applications.

Introduction to Element Positioning

There are numerous ways to position elements using WPF. However, achieving ideal layout goes beyond simply choosing the right Panel element. Fine control of positioning requires an understanding of the HorizontalAlignmentMarginPadding, and VerticalAlignment properties.

The following illustration shows a layout scenario that utilizes several positioning properties.

WPF Positioning Properties Sample

At first glance, the Button elements in this illustration may appear to be placed randomly. However, their positions are actually precisely controlled by using a combination of margins, alignments, and padding.

The following example describes how to create the layout in the preceding illustration. A Border element encapsulates a parent StackPanel, with a Padding value of 15 device independent pixels. This accounts for the narrow LightBlue band that surrounds the child StackPanel. Child elements of the StackPanel are used to illustrate each of the various positioning properties that are detailed in this topic. Three Button elements are used to demonstrate both the Margin and HorizontalAlignment properties.

// Create the application's main Window.
mainWindow = new Window ();
mainWindow.Title = "Margins, Padding and Alignment Sample";

// Add a Border
myBorder = new Border();
myBorder.Background = Brushes.LightBlue;
myBorder.BorderBrush = Brushes.Black;
myBorder.Padding = new Thickness(15);
myBorder.BorderThickness = new Thickness(2);

myStackPanel = new StackPanel();
myStackPanel.Background = Brushes.White;
myStackPanel.HorizontalAlignment = HorizontalAlignment.Center;
myStackPanel.VerticalAlignment = VerticalAlignment.Top;

TextBlock myTextBlock = new TextBlock();
myTextBlock.Margin = new Thickness(5, 0, 5, 0);
myTextBlock.FontSize = 18;
myTextBlock.HorizontalAlignment = HorizontalAlignment.Center;
myTextBlock.Text = "Alignment, Margin and Padding Sample";
Button myButton1 = new Button();
myButton1.HorizontalAlignment = HorizontalAlignment.Left;
myButton1.Margin = new Thickness(20);
myButton1.Content = "Button 1";
Button myButton2 = new Button();
myButton2.HorizontalAlignment = HorizontalAlignment.Right;
myButton2.Margin = new Thickness(10);
myButton2.Content = "Button 2";
Button myButton3 = new Button();
myButton3.HorizontalAlignment = HorizontalAlignment.Stretch;
myButton3.Margin = new Thickness(0);
myButton3.Content = "Button 3";

// Add child elements to the parent StackPanel.
myStackPanel.Children.Add(myTextBlock);
myStackPanel.Children.Add(myButton1);
myStackPanel.Children.Add(myButton2);
myStackPanel.Children.Add(myButton3);

// Add the StackPanel as the lone Child of the Border.
myBorder.Child = myStackPanel;

// Add the Border as the Content of the Parent Window Object.
mainWindow.Content = myBorder;
mainWindow.Show ();

The following diagram provides a close-up view of the various positioning properties that are used in the preceding sample. Subsequent sections in this topic describe in greater detail how to use each positioning property.

Positioning Properties with Screen Call-outs

Understanding Alignment Properties

The HorizontalAlignment and VerticalAlignment properties describe how a child element should be positioned within a parent element's allocated layout space. By using these properties together, you can position child elements precisely. For example, child elements of a DockPanel can specify four different horizontal alignments: LeftRight, or Center, or to Stretch to fill available space. Similar values are available for vertical positioning.

System_CAPS_noteNote

Explicitly-set Height and Width properties on an element take precedence over the Stretch property value. Attempting to set HeightWidth, and a HorizontalAlignment value of Stretch results in the Stretch request being ignored.

HorizontalAlignment Property

The HorizontalAlignment property declares the horizontal alignment characteristics to apply to child elements. The following table shows each of the possible values of the HorizontalAlignment property.

Member

Description

Left

Child elements are aligned to the left of the parent element's allocated layout space.

Center

Child elements are aligned to the center of the parent element's allocated layout space.

Right

Child elements are aligned to the right of the parent element's allocated layout space.

Stretch(Default)

Child elements are stretched to fill the parent element's allocated layout space. Explicit Width and Height values take precedence.

The following example shows how to apply the HorizontalAlignment property to Button elements. Each attribute value is shown, to better illustrate the various rendering behaviors.

Button myButton1 = new Button();
myButton1.HorizontalAlignment = HorizontalAlignment.Left;
myButton1.Content = "Button 1 (Left)";
Button myButton2 = new Button();
myButton2.HorizontalAlignment = HorizontalAlignment.Right;
myButton2.Content = "Button 2 (Right)";
Button myButton3 = new Button();
myButton3.HorizontalAlignment = HorizontalAlignment.Center;
myButton3.Content = "Button 3 (Center)";
Button myButton4 = new Button();
myButton4.HorizontalAlignment = HorizontalAlignment.Stretch;
myButton4.Content = "Button 4 (Stretch)";

The preceding code yields a layout similar to the following image. The positioning effects of each HorizontalAlignment value are visible in the illustration.

HorizontalAlignment Sample

VerticalAlignment Property

The VerticalAlignment property describes the vertical alignment characteristics to apply to child elements. The following table shows each of the possible values for the VerticalAlignment property.

Member

Description

Top

Child elements are aligned to the top of the parent element's allocated layout space.

Center

Child elements are aligned to the center of the parent element's allocated layout space.

Bottom

Child elements are aligned to the bottom of the parent element's allocated layout space.

Stretch(Default)

Child elements are stretched to fill the parent element's allocated layout space. Explicit Width and Height values take precedence.

The following example shows how to apply the VerticalAlignment property to Button elements. Each attribute value is shown, to better illustrate the various rendering behaviors. For purposes of this sample, a Grid element with visible gridlines is used as the parent, to better illustrate the layout behavior of each property value.

TextBlock myTextBlock = new TextBlock();
myTextBlock.FontSize = 18;
myTextBlock.HorizontalAlignment = HorizontalAlignment.Center;
myTextBlock.Text = "VerticalAlignment Sample";
Grid.SetRow(myTextBlock, 0);
Button myButton1 = new Button();
myButton1.VerticalAlignment = VerticalAlignment.Top;
myButton1.Content = "Button 1 (Top)";
Grid.SetRow(myButton1, 1);
Button myButton2 = new Button();
myButton2.VerticalAlignment = VerticalAlignment.Bottom;
myButton2.Content = "Button 2 (Bottom)";
Grid.SetRow(myButton2, 2);
Button myButton3 = new Button();
myButton3.VerticalAlignment = VerticalAlignment.Center;
myButton3.Content = "Button 3 (Center)";
Grid.SetRow(myButton3, 3);
Button myButton4 = new Button();
myButton4.VerticalAlignment = VerticalAlignment.Stretch;
myButton4.Content = "Button 4 (Stretch)";
Grid.SetRow(myButton4, 4);
<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      WindowTitle="VerticalAlignment Sample">
  <Border Background="LightBlue" BorderBrush="Black" BorderThickness="2" Padding="15">
    <Grid Background="White" ShowGridLines="True">
      <Grid.RowDefinitions>
        <RowDefinition Height="25"/>
        <RowDefinition Height="50"/>
        <RowDefinition Height="50"/>
        <RowDefinition Height="50"/>
        <RowDefinition Height="50"/>
      </Grid.RowDefinitions>
            <TextBlock Grid.Row="0" Grid.Column="0" FontSize="18" HorizontalAlignment="Center">VerticalAlignment Sample</TextBlock>
            <Button Grid.Row="1" Grid.Column="0" VerticalAlignment="Top">Button 1 (Top)</Button>
            <Button Grid.Row="2" Grid.Column="0" VerticalAlignment="Bottom">Button 2 (Bottom)</Button>    
            <Button Grid.Row="3" Grid.Column="0" VerticalAlignment="Center">Button 3 (Center)</Button>
            <Button Grid.Row="4" Grid.Column="0" VerticalAlignment="Stretch">Button 4 (Stretch)</Button>          
    </Grid>
  </Border>    
</Page>

The preceding code yields a layout similar to the following image. The positioning effects of each VerticalAlignment value are visible in the illustration.

VerticalAlignment property sample

Understanding Margin Properties

The Margin property describes the distance between an element and its child or peers. Margin values can be uniform, by using syntax like Margin="20". With this syntax, a uniform Margin of 20 device independent pixels would be applied to the element. Margin values can also take the form of four distinct values, each value describing a distinct margin to apply to the left, top, right, and bottom (in that order), like Margin="0,10,5,25". Proper use of the Margin property enables very fine control of an element's rendering position and the rendering position of its neighbor elements and children.

System_CAPS_noteNote

A non-zero margin applies space outside the element's ActualWidth and ActualHeight.

The following example shows how to apply uniform margins around a group of Button elements. The Button elements are spaced evenly with a ten-pixel margin buffer in each direction.

Button myButton7 = new Button();
myButton7.Margin = new Thickness(10);
myButton7.Content = "Button 7";
Button myButton8 = new Button();
myButton8.Margin = new Thickness(10);
myButton8.Content = "Button 8";
Button myButton9 = new Button();
myButton9.Margin = new Thickness(10);
myButton9.Content = "Button 9";
<Button Margin="10">Button 7</Button>
<Button Margin="10">Button 8</Button>
<Button Margin="10">Button 9</Button>

In many instances, a uniform margin is not appropriate. In these cases, non-uniform spacing can be applied. The following example shows how to apply non-uniform margin spacing to child elements. Margins are described in this order: left, top, right, bottom.

Button myButton1 = new Button();
myButton1.Margin = new Thickness(0, 10, 0, 10);
myButton1.Content = "Button 1";
Button myButton2 = new Button();
myButton2.Margin = new Thickness(0, 10, 0, 10);
myButton2.Content = "Button 2";
Button myButton3 = new Button();
myButton3.Margin = new Thickness(0, 10, 0, 10);
<Button Margin="0,10,0,10">Button 1</Button>
<Button Margin="0,10,0,10">Button 2</Button>
<Button Margin="0,10,0,10">Button 3</Button>

Understanding the Padding Property

Padding is similar to Margin in most respects. The Padding property is exposed on only on a few classes, primarily as a convenience: BlockBorderControl, and TextBlock are samples of classes that expose a Padding property. The Padding property enlarges the effective size of a child element by the specified Thickness value.

The following example shows how to apply Padding to a parent Border element.

myBorder = new Border();
myBorder.Background = Brushes.LightBlue;
myBorder.BorderBrush = Brushes.Black;
myBorder.BorderThickness = new Thickness(2);
myBorder.CornerRadius = new CornerRadius(45);
myBorder.Padding = new Thickness(25);
<Border Background="LightBlue" 
        BorderBrush="Black" 
        BorderThickness="2" 
        CornerRadius="45" 
        Padding="25">

Using Alignment, Margins, and Padding in an Application

HorizontalAlignmentMarginPadding, and VerticalAlignment provide the positioning control necessary to create a complex user interface (UI). You can use the effects of each property to change child-element positioning, enabling flexibility in creating dynamic applications and user experiences.

The following example demonstrates each of the concepts that are detailed in this topic. Building on the infrastructure found in the first sample in this topic, this example adds a Grid element as a child of the Border in the first sample. Padding is applied to the parent Border element. The Grid is used to partition space between three child StackPanel elements. Button elements are again used to show the various effects of Margin and HorizontalAlignmentTextBlock elements are added to each ColumnDefinition to better define the various properties applied to the Button elements in each column.

mainWindow = new Window();

myBorder = new Border();
myBorder.Background = Brushes.LightBlue;
myBorder.BorderBrush = Brushes.Black;
myBorder.BorderThickness = new Thickness(2);
myBorder.CornerRadius = new CornerRadius(45);
myBorder.Padding = new Thickness(25);

// Define the Grid.
myGrid = new Grid();
myGrid.Background = Brushes.White;
myGrid.ShowGridLines = true;

// Define the Columns.
ColumnDefinition myColDef1 = new ColumnDefinition();
myColDef1.Width = new GridLength(1, GridUnitType.Auto);
ColumnDefinition myColDef2 = new ColumnDefinition();
myColDef2.Width = new GridLength(1, GridUnitType.Star);
ColumnDefinition myColDef3 = new ColumnDefinition();
myColDef3.Width = new GridLength(1, GridUnitType.Auto);

// Add the ColumnDefinitions to the Grid.
myGrid.ColumnDefinitions.Add(myColDef1);
myGrid.ColumnDefinitions.Add(myColDef2);
myGrid.ColumnDefinitions.Add(myColDef3);

// Add the first child StackPanel.
StackPanel myStackPanel = new StackPanel();
myStackPanel.HorizontalAlignment = HorizontalAlignment.Left;
myStackPanel.VerticalAlignment = VerticalAlignment.Top;
Grid.SetColumn(myStackPanel, 0);
Grid.SetRow(myStackPanel, 0);
TextBlock myTextBlock1 = new TextBlock();
myTextBlock1.FontSize = 18;
myTextBlock1.HorizontalAlignment = HorizontalAlignment.Center;
myTextBlock1.Margin = new Thickness(0, 0, 0, 15);
myTextBlock1.Text = "StackPanel 1";
Button myButton1 = new Button();
myButton1.Margin = new Thickness(0, 10, 0, 10);
myButton1.Content = "Button 1";
Button myButton2 = new Button();
myButton2.Margin = new Thickness(0, 10, 0, 10);
myButton2.Content = "Button 2";
Button myButton3 = new Button();
myButton3.Margin = new Thickness(0, 10, 0, 10);
TextBlock myTextBlock2 = new TextBlock();
myTextBlock2.Text = @"ColumnDefinition.Width = ""Auto""";
TextBlock myTextBlock3 = new TextBlock();
myTextBlock3.Text = @"StackPanel.HorizontalAlignment = ""Left""";
TextBlock myTextBlock4 = new TextBlock();
myTextBlock4.Text = @"StackPanel.VerticalAlignment = ""Top""";
TextBlock myTextBlock5 = new TextBlock();
myTextBlock5.Text = @"StackPanel.Orientation = ""Vertical""";
TextBlock myTextBlock6 = new TextBlock();
myTextBlock6.Text = @"Button.Margin = ""1,10,0,10""";
myStackPanel.Children.Add(myTextBlock1);
myStackPanel.Children.Add(myButton1);
myStackPanel.Children.Add(myButton2);
myStackPanel.Children.Add(myButton3);
myStackPanel.Children.Add(myTextBlock2);
myStackPanel.Children.Add(myTextBlock3);
myStackPanel.Children.Add(myTextBlock4);
myStackPanel.Children.Add(myTextBlock5);
myStackPanel.Children.Add(myTextBlock6);

// Add the second child StackPanel.
StackPanel myStackPanel2 = new StackPanel();
myStackPanel2.HorizontalAlignment = HorizontalAlignment.Stretch;
myStackPanel2.VerticalAlignment = VerticalAlignment.Top;
myStackPanel2.Orientation = Orientation.Vertical;
Grid.SetColumn(myStackPanel2, 1);
Grid.SetRow(myStackPanel2, 0);
TextBlock myTextBlock7 = new TextBlock();
myTextBlock7.FontSize = 18;
myTextBlock7.HorizontalAlignment = HorizontalAlignment.Center;
myTextBlock7.Margin = new Thickness(0, 0, 0, 15);
myTextBlock7.Text = "StackPanel 2";
Button myButton4 = new Button();
myButton4.Margin = new Thickness(10, 0, 10, 0);
myButton4.Content = "Button 4";
Button myButton5 = new Button();
myButton5.Margin = new Thickness(10, 0, 10, 0);
myButton5.Content = "Button 5";
Button myButton6 = new Button();
myButton6.Margin = new Thickness(10, 0, 10, 0);
myButton6.Content = "Button 6";
TextBlock myTextBlock8 = new TextBlock();
myTextBlock8.HorizontalAlignment = HorizontalAlignment.Center;
myTextBlock8.Text = @"ColumnDefinition.Width = ""*""";
TextBlock myTextBlock9 = new TextBlock();
myTextBlock9.HorizontalAlignment = HorizontalAlignment.Center;
myTextBlock9.Text = @"StackPanel.HorizontalAlignment = ""Stretch""";
TextBlock myTextBlock10 = new TextBlock();
myTextBlock10.HorizontalAlignment = HorizontalAlignment.Center;
myTextBlock10.Text = @"StackPanel.VerticalAlignment = ""Top""";
TextBlock myTextBlock11 = new TextBlock();
myTextBlock11.HorizontalAlignment = HorizontalAlignment.Center;
myTextBlock11.Text = @"StackPanel.Orientation = ""Horizontal""";
TextBlock myTextBlock12 = new TextBlock();
myTextBlock12.HorizontalAlignment = HorizontalAlignment.Center;
myTextBlock12.Text = @"Button.Margin = ""10,0,10,0""";
myStackPanel2.Children.Add(myTextBlock7);
myStackPanel2.Children.Add(myButton4);
myStackPanel2.Children.Add(myButton5);
myStackPanel2.Children.Add(myButton6);
myStackPanel2.Children.Add(myTextBlock8);
myStackPanel2.Children.Add(myTextBlock9);
myStackPanel2.Children.Add(myTextBlock10);
myStackPanel2.Children.Add(myTextBlock11);
myStackPanel2.Children.Add(myTextBlock12);

// Add the final child StackPanel.
StackPanel myStackPanel3 = new StackPanel();
myStackPanel3.HorizontalAlignment = HorizontalAlignment.Left;
myStackPanel3.VerticalAlignment = VerticalAlignment.Top;
Grid.SetColumn(myStackPanel3, 2);
Grid.SetRow(myStackPanel3, 0);
TextBlock myTextBlock13 = new TextBlock();
myTextBlock13.FontSize = 18;
myTextBlock13.HorizontalAlignment = HorizontalAlignment.Center;
myTextBlock13.Margin = new Thickness(0, 0, 0, 15);
myTextBlock13.Text = "StackPanel 3";
Button myButton7 = new Button();
myButton7.Margin = new Thickness(10);
myButton7.Content = "Button 7";
Button myButton8 = new Button();
myButton8.Margin = new Thickness(10);
myButton8.Content = "Button 8";
Button myButton9 = new Button();
myButton9.Margin = new Thickness(10);
myButton9.Content = "Button 9";
TextBlock myTextBlock14 = new TextBlock();
myTextBlock14.Text = @"ColumnDefinition.Width = ""Auto""";
TextBlock myTextBlock15 = new TextBlock();
myTextBlock15.Text = @"StackPanel.HorizontalAlignment = ""Left""";
TextBlock myTextBlock16 = new TextBlock();
myTextBlock16.Text = @"StackPanel.VerticalAlignment = ""Top""";
TextBlock myTextBlock17 = new TextBlock();
myTextBlock17.Text = @"StackPanel.Orientation = ""Vertical""";
TextBlock myTextBlock18 = new TextBlock();
myTextBlock18.Text = @"Button.Margin = ""10""";
myStackPanel3.Children.Add(myTextBlock13);
myStackPanel3.Children.Add(myButton7);
myStackPanel3.Children.Add(myButton8);
myStackPanel3.Children.Add(myButton9);
myStackPanel3.Children.Add(myTextBlock14);
myStackPanel3.Children.Add(myTextBlock15);
myStackPanel3.Children.Add(myTextBlock16);
myStackPanel3.Children.Add(myTextBlock17);
myStackPanel3.Children.Add(myTextBlock18);

// Add child content to the parent Grid.
myGrid.Children.Add(myStackPanel);
myGrid.Children.Add(myStackPanel2);
myGrid.Children.Add(myStackPanel3);

// Add the Grid as the lone child of the Border.
myBorder.Child = myGrid;

// Add the Border to the Window as Content and show the Window.
mainWindow.Content = myBorder;
mainWindow.Title = "Margin, Padding, and Alignment Sample";
mainWindow.Show();
<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" WindowTitle="Margins, Padding and Alignment Sample">
  <Border Background="LightBlue" 
          BorderBrush="Black" 
          BorderThickness="2" 
          CornerRadius="45" 
          Padding="25">
    <Grid Background="White" ShowGridLines="True">
      <Grid.ColumnDefinitions>
        <ColumnDefinition Width="Auto"/>
        <ColumnDefinition Width="*"/>
        <ColumnDefinition Width="Auto"/>
      </Grid.ColumnDefinitions>

    <StackPanel Grid.Column="0" Grid.Row="0" HorizontalAlignment="Left" Name="StackPanel1" VerticalAlignment="Top">
        <TextBlock FontSize="18" HorizontalAlignment="Center" Margin="0,0,0,15">StackPanel1</TextBlock>
        <Button Margin="0,10,0,10">Button 1</Button>
        <Button Margin="0,10,0,10">Button 2</Button>
        <Button Margin="0,10,0,10">Button 3</Button>
        <TextBlock>ColumnDefinition.Width="Auto"</TextBlock>
        <TextBlock>StackPanel.HorizontalAlignment="Left"</TextBlock>
        <TextBlock>StackPanel.VerticalAlignment="Top"</TextBlock>
        <TextBlock>StackPanel.Orientation="Vertical"</TextBlock>
        <TextBlock>Button.Margin="0,10,0,10"</TextBlock>
    </StackPanel>

    <StackPanel Grid.Column="1" Grid.Row="0" HorizontalAlignment="Stretch" Name="StackPanel2" VerticalAlignment="Top" Orientation="Vertical">
        <TextBlock FontSize="18" HorizontalAlignment="Center" Margin="0,0,0,15">StackPanel2</TextBlock>
        <Button Margin="10,0,10,0">Button 4</Button>
        <Button Margin="10,0,10,0">Button 5</Button>
        <Button Margin="10,0,10,0">Button 6</Button>
        <TextBlock HorizontalAlignment="Center">ColumnDefinition.Width="*"</TextBlock>
        <TextBlock HorizontalAlignment="Center">StackPanel.HorizontalAlignment="Stretch"</TextBlock>
        <TextBlock HorizontalAlignment="Center">StackPanel.VerticalAlignment="Top"</TextBlock>
        <TextBlock HorizontalAlignment="Center">StackPanel.Orientation="Horizontal"</TextBlock>
        <TextBlock HorizontalAlignment="Center">Button.Margin="10,0,10,0"</TextBlock>
    </StackPanel>        

    <StackPanel Grid.Column="2" Grid.Row="0" HorizontalAlignment="Left" Name="StackPanel3" VerticalAlignment="Top">
        <TextBlock FontSize="18" HorizontalAlignment="Center" Margin="0,0,0,15">StackPanel3</TextBlock>
        <Button Margin="10">Button 7</Button>
        <Button Margin="10">Button 8</Button>
        <Button Margin="10">Button 9</Button>
        <TextBlock>ColumnDefinition.Width="Auto"</TextBlock>
        <TextBlock>StackPanel.HorizontalAlignment="Left"</TextBlock>
        <TextBlock>StackPanel.VerticalAlignment="Top"</TextBlock>
        <TextBlock>StackPanel.Orientation="Vertical"</TextBlock>
        <TextBlock>Button.Margin="10"</TextBlock>      
    </StackPanel>
  </Grid>
  </Border>    
</Page>

When compiled, the preceding application yields a UI that looks like the following illustration. The effects of the various property values are evident in the spacing between elements, and significant property values for elements in each column are shown within TextBlock elements.

Several positioning properties in one application

What's Next

Positioning properties defined by the FrameworkElement class enable fine control of element placement within WPF applications. You now have several techniques you can use to better position elements using WPF.

Additional resources are available that explain WPF layout in greater detail. The Panels Overview topic contains more detail about the various Panelelements. The topic Walkthrough: My First WPF Desktop Application introduces advanced techniques that use layout elements to position components and bind their actions to data sources.





How-to Topics




How to: Make a UIElement Transparent or Semi-Transparent


https://msdn.microsoft.com/en-us/library/ms752049(v=vs.110).aspx

https://msdn.microsoft.com/en-us/library/ms752049(v=vs.110).aspx


This example shows how to make a UIElement transparent or semi-transparent. To make an element transparent or semi-transparent, you set its Opacity property. A value of 0.0 makes the element completely transparent, while a value of 1.0 makes the element completely opaque. A value of 0.5makes the element 50% opaque, and so on. An element's Opacity is set to 1.0 by default.

Example

The following example sets the Opacity of a button to 0.25, making it and its contents (in this case, the button's text) 25% opaque.

<!-- Both the button and its text are made 25% opaque. -->
<Button Opacity="0.25">A Button</Button>
//
// Both the button and its text are made 25% opaque.
//
Button myTwentyFivePercentOpaqueButton = new Button();
myTwentyFivePercentOpaqueButton.Opacity = new Double();
myTwentyFivePercentOpaqueButton.Opacity = 0.25;
myTwentyFivePercentOpaqueButton.Content = "A Button";

If an element's contents have their own Opacity settings, those values are multiplied against the containing elements Opacity.

The following example sets a button's Opacity to 0.25, and the Opacity of an Image control contained with in the button to 0.5. As a result, the image appears 12.5% opaque: 0.25 * 0.5 = 0.125.

<!-- The image contained within this button has an effective
     opacity of 0.125 (0.25 * 0.5 = 0.125). -->
<Button Opacity="0.25">
  <StackPanel Orientation="Horizontal">
    <TextBlock VerticalAlignment="Center" Margin="10">A Button</TextBlock>
    <Image Source="sampleImages\berries.jpg" Width="50" Height="50"
      Opacity="0.5"/>
  </StackPanel>
</Button>
//
// The image contained within this button has an 
// effective opacity of 0.125 (0.25*0.5 = 0.125);
//
Button myImageButton = new Button();
myImageButton.Opacity = new Double();
myImageButton.Opacity = 0.25;

StackPanel myImageStackPanel = new StackPanel();
myImageStackPanel.Orientation = Orientation.Horizontal;


TextBlock myTextBlock = new TextBlock();
myTextBlock.VerticalAlignment = VerticalAlignment.Center;
myTextBlock.Margin = new Thickness(10);
myTextBlock.Text = "A Button";
myImageStackPanel.Children.Add(myTextBlock);

Image myImage = new Image();
BitmapImage myBitmapImage = new BitmapImage();
myBitmapImage.BeginInit();
myBitmapImage.UriSource = new Uri("sampleImages/berries.jpg",UriKind.Relative);
myBitmapImage.EndInit();
myImage.Source = myBitmapImage;
ImageBrush myImageBrush = new ImageBrush(myBitmapImage);
myImage.Width = 50;
myImage.Height = 50;
myImage.Opacity = 0.5;
myImageStackPanel.Children.Add(myImage);
myImageButton.Content = myImageStackPanel;       

Another way to control the opacity of an element is to set the opacity of the Brush that paints the element. This approach enables you to selectively alter the opacity of portions of an element, and provides performance benefits over using the element's Opacity property. The following example sets the Opacity of a SolidColorBrush used to paint the button's Background is set to 0.25. As a result, the brush's background is 25% opaque, but its contents (the button's text) remain 100% opaque.

<!-- This button's background is made 25% opaque, but its
     text remains 100% opaque. -->
<Button>
  <Button.Background>
    <SolidColorBrush Color="Gray" Opacity="0.25" />
  </Button.Background>
  A Button
</Button>
//
//  This button's background is made 25% opaque, 
// but its text remains 100% opaque.
//
Button myOpaqueTextButton = new Button();
SolidColorBrush mySolidColorBrush = new SolidColorBrush(Colors.Gray);
mySolidColorBrush.Opacity = 0.25;
myOpaqueTextButton.Background = mySolidColorBrush;
myOpaqueTextButton.Content = "A Button"

You may also control the opacity of individual colors within a brush. For more information about colors and brushes, see Painting with Solid Colors and Gradients Overview. For an example showing how to animate an element's opacity, see How to: Animate the Opacity of an Element or Brush.





How to: Animate the Size of a FrameworkElement


To animate the size of a FrameworkElement, you can either animate its Width and Height properties or use an animated ScaleTransform.

In the following example animates the size of two buttons using these two approaches. One button is resized by animating its Width property and another is resized by animating a ScaleTransform applied to its RenderTransform property. Each button contains some text. Initially, the text appears the same in both buttons, but as the buttons are resized, the text in the second button becomes distorted.

Example

<!-- AnimatingSizeExample.xaml
     This example shows two ways of animating the size
     of a framework element. -->
<Page 
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  x:Class="Microsoft.Samples.Animation.AnimatingSizeExample" 
  WindowTitle="Animating Size Example">    
  <Canvas Width="650" Height="400">

    <Button Name="AnimatedWidthButton"
      Canvas.Left="20" Canvas.Top="20"      
      Width="200" Height="150"
      BorderBrush="Red" BorderThickness="5">
        Click Me
      <Button.Triggers>

        <!-- Animate the button's Width property. -->
        <EventTrigger RoutedEvent="Button.Loaded">
          <BeginStoryboard>
            <Storyboard>
              <DoubleAnimation
                Storyboard.TargetName="AnimatedWidthButton"
                Storyboard.TargetProperty="(Button.Width)"
                To="500" Duration="0:0:10" AutoReverse="True" 
                RepeatBehavior="Forever" />
            </Storyboard>
          </BeginStoryboard>
        </EventTrigger>
      </Button.Triggers>
    </Button>

    <Button 
      Canvas.Left="20" Canvas.Top="200"
      Width="200" Height="150"
      BorderBrush="Black" BorderThickness="3"> 
        Click Me
      <Button.RenderTransform>
         <ScaleTransform x:Name="MyAnimatedScaleTransform" 
          ScaleX="1" ScaleY="1"  />
      </Button.RenderTransform>
      <Button.Triggers>

        <!-- Animate the ScaleX property of a ScaleTransform
             applied to the button. -->
        <EventTrigger RoutedEvent="Button.Loaded">
          <BeginStoryboard>
            <Storyboard>
              <DoubleAnimation
                Storyboard.TargetName="MyAnimatedScaleTransform"
                Storyboard.TargetProperty="(ScaleTransform.ScaleX)"
                To="3.0" Duration="0:0:10" AutoReverse="True"
                RepeatBehavior="Forever" />
            </Storyboard>
          </BeginStoryboard>
        </EventTrigger>
      </Button.Triggers>      
    </Button>
  </Canvas> 
</Page>

When you transform an element, the entire element and its contents are transformed. When you directly alter the size of an element, as in the case of the first button, the element's contents are not resized unless their size and position depend on the size of their parent element.

Animating the size of an element by applying an animated transform to its RenderTransform property provides better performance than animated its Width and Height directly, because the RenderTransform property does not trigger a layout pass.

For more information about animating properties, see the Animation Overview. For more information about transforms, see the Transforms Overview.





How to: Determine Whether a Freezable Is Frozen


This example shows how to determine whether a Freezable object is frozen. If you try to modify a frozen Freezable object, it throws an InvalidOperationException. To avoid throwing this exception, use the IsFrozen property of the Freezable object to determine whether it is frozen.

Example

The following example freezes a SolidColorBrush and then tests it by using the IsFrozen property to determine whether it is frozen.

Button myButton = new Button();
SolidColorBrush myBrush = new SolidColorBrush(Colors.Yellow);

if (myBrush.CanFreeze)
{
    // Makes the brush unmodifiable.
    myBrush.Freeze();
}            

myButton.Background = myBrush;


if (myBrush.IsFrozen) // Evaluates to true.
{
    // If the brush is frozen, create a clone and
    // modify the clone.
    SolidColorBrush myBrushClone = myBrush.Clone();
    myBrushClone.Color = Colors.Red;
    myButton.Background = myBrushClone;
}
else
{
    // If the brush is not frozen,
    // it can be modified directly.
    myBrush.Color = Colors.Red;
}


For more information about Freezable objects, see the Freezable Objects Overview.





How to: Handle a Loaded Event


This example shows how handle the FrameworkElement.Loaded event, and an appropriate scenario for handling that event. The handler creates a Button when the page loads .

Example

The following example uses Extensible Application Markup Language (XAML) together with a code-behind file.

<StackPanel
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  x:Class="SDKSample.FELoaded"
  Loaded="OnLoad"
  Name="root"
>
</StackPanel>
void OnLoad(object sender, RoutedEventArgs e)
{
    Button b1 = new Button();
    b1.Content = "New Button";
    root.Children.Add(b1);
    b1.Height = 25;
    b1.Width = 200;
    b1.HorizontalAlignment = HorizontalAlignment.Left;
}





How to: Set Margins of Elements and Controls


This example describes how to set the Margin property, by changing any existing property value for the margin in code-behind. The Margin property is a property of the FrameworkElement base element, and is thus inherited by a variety of controls and other elements.

This example is written in Extensible Application Markup Language (XAML), with a code-behind file that the XAML refers to. The code-behind is shown in both a C# and a Microsoft Visual Basic version.

Example

<Button Click="OnClick" Margin="10" Name="btn1">
Click To See Change!!</Button>
void OnClick(object sender, RoutedEventArgs e)
{
    // Get the current value of the property.
    Thickness marginThickness = btn1.Margin;
    // If the current leftlength value of margin is set to 10 then change it to a new value.
    // Otherwise change it back to 10.
    if(marginThickness.Left == 10)
    {
         btn1.Margin = new Thickness(60);
    } else {
         btn1.Margin = new Thickness(10);
    }
}





How to: Make a Freezable Read-Only


This example shows how to make a Freezable read-only by calling its Freeze method.

You cannot freeze a Freezable object if any one of the following conditions is true about the object:

  • It has animated or data bound properties.

  • It has properties that are set by a dynamic resource. For more information about dynamic resources, see the XAML Resources.

  • It contains Freezable sub-objects that cannot be frozen.

If these conditions are false for your Freezable object and you do not intend to modify it, consider freezing it to gain performance benefits.

Example

The following example freezes a SolidColorBrush, which is a type of Freezable object.

Button myButton = new Button();
SolidColorBrush myBrush = new SolidColorBrush(Colors.Yellow);          

if (myBrush.CanFreeze)
{
    // Makes the brush unmodifiable.
    myBrush.Freeze();
}

myButton.Background = myBrush;   

For more information about Freezable objects, see the Freezable Objects Overview.





How to: Obtain a Writable Copy of a Read-Only Freezable


This example shows how to use the Clone method to create a writable copy of a read-only Freezable.

After a Freezable object is marked as read-only ("frozen"), you cannot modify it. However, you can use the Clone method to create a modifiable clone of the frozen object.

Example

The following example creates a modifiable clone of a frozen SolidColorBrush object.

Button myButton = new Button();
SolidColorBrush myBrush = new SolidColorBrush(Colors.Yellow);

// Freezing a Freezable before it provides
// performance improvements if you don't
// intend on modifying it. 
if (myBrush.CanFreeze)
{
    // Makes the brush unmodifiable.
    myBrush.Freeze();
}


myButton.Background = myBrush;  

// If you need to modify a frozen brush,
// the Clone method can be used to
// create a modifiable copy.
SolidColorBrush myBrushClone = myBrush.Clone();

// Changing myBrushClone does not change
// the color of myButton, because its
// background is still set by myBrush.
myBrushClone.Color = Colors.Red;

// Replacing myBrush with myBrushClone
// makes the button change to red.
myButton.Background = myBrushClone;

For more information about Freezable objects, see the Freezable Objects Overview.





How to: Flip a UIElement Horizontally or Vertically


This example shows how to use a ScaleTransform to flip a UIElement horizontally or vertically. In this example, a Button control (a type of UIElement) is flipped by applying a ScaleTransform to its RenderTransform property.

Example

The following illustration shows the button to flip.

A button with no transform

The UIElement to flip

The following shows the code that creates the button.

<Button Content="Flip me!" Padding="5">
</Button>

Example

To flip the button horizontally, create a ScaleTransform and set its ScaleX property to -1. Apply the ScaleTransform to the button's RenderTransformproperty.

<Button Content="Flip me!" Padding="5">
  <Button.RenderTransform>
    <ScaleTransform ScaleX="-1" />
  </Button.RenderTransform>
</Button>
A button flipped horizontally about (0,0)

The button after applying the ScaleTransform

Example

As you can see from the previous illustration, the button was flipped, but it was also moved. That's because the button was flipped from its top left corner. To flip the button in place, you want to apply the ScaleTransform to its center, not its corner. An easy way to apply the ScaleTransform to the buttons center is to set the button's RenderTransformOrigin property to 0.5, 0.5.

<Button Content="Flip me!" Padding="5"
  RenderTransformOrigin="0.5,0.5">
  <Button.RenderTransform>
    <ScaleTransform ScaleX="-1" />
  </Button.RenderTransform>
</Button>
A button flipped horizontally about its center

The button with a RenderTransformOrigin of 0.5, 0.5

Example

To flip the button vertically, set the ScaleTransform object's ScaleY property instead of its ScaleX property.

<Button Content="Flip me!" Padding="5"
  RenderTransformOrigin="0.5,0.5">
  <Button.RenderTransform>
    <ScaleTransform ScaleY="-1" />
  </Button.RenderTransform>
</Button>
A button flipped vertically about its center

The vertically flipped button





How to: Use a ThicknessConverter Object


Example

This example shows how to create an instance of ThicknessConverter and use it to change the thickness of a border.

The example defines a custom method called changeThickness; this method first converts the contents of a ListBoxItem, as defined in a separate Extensible Application Markup Language (XAML) file, to an instance of Thickness, and later converts the content into a String. This method passes the ListBoxItem to a ThicknessConverter object, which converts the Content of a ListBoxItem to an instance of Thickness. This value is then passed back as the value of the BorderThickness property of the Border.

This example does not run.

     private void changeThickness(object sender, SelectionChangedEventArgs args)
     {
ListBoxItem li = ((sender as ListBox).SelectedItem as ListBoxItem);
ThicknessConverter myThicknessConverter = new ThicknessConverter();
Thickness th1 = (Thickness)myThicknessConverter.ConvertFromString(li.Content.ToString());
         border1.BorderThickness = th1;
         bThickness.Text = "Border.BorderThickness =" + li.Content.ToString();
     }





How to: Handle the ContextMenuOpening Event


The ContextMenuOpening event can be handled in an application to either adjust an existing context menu prior to display or to suppress the menu that would otherwise be displayed by setting the Handled property to true in the event data. The typical reason for setting Handled to true in the event data is to replace the menu entirely with a new ContextMenu object, which sometimes requires canceling the operation and starting a new open. If you write handlers for the ContextMenuOpening event, you should be aware of timing issues between a ContextMenu control and the service that is responsible for opening and positioning context menus for controls in general. This topic illustrates some of the code techniques for various context menu opening scenarios and illustrates a case where the timing issue comes into play.

There are several scenarios for handling the ContextMenuOpening event:

  • Adjusting the menu items before display.

  • Replacing the entire menu before display.

  • Completely suppressing any existing context menu and displaying no context menu.

Example

Adjusting the Menu Items Before Display

Adjusting the existing menu items is fairly simple and is probably the most common scenario. You might do this in order to add or subtract context menu options in response to current state information in your application or particular state information that is available as a property on the object where the context menu is requested.

The general technique is to get the source of the event, which is the specific control that was right-clicked, and get the ContextMenu property from it. You typically want to check the Items collection to see what context menu items already exist in the menu, and then add or remove appropriate new MenuItem items to or from the collection.

void AddItemToCM(object sender, ContextMenuEventArgs e)
{
    //check if Item4 is already there, this will probably run more than once
    FrameworkElement fe = e.Source as FrameworkElement;
    ContextMenu cm = fe.ContextMenu;
    foreach (MenuItem mi in cm.Items)
    {
        if ((String)mi.Header == "Item4") return;
    }
    MenuItem mi4 = new MenuItem();
    mi4.Header = "Item4";
    fe.ContextMenu.Items.Add(mi4);
}

Replacing the Entire Menu Before Display

An alternative scenario is if you want to replace the entire context menu. You could of course also use a variation of the preceding code, to remove every item of an existing context menu and add new ones starting with item zero. But the more intuitive approach for replacing all items in the context menu is to create a new ContextMenu, populate it with items, and then set the FrameworkElement.ContextMenu property of a control to be the new ContextMenu.

The following is the simple handler code for replacing a ContextMenu. The code references a custom BuildMenu method, which is separated out because it is called by more than one of the example handlers.

void HandlerForCMO(object sender, ContextMenuEventArgs e)
{
    FrameworkElement fe = e.Source as FrameworkElement;
    fe.ContextMenu = BuildMenu();
}
ContextMenu BuildMenu()
{
    ContextMenu theMenu = new ContextMenu();
    MenuItem mia = new MenuItem();
    mia.Header = "Item1";
    MenuItem mib = new MenuItem();
    mib.Header = "Item2";
    MenuItem mic = new MenuItem();
    mic.Header = "Item3";
    theMenu.Items.Add(mia);
    theMenu.Items.Add(mib);
    theMenu.Items.Add(mic);
    return theMenu;
}

However, if you use this style of handler for ContextMenuOpening, you can potentially expose a timing issue if the object where you are setting the ContextMenu does not have a preexisting context menu. When a user right-clicks a control, ContextMenuOpening is raised even if the existing ContextMenu is empty or null. But in this case, whatever new ContextMenu you set on the source element arrives too late to be displayed. Also, if the user happens to right-click a second time, this time your new ContextMenu appears, the value is non null, and your handler will properly replace and display the menu when the handler runs a second time. This suggests two possible workarounds:

  1. Insure that ContextMenuOpening handlers always run against controls that have at least a placeholder ContextMenu available, which you intend to be replaced by the handler code. In this case, you can still use the handler shown in the previous example, but you typically want to assign a placeholder ContextMenu in the initial markup:

    <StackPanel>
      <Rectangle Fill="Yellow" Width="200" Height="100" ContextMenuOpening="HandlerForCMO">
        <Rectangle.ContextMenu>
          <ContextMenu>
            <MenuItem>Initial menu; this will be replaced ...</MenuItem>
          </ContextMenu>
        </Rectangle.ContextMenu>
      </Rectangle>
      <TextBlock>Right-click the rectangle above, context menu gets replaced</TextBlock>
    </StackPanel>
    
  2. Assume that the initial ContextMenu value might be null, based on some preliminary logic. You could either check ContextMenu for null, or use a flag in your code to check whether your handler has been run at least once. Because you assume that the ContextMenu is about to be displayed, your handler then sets Handled to true in the event data. To the ContextMenuService that is responsible for context menu display, a true value for Handled in the event data represents a request to cancel the display for the context menu / control combination that raised the event.

Now that you have suppressed the potentially suspect context menu, the next step is to supply a new one, then display it. Setting the new one is basically the same as the previous handler: you build a new ContextMenu and set the control source's FrameworkElement.ContextMenu property with it. The additional step is that you must now force the display of the context menu, because you suppressed the first attempt. To force the display, you set the Popup.IsOpen property to true within the handler. Be careful when you do this, because opening the context menu in the handler raises the ContextMenuOpening event again. If you reenter your handler, it becomes infinitely recursive. This is why you always need to check for null or use a flag if you open a context menu from within a ContextMenuOpening event handler.

Suppressing Any Existing Context Menu and Displaying No Context Menu

The final scenario, writing a handler that suppresses a menu totally, is uncommon. If a given control is not supposed to display a context menu, there are probably more appropriate ways to assure this than by suppressing the menu just when a user requests it. But if you want to use the handler to suppress a context menu and show nothing, then your handler should simply set Handled to true in the event data. The ContextMenuService that is responsible for displaying a context menu will check the event data of the event it raised on the control. If the event was marked Handled anywhere along the route, then the context menu open action that initiated the event is suppressed.

       void HandlerForCMO2(object sender, ContextMenuEventArgs e)
       {
           if (!FlagForCustomContextMenu)
           {
               e.Handled = true; //need to suppress empty menu
               FrameworkElement fe = e.Source as FrameworkElement;
               fe.ContextMenu = BuildMenu();
               FlagForCustomContextMenu = true;
               fe.ContextMenu.IsOpen = true;
           }
       }
}























'프로그래밍 > WPF' 카테고리의 다른 글

Events  (0) 2016.11.01
Element Tree and Serialization  (0) 2016.11.01
종속성 속성(Dependency Properties)  (0) 2016.10.24
WPF 고급 - 끌어서 놓기 (Drag and Drop)  (0) 2016.10.21
WPF 고급 - 입력 (Input)  (0) 2016.10.15
:
Posted by 지훈2