달력

8

« 2025/8 »

  • 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
  • 29
  • 30
  • 31

고급 - 끌어서 놓기


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

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




Drag and Drop Overview


This topic provides an overview of drag-and-drop support in Windows Presentation Foundation (WPF) applications. Drag-and-drop commonly refers to a method of data transfer that involves using a mouse (or some other pointing device) to select one or more objects, dragging these objects over some desired drop target in the user interface (UI), and dropping them.

Drag-and-Drop Support in WPF

Drag-and-drop operations typically involve two parties: a drag source from which the dragged object originates and a drop target which receives the dropped object. The drag source and drop target may be UI elements in the same application or a different application.

The type and number of objects that can be manipulated with drag-and-drop is completely arbitrary. For example, files, folders, and selections of content are some of the more common objects manipulated through drag-and-drop operations.

The particular actions performed during a drag-and-drop operation are application specific, and often determined by context. For example, dragging a selection of files from one folder to another on the same storage device moves the files by default, whereas dragging files from a Universal Naming Convention (UNC) share to a local folder copies the files by default.

The drag-and-drop facilities provided by WPF are designed to be highly flexible and customizable to support a wide variety of drag-and-drop scenarios. Drag-and-drop supports manipulating objects within a single application, or between different applications. Dragging-and-dropping between WPF applications and other Windows applications is also fully supported.

In WPF, any UIElement or ContentElement can participate in drag-and-drop. The events and methods required for drag-and-drop operations are defined in the DragDrop class. The UIElement and ContentElement classes contain aliases for the DragDrop attached events so that the events appear in the class members list when a UIElement or ContentElement is inherited as a base element. Event handlers that are attached to these events are attached to the underlying DragDrop attached event and receive the same event data instance. For more information, see the UIElement.Drop event.

System_CAPS_security Security Note

OLE drag-and-drop does not work while in the Internet zone.

Data Transfer

Drag-and-drop is part of the more general area of data transfer. Data transfer includes drag-and-drop and copy-and-paste operations. A drag-and-drop operation is analogous to a copy-and-paste or cut-and-paste operation that is used to transfer data from one object or application to another by using the system clipboard. Both types of operations require:

  • A source object that provides the data.

  • A way to temporarily store the transferred data.

  • A target object that receives the data.

In a copy-and-paste operation, the system clipboard is used to temporarily store the transferred data; in a drag-and-drop operation, a DataObject is used to store the data. Conceptually, a data object consists of one or more pairs of an Object that contains the actual data, and a corresponding data format identifier.

The drag source initiates a drag-and-drop operation by calling the static DragDrop.DoDragDrop method and passing the transferred data to it. The DoDragDrop method will automatically wrap the data in a DataObject if necessary. For greater control over the data format, you can wrap the data in a DataObject before passing it to the DoDragDrop method. The drop target is responsible for extracting the data from the DataObject. For more information about working with data objects, see Data and Data Objects.

The source and target of a drag-and-drop operation are UI elements; however, the data that is actually being transferred typically does not have a visual representation. You can write code to provide a visual representation of the data that is dragged, such as occurs when dragging files in Windows Explorer. By default, feedback is provided to the user by changing the cursor to represent the effect that the drag-and-drop operation will have on the data, such as whether the data will be moved or copied.

Drag-and-Drop Effects

Drag-and-drop operations can have different effects on the transferred data. For example, you can copy the data or you can move the data. WPF defines a DragDropEffects enumeration that you can use to specify the effect of a drag-and-drop operation. In the drag source, you can specify the effects that the source will allow in the DoDragDrop method. In the drop target, you can specify the effect that the target intends in the Effectsproperty of the DragEventArgs class. When the drop target specifies its intended effect in the DragOver event, that information is passed back to the drag source in the GiveFeedback event. The drag source uses this information to inform the user what effect the drop target intends to have on the data. When the data is dropped, the drop target specifies its actual effect in the Drop event. That information is passed back to the drag source as the return value of the DoDragDrop method. If the drop target returns an effect that is not in the drag sources list of allowedEffects, the drag-and-drop operation is cancelled without any data transfer occurring.

It is important to remember that in WPF, the DragDropEffects values are only used to provide communication between the drag source and the drop target regarding the effects of the drag-and-drop operation. The actual effect of the drag-and-drop operation depends on you to write the appropriate code in your application.

For example, the drop target might specify that the effect of dropping data on it is to move the data. However, to move the data, it must be both added to the target element and removed from the source element. The source element might indicate that it allows moving the data, but if you do not provide the code to remove the data from the source element, the end result will be that the data is copied, and not moved.

Drag-and-Drop Events

Drag-and-drop operations support an event driven model. Both the drag source and the drop target use a standard set of events to handle drag-and-drop operations. The following tables summarize the standard drag-and-drop events. These are attached events on the DragDrop class. For more information about attached events, see Attached Events Overview.

Drag Source Events

Event

Summary

GiveFeedback

This event occurs continuously during a drag-and-drop operation, and enables the drop source to give feedback information to the user. This feedback is commonly given by changing the appearance of the mouse pointer to indicate the effects allowed by the drop target. This is a bubbling event.

QueryContinueDrag

This event occurs when there is a change in the keyboard or mouse button states during a drag-and-drop operation, and enables the drop source to cancel the drag-and-drop operation depending on the key/button states. This is a bubbling event.

PreviewGiveFeedback

Tunneling version of GiveFeedback.

PreviewQueryContinueDrag

Tunneling version of QueryContinueDrag.

Drop Target Events

Event

Summary

DragEnter

This event occurs when an object is dragged into the drop target's boundary. This is a bubbling event.

DragLeave

This event occurs when an object is dragged out of the drop target's boundary. This is a bubbling event.

DragOver

This event occurs continuously while an object is dragged (moved) within the drop target's boundary. This is a bubbling event.

Drop

This event occurs when an object is dropped on the drop target. This is a bubbling event.

PreviewDragEnter

Tunneling version of DragEnter.

PreviewDragLeave

Tunneling version of DragLeave.

PreviewDragOver

Tunneling version of DragOver.

PreviewDrop

Tunneling version of Drop.

To handle drag-and-drop events for instances of an object, add handlers for the events listed in the preceding tables. To handle drag-and-drop events at the class level, override the corresponding virtual On*Event and On*PreviewEvent methods. For more information, see Class Handling of Routed Events by Control Base Classes.

Implementing Drag-and-Drop

A UI element can be a drag source, a drop target, or both. To implement basic drag-and-drop, you write code to initiate the drag-and-drop operation and to process the dropped data. You can enhance the drag-and-drop experience by handling optional drag-and-drop events.

To implement basic drag-and-drop, you will complete the following tasks:

  • Identify the element that will be a drag source. A drag source can be a UIElement or a ContentElement.

  • Create an event handler on the drag source that will initiate the drag-and-drop operation. The event is typically the MouseMove event.

  • In the drag source event handler, call the DoDragDrop method to initiate the drag-and-drop operation. In the DoDragDrop call, specify the drag source, the data to be transferred, and the allowed effects.

  • Identify the element that will be a drop target. A drop target can be UIElement or a ContentElement.

  • On the drop target, set the AllowDrop property to true.

  • In the drop target, create a Drop event handler to process the dropped data.

  • In the Drop event handler, extract the data from the DragEventArgs by using the GetDataPresent and GetData methods.

  • In the Drop event handler, use the data to perform the desired drag-and-drop operation.

You can enhance your drag-and-drop implementation by creating a custom DataObject and by handling optional drag source and drop target events, as shown in the following tasks:

  • To transfer custom data or multiple data items, create a DataObject to pass to the DoDragDrop method.

  • To perform additional actions during a drag, handle the DragEnterDragOver, and DragLeave events on the drop target.

  • To change the appearance of the mouse pointer, handle the GiveFeedback event on the drag source.

  • To change how the drag-and-drop operation is canceled, handle the QueryContinueDrag event on the drag source.

Drag-and-Drop Example

This section describes how to implement drag-and-drop for an Ellipse element. The Ellipse is both a drag source and a drop target. The transferred data is the string representation of the ellipse’s Fill property. The following XAML shows the Ellipse element and the drag-and-drop related events that it handles. For complete steps on how to implement drag-and-drop, see Walkthrough: Enabling Drag and Drop on a User Control.

<Ellipse Height="50" Width="50" Fill="Green"
     MouseMove="ellipse_MouseMove"
     GiveFeedback="ellipse_GiveFeedback"
     AllowDrop="True"
     DragEnter="ellipse_DragEnter" DragLeave="ellipse_DragLeave"
     DragOver="ellipse_DragOver" Drop="ellipse_Drop" />

Enabling an Element to be a Drag Source

An object that is a drag source is responsible for:

  • Identifying when a drag occurs.

  • Initiating the drag-and-drop operation.

  • Identifying the data to be transferred.

  • Specifying the effects that the drag-and-drop operation is allowed to have on the transferred data.

The drag source may also give feedback to the user regarding the allowed actions (move, copy, none), and can cancel the drag-and-drop operation based on additional user input, such as pressing the ESC key during the drag.

It is the responsibility of your application to determine when a drag occurs, and then initiate the drag-and-drop operation by calling the DoDragDrop method. Typically, this is when a MouseMove event occurs over the element to be dragged while a mouse button is pressed. The following example shows how to initiate a drag-and-drop operation from the MouseMove event handler of an Ellipse element to make it a drag source. The transferred data is the string representation of the ellipse’s Fill property.

private void ellipse_MouseMove(object sender, MouseEventArgs e)
{
    Ellipse ellipse = sender as Ellipse;
    if (ellipse != null && e.LeftButton == MouseButtonState.Pressed)
    {
        DragDrop.DoDragDrop( ellipse,
                             ellipse.Fill.ToString(),
                             DragDropEffects.Copy);
    }
}

Inside of the MouseMove event handler, call the DoDragDrop method to initiate the drag-and-drop operation. The DoDragDrop method takes three parameters:

  • dragSource – A reference to the dependency object that is the source of the transferred data; this is typically the source of the MouseMoveevent.

  • data - An object that contains the transferred data, wrapped in a DataObject.

  • allowedEffects - One of the DragDropEffects enumeration values that specifies the permitted effects of the drag-and-drop operation.

Any serializable object can be passed in the data parameter. If the data is not already wrapped in a DataObject, it will automatically be wrapped in a new DataObject. To pass multiple data items, you must create the DataObject yourself, and pass it to the DoDragDrop method. For more information, see Data and Data Objects.

The allowedEffects parameter is used to specify what the drag source will allow the drop target to do with the transferred data. The common values for a drag source are CopyMove, and All.

System_CAPS_noteNote

The drop target is also able to specify what effects it intends in response to the dropped data. For example, if the drop target does not recognize the data type to be dropped, it can refuse the data by setting its allowed effects to None. It typically does this in its DragOver event handler.

A drag source can optionally handle the GiveFeedback and QueryContinueDrag events. These events have default handlers that are used unless you mark the events as handled. You will typically ignore these events unless you have a specific need to change their default behavior.

The GiveFeedback event is raised continuously while the drag source is being dragged. The default handler for this event checks whether the drag source is over a valid drop target. If it is, it checks the allowed effects of the drop target. It then gives feedback to the end user regarding the allowed drop effects. This is typically done by changing the mouse cursor to a no-drop, copy, or move cursor. You should only handle this event if you need to use custom cursors to provide feedback to the user. If you handle this event, be sure to mark it as handled so that the default handler does not override your handler.

The QueryContinueDrag event is raised continuously while the drag source is being dragged. You can handle this event to determine what action ends the drag-and-drop operation based on the state of the ESC, SHIFT, CTRL, and ALT keys, as well as the state of the mouse buttons. The default handler for this event cancels the drag-and-drop operation if the ESC key is pressed, and drops the data if the mouse button is released.

System_CAPS_cautionCaution

These events are raised continuously during the drag-and-drop operation. Therefore, you should avoid resource-intensive tasks in the event handlers. For example, use a cached cursor instead of creating a new cursor each time the GiveFeedback event is raised.

Enabling an Element to be a Drop Target

An object that is a drop target is responsible for:

  • Specifying that it is a valid drop target.

  • Responding to the drag source when it drags over the target.

  • Checking that the transferred data is in a format that it can receive.

  • Processing the dropped data.

To specify that an element is a drop target, you set its AllowDrop property to true. The drop target events will then be raised on the element so that you can handle them. During a drag-and-drop operation, the following sequence of events occurs on the drop target:

  1. DragEnter

  2. DragOver

  3. DragLeave or Drop

The DragEnter event occurs when the data is dragged into the drop target's boundary. You typically handle this event to provide a preview of the effects of the drag-and-drop operation, if appropriate for your application. Do not set the DragEventArgs.Effects property in the DragEnter event, as it will be overwritten in the DragOver event.

The following example shows the DragEnter event handler for an Ellipse element. This code previews the effects of the drag-and-drop operation by saving the current Fill brush. It then uses the GetDataPresent method to check whether the DataObject being dragged over the ellipse contains string data that can be converted to a Brush. If so, the data is extracted using the GetData method. It is then converted to a Brush and applied to the ellipse. The change is reverted in the DragLeave event handler. If the data cannot be converted to a Brush, no action is performed.

private Brush _previousFill = null;
private void ellipse_DragEnter(object sender, DragEventArgs e)
{
    Ellipse ellipse = sender as Ellipse;
    if (ellipse != null)
    {
        // Save the current Fill brush so that you can revert back to this value in DragLeave.
        _previousFill = ellipse.Fill;

        // If the DataObject contains string data, extract it.
        if (e.Data.GetDataPresent(DataFormats.StringFormat))
        {
            string dataString = (string)e.Data.GetData(DataFormats.StringFormat);

            // If the string can be converted into a Brush, convert it.
            BrushConverter converter = new BrushConverter();
            if (converter.IsValid(dataString))
            {
                Brush newFill = (Brush)converter.ConvertFromString(dataString);
                ellipse.Fill = newFill;
            }
        }
    }
}

The DragOver event occurs continuously while the data is dragged over the drop target. This event is paired with the GiveFeedback event on the drag source. In the DragOver event handler, you typically use the GetDataPresent and GetData methods to check whether the transferred data is in a format that the drop target can process. You can also check whether any modifier keys are pressed, which will typically indicate whether the user intends a move or copy action. After these checks are performed, you set the DragEventArgs.Effects property to notify the drag source what effect dropping the data will have. The drag source receives this information in the GiveFeedback event args, and can set an appropriate cursor to give feedback to the user.

The following example shows the DragOver event handler for an Ellipse element. This code checks to see if the DataObject being dragged over the ellipse contains string data that can be converted to a Brush. If so, it sets the DragEventArgs.Effects property to Copy. This indicates to the drag source that the data can be copied to the ellipse. If the data cannot be converted to a Brush, the DragEventArgs.Effects property is set to None. This indicates to the drag source that the ellipse is not a valid drop target for the data.

private void ellipse_DragOver(object sender, DragEventArgs e)
{
    e.Effects = DragDropEffects.None;

    // If the DataObject contains string data, extract it.
    if (e.Data.GetDataPresent(DataFormats.StringFormat))
    {
        string dataString = (string)e.Data.GetData(DataFormats.StringFormat);

        // If the string can be converted into a Brush, allow copying.
        BrushConverter converter = new BrushConverter();
        if (converter.IsValid(dataString))
        {
            e.Effects = DragDropEffects.Copy | DragDropEffects.Move;
        }
    }
}

The DragLeave event occurs when the data is dragged out of the target's boundary without being dropped. You handle this event to undo anything that you did in the DragEnter event handler.

The following example shows the DragLeave event handler for an Ellipse element. This code undoes the preview performed in the DragEnter event handler by applying the saved Brush to the ellipse.

private void ellipse_DragLeave(object sender, DragEventArgs e)
{
    Ellipse ellipse = sender as Ellipse;
    if (ellipse != null)
    {
        ellipse.Fill = _previousFill;
    }
}

The Drop event occurs when the data is dropped over the drop target; by default, this happens when the mouse button is released. In the Dropevent handler, you use the GetData method to extract the transferred data from the DataObject and perform any data processing that your application requires. The Drop event ends the drag-and-drop operation.

The following example shows the Drop event handler for an Ellipse element. This code applies the effects of the drag-and-drop operation, and is similar to the code in the DragEnter event handler. It checks to see if the DataObject being dragged over the ellipse contains string data that can be converted to a Brush. If so, the Brush is applied to the ellipse. If the data cannot be converted to a Brush, no action is performed.

private void ellipse_Drop(object sender, DragEventArgs e)
{
    Ellipse ellipse = sender as Ellipse;
    if (ellipse != null)
    {
        // If the DataObject contains string data, extract it.
        if (e.Data.GetDataPresent(DataFormats.StringFormat))
        {
            string dataString = (string)e.Data.GetData(DataFormats.StringFormat);

            // If the string can be converted into a Brush, 
            // convert it and apply it to the ellipse.
            BrushConverter converter = new BrushConverter();
            if (converter.IsValid(dataString))
            {
                Brush newFill = (Brush)converter.ConvertFromString(dataString);
                ellipse.Fill = newFill;
            }
        }
    }
}





Data and Data Objects


Data that is transferred as part of a drag-and-drop operation is stored in a data object. Conceptually, a data object consists of one or more of the following pairs:

  • An Object that contains the actual data.

  • A corresponding data format identifier.

The data itself can consist of anything that can be represented as a base Object. The corresponding data format is a string or Type that provides a hint about what format the data is in. Data objects support hosting multiple data/data format pairs; this enables a single data object to provide data in multiple formats.

Data Objects

All data objects must implement the IDataObject interface, which provides the following standard set of methods that enable and facilitate data transfer.

Method

Summary

GetData

Retrieves a data object in a specified data format.

GetDataPresent

Checks to see whether the data is available in, or can be converted to, a specified format.

GetFormats

Returns a list of formats that the data in this data object is stored in, or can be converted to.

SetData

Stores the specified data in this data object.

WPF provides a basic implementation of IDataObject in the DataObject class. The stock DataObject class is sufficient for many common data transfer scenarios.

There are several pre-defined formats, such as bitmap, CSV, file, HTML, RTF, string, text, and audio. For information about pre-defined data formats provided with WPF, see the DataFormats class reference topic.

Data objects commonly include a facility for automatically converting data stored in one format to a different format while extracting data; this facility is referred to as auto-convert. When querying for the data formats available in a data object, auto-convertible data formats can be filtered from native data formats by calling the GetFormats(Boolean) or GetDataPresent(String, Boolean) method and specifying the autoConvert parameter as false. When adding data to a data object with the SetData(String, Object, Boolean) method, auto-conversion of data can be prohibited by setting the autoConvert parameter to false.

Working with Data Objects

This section describes common techniques for creating and working with data objects.

Creating New Data Objects

The DataObject class provides several overloaded constructors that facilitate populating a new DataObject instance with a single data/data format pair.

The following example code creates a new data object and uses one of the overloaded constructors DataObject(DataObject(String, Object)) to initialize the data object with a string and a specified data format. In this case, the data format is specified by a string; the DataFormats class provides a set of pre-defined type strings. Auto-conversion of the stored data is allowed by default.

string stringData = "Some string data to store...";
string dataFormat = DataFormats.UnicodeText;
DataObject dataObject = new DataObject(dataFormat, stringData);

For more examples of code that creates a data object, see How to: Create a Data Object.

Storing Data in Multiple Formats

A single data object is able to store data in multiple formats. Strategic use of multiple data formats within a single data object potentially makes the data object consumable by a wider variety of drop targets than if only a single data format could be represented. Note that, in general, a drag source must be agnostic about the data formats that are consumable by potential drop targets.

The following example shows how to use the SetData(String, Object) method to add data to a data object in multiple formats.

DataObject dataObject = new DataObject();
string sourceData = "Some string data to store...";

// Encode the source string into Unicode byte arrays.
byte[] unicodeText = Encoding.Unicode.GetBytes(sourceData); // UTF-16
byte[] utf8Text = Encoding.UTF8.GetBytes(sourceData);
byte[] utf32Text = Encoding.UTF32.GetBytes(sourceData);

// The DataFormats class does not provide data format fields for denoting
// UTF-32 and UTF-8, which are seldom used in practice; the following strings 
// will be used to identify these "custom" data formats.
string utf32DataFormat = "UTF-32";
string utf8DataFormat  = "UTF-8";

// Store the text in the data object, letting the data object choose
// the data format (which will be DataFormats.Text in this case).
dataObject.SetData(sourceData);
// Store the Unicode text in the data object.  Text data can be automatically
// converted to Unicode (UTF-16 / UCS-2) format on extraction from the data object; 
// Therefore, explicitly converting the source text to Unicode is generally unnecessary, and
// is done here as an exercise only.
dataObject.SetData(DataFormats.UnicodeText, unicodeText);
// Store the UTF-8 text in the data object...
dataObject.SetData(utf8DataFormat, utf8Text);
// Store the UTF-32 text in the data object...
dataObject.SetData(utf32DataFormat, utf32Text);

Querying a Data Object for Available Formats

Because a single data object can contain an arbitrary number of data formats, data objects include facilities for retrieving a list of available data formats.

The following example code uses the GetFormats overload to get an array of strings denoting all data formats available in a data object (both native and by auto-convert).

DataObject dataObject = new DataObject("Some string data to store...");

// Get an array of strings, each string denoting a data format
// that is available in the data object.  This overload of GetDataFormats
// returns all available data formats, native and auto-convertible.
string[] dataFormats = dataObject.GetFormats();

// Get the number of data formats present in the data object, including both
// auto-convertible and native data formats.
int numberOfDataFormats = dataFormats.Length;

// To enumerate the resulting array of data formats, and take some action when
// a particular data format is found, use a code structure similar to the following.
foreach (string dataFormat in dataFormats)
{
    if (dataFormat == DataFormats.Text)
    {
        // Take some action if/when data in the Text data format is found.
        break;
    }
    else if(dataFormat == DataFormats.StringFormat)
    {
        // Take some action if/when data in the string data format is found.
        break;
    }
}

For more examples of code that queries a data object for available data formats, see How to: List the Data Formats in a Data Object. For examples of querying a data object for the presence of a particular data format, see How to: Determine if a Data Format is Present in a Data Object.

Retrieving Data from a Data Object

Retrieving data from a data object in a particular format simply involves calling one of the GetData methods and specifying the desired data format. One of the GetDataPresent methods can be used to check for the presence of a particular data format. GetData returns the data in an Object; depending on the data format, this object can be cast to a type-specific container.

The following example code uses the GetDataPresent(String) overload to check if a specified data format is available (native or by auto-convert). If the specified format is available, the example retrieves the data by using the GetData(String) method.

DataObject dataObject = new DataObject("Some string data to store...");

string desiredFormat = DataFormats.UnicodeText;
byte[] data = null;

// Use the GetDataPresent method to check for the presence of a desired data format.
// This particular overload of GetDataPresent looks for both native and auto-convertible 
// data formats.
if (dataObject.GetDataPresent(desiredFormat))
{
    // If the desired data format is present, use one of the GetData methods to retrieve the
    // data from the data object.
    data = dataObject.GetData(desiredFormat) as byte[];
}

For more examples of code that retrieves data from a data object, see How to: Retrieve Data in a Particular Data Format.

Removing Data From a Data Object

Data cannot be directly removed from a data object. To effectively remove data from a data object, follow these steps:

  1. Create a new data object that will contain only the data you want to retain.

  2. "Copy" the desired data from the old data object to the new data object. To copy the data, use one of the GetData methods to retrieve an Object that contains the raw data, and then use one of the SetData methods to add the data to the new data object.

  3. Replace the old data object with the new one.

System_CAPS_noteNote

The SetData methods only add data to a data object; they do not replace data, even if the data and data format are exactly the same as a previous call. Calling SetData twice for the same data and data format will result in the data/data format being present twice in the data object.





Walkthrough: Enabling Drag and Drop on a User Control


This walkthrough demonstrates how to create a custom user control that can participate in drag-and-drop data transfer in Windows Presentation Foundation (WPF).

In this walkthrough, you will create a custom WPF UserControl that represents a circle shape. You will implement functionality on the control to enable data transfer through drag-and-drop. For example, if you drag from one Circle control to another, the Fill color data is copied from the source Circle to the target. If you drag from a Circle control to a TextBox, the string representation of the Fill color is copied to the TextBox. You will also create a small application that contains two panel controls and a TextBox to test the drag-and-drop functionality. You will write code that enables the panels to process dropped Circle data, which will enable you to move or copy Circles from the Children collection of one panel to the other.

This walkthrough illustrates the following tasks:

  • Create a custom user control.

  • Enable the user control to be a drag source.

  • Enable the user control to be a drop target.

  • Enable a panel to receive data dropped from the user control.

Prerequisites

You need the following components to complete this walkthrough:

  • Visual Studio 2010

Creating the Application Project

In this section, you will create the application infrastructure, which includes a main page with two panels and a TextBox.

To create the project

  1. Create a new WPF Application project in Visual Basic or Visual C# named DragDropExample. For more information, see How to: Create a New WPF Application Project.

  2. Open MainWindow.xaml.

  3. Add the following markup between the opening and closing Grid tags.

    This markup creates the user interface for the test application.

    <Grid.ColumnDefinitions>
        <ColumnDefinition />
        <ColumnDefinition />
    </Grid.ColumnDefinitions>
    <StackPanel Grid.Column="0"
                Background="Beige">
        <TextBox Width="Auto" Margin="2"
                 Text="green"/>
    </StackPanel>
    <StackPanel Grid.Column="1"
                Background="Bisque">
    </StackPanel>
    

Adding a New User Control to the Project

In this section, you will add a new user control to the project.

To add a new user control

  1. On the Project menu, select Add User Control.

  2. In the Add New Item dialog box, change the name to Circle.xaml, and click Add.

    Circle.xaml and its code-behind is added to the project.

  3. Open Circle.xaml.

    This file will contain the user interface elements of the user control.

  4. Add the following markup to the root Grid to create a simple user control that has a blue circle as its UI.

    <Ellipse x:Name="circleUI" 
             Height="100" Width="100"
             Fill="Blue" />
    
  5. Open Circle.xaml.cs or Circle.xaml.vb.

  6. In C#, add the following code after the default constructor to create a copy constructor. In Visual Basic, add the following code to create both a default constructor and a copy constructor.

    In order to allow the user control to be copied, you add a copy constructor method in the code-behind file. In the simplified Circle user control, you will only copy the Fill and the size of the of the user control.

    public Circle(Circle c)
    {
        InitializeComponent();
        this.circleUI.Height = c.circleUI.Height;
        this.circleUI.Width = c.circleUI.Height;
        this.circleUI.Fill = c.circleUI.Fill;
    }
    

To add the user control to the main window

  1. Open MainWindow.xaml.

  2. Add the following XAML to the opening Window tag to create an XML namespace reference to the current application.

    xmlns:local="clr-namespace:DragDropExample"
    
  3. In the first StackPanel, add the following XAML to create two instances of the Circle user control in the first panel.

    <local:Circle Margin="2" />
    <local:Circle Margin="2" />
    

    The full XAML for the panel looks like the following.

    <StackPanel Grid.Column="0"
                Background="Beige">
        <TextBox Width="Auto" Margin="2"
                 Text="green"/>
        <local:Circle Margin="2" />
        <local:Circle Margin="2" />
    </StackPanel>
    <StackPanel Grid.Column="1"
                Background="Bisque">
    </StackPanel>
    

Implementing Drag Source Events in the User Control

In this section, you will override the OnMouseMove method and initiate the drag-and-drop operation.

If a drag is started (a mouse button is pressed and the mouse is moved), you will package the data to be transferred into a DataObject. In this case, the Circle control will package three data items; a string representation of its Fill color, a double representation of its height, and a copy of itself.

To initiate a drag-and-drop operation

  1. Open Circle.xaml.cs or Circle.xaml.vb.

  2. Add the following OnMouseMove override to provide class handling for the MouseMove event.

    protected override void OnMouseMove(MouseEventArgs e)
    {
        base.OnMouseMove(e);
        if (e.LeftButton == MouseButtonState.Pressed)
        {
            // Package the data.
            DataObject data = new DataObject();
            data.SetData(DataFormats.StringFormat, circleUI.Fill.ToString());
            data.SetData("Double", circleUI.Height);
            data.SetData("Object", this);
    
            // Inititate the drag-and-drop operation.
            DragDrop.DoDragDrop(this, data, DragDropEffects.Copy | DragDropEffects.Move);
        }
    }
    

    This OnMouseMove override performs the following tasks:

    • Checks whether the left mouse button is pressed while the mouse is moving.

    • Packages the Circle data into a DataObject. In this case, the Circle control packages three data items; a string representation of its Fill color, a double representation of its height, and a copy of itself.

    • Calls the static DragDrop.DoDragDrop method to initiate the drag-and-drop operation. You pass the following three parameters to the DoDragDrop method:

      • dragSource – A reference to this control.

      • data – The DataObject created in the previous code.

      • allowedEffects – The allowed drag-and-drop operations, which are Copy or Move.

  3. Press F5 to build and run the application.

  4. Click one of the Circle controls and drag it over the panels, the other Circle, and the TextBox. When dragging over the TextBox, the cursor changes to indicate a move.

  5. While dragging a Circle over the TextBox, press the CTRL key. Notice how the cursor changes to indicate a copy.

  6. Drag and drop a Circle onto the TextBox. The string representation of the Circle’s fill color is appended to the TextBox.

    String representation of Circle's fill color

By default, the cursor will change during a drag-and-drop operation to indicate what effect dropping the data will have. You can customize the feedback given to the user by handling the GiveFeedback event and setting a different cursor.

To give feedback to the user

  1. Open Circle.xaml.cs or Circle.xaml.vb.

  2. Add the following OnGiveFeedback override to provide class handling for the GiveFeedback event.

    protected override void OnGiveFeedback(GiveFeedbackEventArgs e)
    {
        base.OnGiveFeedback(e);
        // These Effects values are set in the drop target's
        // DragOver event handler.
        if (e.Effects.HasFlag(DragDropEffects.Copy))
        {
            Mouse.SetCursor(Cursors.Cross);
        }
        else if (e.Effects.HasFlag(DragDropEffects.Move))
        {
            Mouse.SetCursor(Cursors.Pen);
        }
        else
        {
            Mouse.SetCursor(Cursors.No);
        }
        e.Handled = true;
    }
    

    This OnGiveFeedback override performs the following tasks:

    • Checks the Effects values that are set in the drop target's DragOver event handler.

    • Sets a custom cursor based on the Effects value. The cursor is intended to give visual feedback to the user about what effect dropping the data will have.

  3. Press F5 to build and run the application.

  4. Drag one of the Circle controls over the panels, the other Circle, and the TextBox. Notice that the cursors are now the custom cursors that you specified in the OnGiveFeedback override.

    Drag and drop with custom cursors
  5. Select the text green from the TextBox.

  6. Drag the green text to a Circle control. Notice that the default cursors are shown to indicate the effects of the drag-and-drop operation. The feedback cursor is always set by the drag source.

Implementing Drop Target Events in the User Control

In this section, you will specify that the user control is a drop target, override the methods that enable the user control to be a drop target, and process the data that is dropped on it.

To enable the user control to be a drop target

  1. Open Circle.xaml.

  2. In the opening UserControl tag, add the AllowDrop property and set it to true.

    <UserControl x:Class="DragDropWalkthrough.Circle"
                 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
                 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
                 mc:Ignorable="d" 
                 d:DesignHeight="300" d:DesignWidth="300"
                 AllowDrop="True">
    

The OnDrop method is called when the AllowDrop property is set to true and data from the drag source is dropped on the Circle user control. In this method, you will process the data that was dropped and apply the data to the Circle.

To process the dropped data

  1. Open Circle.xaml.cs or Circle.xaml.vb.

  2. Add the following OnDrop override to provide class handling for the Drop event.

    protected override void OnDrop(DragEventArgs e)
    {
        base.OnDrop(e);
    
        // If the DataObject contains string data, extract it.
        if (e.Data.GetDataPresent(DataFormats.StringFormat))
        {
            string dataString = (string)e.Data.GetData(DataFormats.StringFormat);
    
            // If the string can be converted into a Brush, 
            // convert it and apply it to the ellipse.
            BrushConverter converter = new BrushConverter();
            if (converter.IsValid(dataString))
            {
                Brush newFill = (Brush)converter.ConvertFromString(dataString);
                circleUI.Fill = newFill;
    
                // Set Effects to notify the drag source what effect
                // the drag-and-drop operation had.
                // (Copy if CTRL is pressed; otherwise, move.)
                if (e.KeyStates.HasFlag(DragDropKeyStates.ControlKey))
                {
                    e.Effects = DragDropEffects.Copy;
                }
                else
                {
                    e.Effects = DragDropEffects.Move;
                }
            }
        }
        e.Handled = true;
    }
    

    This OnDrop override performs the following tasks:

    • Uses the GetDataPresent method to check if the dragged data contains a string object.

    • Uses the GetData method to extract the string data if it is present.

    • Uses a BrushConverter to try to convert the string to a Brush.

    • If the conversion is successful, applies the brush to the Fill of the Ellipse that provides the UI of the Circle control.

    • Marks the Drop event as handled. You should mark the drop event as handled so that other elements that receive this event know that the Circle user control handled it.

  3. Press F5 to build and run the application.

  4. Select the text green in the TextBox.

  5. Drag the text to a Circle control and drop it. The Circle changes from blue to green.

    Convert a string to a brush
  6. Type the text green in the TextBox.

  7. Select the text gre in the TextBox.

  8. Drag it to a Circle control and drop it. Notice that the cursor changes to indicate that the drop is allowed, but the color of the Circle does not change because gre is not a valid color.

  9. Drag from the green Circle control and drop on the blue Circle control. The Circle changes from blue to green. Notice that which cursor is shown depends on whether the TextBox or the Circle is the drag source.

Setting the AllowDrop property to true and processing the dropped data is all that is required to enable an element to be a drop target. However, to provide a better user experience, you should also handle the DragEnterDragLeave, and DragOver events. In these events, you can perform checks and provide additional feedback to the user before the data is dropped.

When data is dragged over the Circle user control, the control should notify the drag source whether it can process the data that is being dragged. If the control does not know how to process the data, it should refuse the drop. To do this, you will handle the DragOver event and set the Effectsproperty.

To verify that the data drop is allowed

  1. Open Circle.xaml.cs or Circle.xaml.vb.

  2. Add the following OnDragOver override to provide class handling for the DragOver event.

    protected override void OnDragOver(DragEventArgs e)
    {
        base.OnDragOver(e);
        e.Effects = DragDropEffects.None;
    
        // If the DataObject contains string data, extract it.
        if (e.Data.GetDataPresent(DataFormats.StringFormat))
        {
            string dataString = (string)e.Data.GetData(DataFormats.StringFormat);
    
            // If the string can be converted into a Brush, allow copying or moving.
            BrushConverter converter = new BrushConverter();
            if (converter.IsValid(dataString))
            {
                // Set Effects to notify the drag source what effect
                // the drag-and-drop operation will have. These values are 
                // used by the drag source's GiveFeedback event handler.
                // (Copy if CTRL is pressed; otherwise, move.)
                if (e.KeyStates.HasFlag(DragDropKeyStates.ControlKey))
                {
                    e.Effects = DragDropEffects.Copy;
                }
                else
                {
                    e.Effects = DragDropEffects.Move;
                }
            }
        }
        e.Handled = true;
    }
    

    This OnDragOver override performs the following tasks:

    • Sets the Effects property to None.

    • Performs the same checks that are performed in the OnDrop method to determine whether the Circle user control can process the dragged data.

    • If the user control can process the data, sets the Effects property to Copy or Move.

  3. Press F5 to build and run the application.

  4. Select the text gre in the TextBox.

  5. Drag the text to a Circle control. Notice that the cursor now changes to indicate that the drop is not allowed because gre is not a valid color.

You can further enhance the user experience by applying a preview of the drop operation. For the Circle user control, you will override the OnDragEnter and OnDragLeave methods. When the data is dragged over the control, the current background Fill is saved in a placeholder variable. The string is then converted to a brush and applied to the Ellipse that provides the Circle's UI. If the data is dragged out of the Circle without being dropped, the original Fill value is re-applied to the Circle.

To preview the effects of the drag-and-drop operation

  1. Open Circle.xaml.cs or Circle.xaml.vb.

  2. In the Circle class, declare a private Brush variable named _previousFill and initialize it to null.

    public partial class Circle : UserControl
    {
        private Brush _previousFill = null;
    
  3. Add the following OnDragEnter override to provide class handling for the DragEnter event.

    protected override void OnDragEnter(DragEventArgs e)
    {
        base.OnDragEnter(e);
        // Save the current Fill brush so that you can revert back to this value in DragLeave.
        _previousFill = circleUI.Fill;
    
        // If the DataObject contains string data, extract it.
        if (e.Data.GetDataPresent(DataFormats.StringFormat))
        {
            string dataString = (string)e.Data.GetData(DataFormats.StringFormat);
    
            // If the string can be converted into a Brush, convert it.
            BrushConverter converter = new BrushConverter();
            if (converter.IsValid(dataString))
            {
                Brush newFill = (Brush)converter.ConvertFromString(dataString.ToString());
                circleUI.Fill = newFill;
            }
        }
    }
    

    This OnDragEnter override performs the following tasks:

    • Saves the Fill property of the Ellipse in the _previousFill variable.

    • Performs the same checks that are performed in the OnDrop method to determine whether the data can be converted to a Brush.

    • If the data is converted to a valid Brush, applies it to the Fill of the Ellipse.

  4. Add the following OnDragLeave override to provide class handling for the DragLeave event.

    protected override void OnDragLeave(DragEventArgs e)
    {
        base.OnDragLeave(e);
        // Undo the preview that was applied in OnDragEnter.
        circleUI.Fill = _previousFill;
    }
    

    This OnDragLeave override performs the following tasks:

    • Applies the Brush saved in the _previousFill variable to the Fill of the Ellipse that provides the UI of the Circle user control.

  5. Press F5 to build and run the application.

  6. Select the text green in the TextBox.

  7. Drag the text over a Circle control without dropping it. The Circle changes from blue to green. 

    Preview the effects of a drag-and-drop operation
  8. Drag the text away from the Circle control. The Circle changes from green back to blue.

Enabling a Panel to Receive Dropped Data

In this section, you will enable the panels that host the Circle user controls to act as drop targets for dragged Circle data. You will implement code that enables you to move a Circle from one panel to another, or to make a copy of a Circle control by holding down the CTRL key while dragging and dropping a Circle.

To enable the panel to be a drop target

  1. Open MainWindow.xaml.

  2. As shown in the following XAML, in each of the StackPanel controls, add handlers for the DragOver and Drop events. Name the DragOverevent handler, panel_DragOver, and name the Drop event handler, panel_Drop.

    <StackPanel Grid.Column="0"
                Background="Beige"
                AllowDrop="True"
                DragOver="panel_DragOver"
                Drop="panel_Drop">
        <TextBox Width="Auto" Margin="2"
                 Text="green"/>
        <local:Circle Margin="2" />
        <local:Circle Margin="2" />
    </StackPanel>
    <StackPanel Grid.Column="1"
                Background="Bisque"
                AllowDrop="True"
                DragOver="panel_DragOver"
                Drop="panel_Drop">
    </StackPanel>
    
  3. Open MainWindows.xaml.cs or MainWindow.xaml.vb.

  4. Add the following code for the DragOver event handler.

    private void panel_DragOver(object sender, DragEventArgs e)
    {
        if (e.Data.GetDataPresent("Object"))
        {
            // These Effects values are used in the drag source's
            // GiveFeedback event handler to determine which cursor to display.
            if (e.KeyStates == DragDropKeyStates.ControlKey)
            {
                e.Effects = DragDropEffects.Copy;
            }
            else
            {
                e.Effects = DragDropEffects.Move;
            }
        }
    }
    

    This DragOver event handler performs the following tasks:

    • Checks that the dragged data contains the "Object" data that was packaged in the DataObject by the Circle user control and passed in the call to DoDragDrop.

    • If the "Object" data is present, checks whether the CTRL key is pressed.

    • If the CTRL key is pressed, sets the Effects property to Copy. Otherwise, set the Effects property to Move.

  5. Add the following code for the Drop event handler.

    private void panel_Drop(object sender, DragEventArgs e)
    {
        // If an element in the panel has already handled the drop,
        // the panel should not also handle it.
        if (e.Handled == false)
        {
            Panel _panel = (Panel)sender;
            UIElement _element = (UIElement)e.Data.GetData("Object");
    
            if (_panel != null && _element != null)
            {
                // Get the panel that the element currently belongs to,
                // then remove it from that panel and add it the Children of
                // the panel that its been dropped on.
                Panel _parent = (Panel)VisualTreeHelper.GetParent(_element);
    
                if (_parent != null)
                {
                    if (e.KeyStates == DragDropKeyStates.ControlKey &&
                        e.AllowedEffects.HasFlag(DragDropEffects.Copy))
                    {
                        Circle _circle = new Circle((Circle)_element);
                        _panel.Children.Add(_circle);
                        // set the value to return to the DoDragDrop call
                        e.Effects = DragDropEffects.Copy;
                    }
                    else if (e.AllowedEffects.HasFlag(DragDropEffects.Move))
                    {
                        _parent.Children.Remove(_element);
                        _panel.Children.Add(_element);
                        // set the value to return to the DoDragDrop call
                        e.Effects = DragDropEffects.Move;
                    }
                }
            }
        }
    }
    

    This Drop event handler performs the following tasks:

    • Checks whether the Drop event has already been handled. For instance, if a Circle is dropped on another Circle which handles the Drop event, you do not want the panel that contains the Circle to also handle it.

    • If the Drop event is not handled, checks whether the CTRL key is pressed.

    • If the CTRL key is pressed when the Drop happens, makes a copy of the Circle control and add it to the Children collection of the StackPanel.

    • If the CTRL key is not pressed, moves the Circle from the Children collection of its parent panel to the Children collection of the panel that it was dropped on.

    • Sets the Effects property to notify the DoDragDrop method whether a move or copy operation was performed.

  6. Press F5 to build and run the application.

  7. Select the text green from the TextBox.

  8. Drag the text over a Circle control and drop it.

  9. Drag a Circle control from the left panel to the right panel and drop it. The Circle is removed from the Children collection of the left panel and added to the Children collection of the right panel.

  10. Drag a Circle control from the panel it is in to the other panel and drop it while pressing the CTRL key. The Circle is copied and the copy is added to the Children collection of the receiving panel.

    Dragging a Circle while pressing the CTRL key





How to: Open a File That is Dropped on a RichTextBox Control


In Windows Presentation Foundation (WPF), the TextBoxRichTextBox, and FlowDocument controls all have built-in drag-and-drop functionality. The built-in functionality enables drag-and-drop of text within and between the controls. However, it does not enable opening a file by dropping the file on the control. These controls also mark the drag-and-drop events as handled. As a result, by default, you cannot add your own event handlers to provide functionality to open dropped files.

To add additional handling for drag-and-drop events in these controls, use the AddHandler(RoutedEvent, Delegate, Boolean) method to add your event handlers for the drag-and-drop events. Set the handledEventsToo parameter to true to have the specified handler be invoked for a routed event that has already been marked as handled by another element along the event route.

System_CAPS_tipTip

You can replace the built-in drag-and-drop functionality of TextBoxRichTextBox, and FlowDocument by handling the preview versions of the drag-and-drop events and marking the preview events as handled. However, this will disable the built-in drag-and-drop functionality, and is not recommended.

Example

The following example demonstrates how to add handlers for the DragOver and Drop events on a RichTextBox. This example uses the AddHandler(RoutedEvent, Delegate, Boolean) method and sets the handledEventsToo parameter to true so that the events handlers will be invoked even though the RichTextBox marks these events as handled. The code in the event handlers adds functionality to open a text file that is dropped on the RichTextBox.

To test this example, drag a text file or a rich text format (RTF) file from Windows Explorer to the RichTextBox. The file will be opened in the RichTextBox. If you press the SHIFT key before the dropping the file, the file will be opened as plain text.

<RichTextBox x:Name="richTextBox1"
             AllowDrop="True" />
public MainWindow()
{
    InitializeComponent();

    // Add using System.Windows.Controls;
    richTextBox1.AddHandler(RichTextBox.DragOverEvent, new DragEventHandler(RichTextBox_DragOver), true);
    richTextBox1.AddHandler(RichTextBox.DropEvent, new DragEventHandler(RichTextBox_Drop), true);
}

private void RichTextBox_DragOver(object sender, DragEventArgs e)
{
    if (e.Data.GetDataPresent(DataFormats.FileDrop))
    {
        e.Effects = DragDropEffects.All;
    }
    else
    {
        e.Effects = DragDropEffects.None;
    }
    e.Handled = false;
}

private void RichTextBox_Drop(object sender, DragEventArgs e)
{
    if (e.Data.GetDataPresent(DataFormats.FileDrop))
    {
        string[] docPath = (string[])e.Data.GetData(DataFormats.FileDrop);

        // By default, open as Rich Text (RTF).
        var dataFormat = DataFormats.Rtf;

        // If the Shift key is pressed, open as plain text.
        if (e.KeyStates == DragDropKeyStates.ShiftKey)
        {
            dataFormat = DataFormats.Text;
        }

        System.Windows.Documents.TextRange range;
        System.IO.FileStream fStream;
        if (System.IO.File.Exists(docPath[0]))
        {
            try
            {
                // Open the document in the RichTextBox.
                range = new System.Windows.Documents.TextRange(richTextBox1.Document.ContentStart, richTextBox1.Document.ContentEnd);
                fStream = new System.IO.FileStream(docPath[0], System.IO.FileMode.OpenOrCreate);
                range.Load(fStream, dataFormat);
                fStream.Close();
            }
            catch (System.Exception)
            {
                MessageBox.Show("File could not be opened. Make sure the file is a text file.");
            }
        }
    }
}





How to: Create a Data Object


The following examples show various ways to create a data object using the constructors provided by the DataObject class.

Example

Description

The following example code creates a new data object and uses one of the overloaded constructors (DataObject(Object)) to initialize the data object with a string. In this case, an appropriate data format is determined automatically according to the stored data's type, and auto-converting of the stored data is allowed by default.

Code

string stringData = "Some string data to store...";
DataObject dataObject = new DataObject(stringData);

Description

The following example code is a condensed version of the code shown above.

Code

DataObject dataObject = new DataObject("Some string data to store...");

Example

Description

The following example code creates a new data object and uses one of the overloaded constructors (DataObject(String, Object)) to initialize the data object with a string and a specified data format. In this case the data format is specified by a string; the DataFormats class provides a set of pre-defined type strings. Auto-converting of the stored data is allowed by default.

Code

string stringData = "Some string data to store...";
string dataFormat = DataFormats.UnicodeText;
DataObject dataObject = new DataObject(dataFormat, stringData);

Description

The following example code is a condensed version of the code shown above.

Code

DataObject dataObject = new DataObject(DataFormats.UnicodeText, "Some string data to store...");

Example

Description

The following example code creates a new data object and uses one of the overloaded constructors (DataObject) to initialize the data object with a string and a specified data format. In this case the data format is specified by a Type parameter. Auto-converting of the stored data is allowed by default.

Code

string stringData = "Some string data to store...";
Type dataFormat = stringData.GetType();
DataObject dataObject = new DataObject(dataFormat, stringData);

Description

The following example code is a condensed version of the code shown above.

Code

DataObject dataObject = new DataObject("".GetType(), "Some string data to store...");

Example

Description

The following example code creates a new data object and uses one of the overloaded constructors (DataObject(String, Object, Boolean)) to initialize the data object with a string and a specified data format. In this case the data format is specified by a string; the DataFormats class provides a set of pre-defined type strings. This particular constructor overload enables the caller to specify whether auto-converting is allowed.

Code

string stringData = "Some string data to store...";
string dataFormat = DataFormats.Text;
bool autoConvert = false;
DataObject dataObject = new DataObject(dataFormat, stringData, autoConvert);

Description

The following example code is a condensed version of the code shown above.

Code

DataObject dataObject = new DataObject(DataFormats.Text, "Some string data to store...", false);






How to: Determine if a Data Format is Present in a Data Object


The following examples show how to use the various GetDataPresent method overloads to query whether a particular data format is present in a data object.

Example

Description

The following example code uses the GetDataPresent(String) overload to query for the presence of a particular data format by descriptor string.

Code

DataObject dataObject = new DataObject("Some string data to store...");

// Query for the presence of Text data in the data object, by a data format descriptor string.
// In this overload of GetDataPresent, the method will return true both for native data formats
// and when the data can automatically be converted to the specifed format.

// In this case, string data is present natively, so GetDataPresent returns "true".
string textData = null;
if (dataObject.GetDataPresent(DataFormats.StringFormat))
{
    textData = dataObject.GetData(DataFormats.StringFormat) as string;
}

// In this case, the Text data in the data object can be autoconverted to 
// Unicode text, so GetDataPresent returns "true".
byte[] unicodeData = null;
if (dataObject.GetDataPresent(DataFormats.UnicodeText))
{
    unicodeData = dataObject.GetData(DataFormats.UnicodeText) as byte[];
}

Example

Description

The following example code uses the GetDataPresent(Type) overload to query for the presence of a particular data format by type.

Code

DataObject dataObject = new DataObject("Some string data to store...");

// Query for the presence of String data in the data object, by type.  In this overload 
// of GetDataPresent, the method will return true both for native data formats
// and when the data can automatically be converted to the specifed format.

// In this case, the Text data present in the data object can be autoconverted
// to type string (also represented by DataFormats.String), so GetDataPresent returns "true".
string stringData = null;
if (dataObject.GetDataPresent(typeof(string)))
{
    stringData = dataObject.GetData(DataFormats.Text) as string;
}

Example

Description

The following example code uses the GetDataPresent(String, Boolean) overload to query for data by descriptor string, and specifying how to treat auto-convertible data formats.

Code

DataObject dataObject = new DataObject("Some string data to store...");

// Query for the presence of Text data in the data object, by data format descriptor string,
// and specifying whether auto-convertible data formats are acceptable.  

// In this case, Text data is present natively, so GetDataPresent returns "true".
string textData = null;
if (dataObject.GetDataPresent(DataFormats.Text, false /* Auto-convert? */))
{
    textData = dataObject.GetData(DataFormats.Text) as string;
}

// In this case, the Text data in the data object can be autoconverted to 
// Unicode text, but it is not available natively, so GetDataPresent returns "false".
byte[] unicodeData = null;
if (dataObject.GetDataPresent(DataFormats.UnicodeText, false /* Auto-convert? */))
{
    unicodeData = dataObject.GetData(DataFormats.UnicodeText) as byte[];
}

// In this case, the Text data in the data object can be autoconverted to 
// Unicode text, so GetDataPresent returns "true".
if (dataObject.GetDataPresent(DataFormats.UnicodeText, true /* Auto-convert? */))
{
    unicodeData = dataObject.GetData(DataFormats.UnicodeText) as byte[];
}





How to: List the Data Formats in a Data Object


The following examples show how to use the GetFormats method overloads get an array of strings denoting each data format that is available in a data object.

Example

Description

The following example code uses the GetFormats overload to get an array of strings denoting all data formats available in a data object (both native and auto-convertible).

Code

DataObject dataObject = new DataObject("Some string data to store...");

// Get an array of strings, each string denoting a data format
// that is available in the data object.  This overload of GetDataFormats
// returns all available data formats, native and auto-convertible.
string[] dataFormats = dataObject.GetFormats();

// Get the number of data formats present in the data object, including both
// auto-convertible and native data formats.
int numberOfDataFormats = dataFormats.Length;

// To enumerate the resulting array of data formats, and take some action when
// a particular data format is found, use a code structure similar to the following.
foreach (string dataFormat in dataFormats)
{
    if (dataFormat == DataFormats.Text)
    {
        // Take some action if/when data in the Text data format is found.
        break;
    }
    else if(dataFormat == DataFormats.StringFormat)
    {
        // Take some action if/when data in the string data format is found.
        break;
    }
}

Example

Description

The following example code uses the GetFormats overload to get an array of strings denoting only data formats available in a data object (auto-convertible data formats are filtered).

Code

DataObject dataObject = new DataObject("Some string data to store...");

// Get an array of strings, each string denoting a data format
// that is available in the data object.  This overload of GetDataFormats
// accepts a Boolean parameter inidcating whether to include auto-convertible
// data formats, or only return native data formats.
string[] dataFormats = dataObject.GetFormats(false /* Include auto-convertible? */);

// Get the number of native data formats present in the data object.
int numberOfDataFormats = dataFormats.Length;

// To enumerate the resulting array of data formats, and take some action when
// a particular data format is found, use a code structure similar to the following.
foreach (string dataFormat in dataFormats)
{
    if (dataFormat == DataFormats.Text)
    {
        // Take some action if/when data in the Text data format is found.
        break;
    }
}





How to: Retrieve Data in a Particular Data Format


The following examples show how to retrieve data from a data object in a specified format.

Example

Description

The following example code uses the GetDataPresent(String) overload to first check if a specified data format is available (natively or by auto-convert); if the specified format is available, the example retrieves the data by using the GetData(String) method.

Code

DataObject dataObject = new DataObject("Some string data to store...");

string desiredFormat = DataFormats.UnicodeText;
byte[] data = null;

// Use the GetDataPresent method to check for the presence of a desired data format.
// This particular overload of GetDataPresent looks for both native and auto-convertible 
// data formats.
if (dataObject.GetDataPresent(desiredFormat))
{
    // If the desired data format is present, use one of the GetData methods to retrieve the
    // data from the data object.
    data = dataObject.GetData(desiredFormat) as byte[];
}

Example

Description

The following example code uses the GetDataPresent(String, Boolean) overload to first check if a specified data format is available natively (auto-convertible data formats are filtered); if the specified format is available, the example retrieves the data by using the GetData(String) method.

Code

DataObject dataObject = new DataObject("Some string data to store...");

string desiredFormat = DataFormats.UnicodeText;
bool noAutoConvert = false;
byte[] data = null;

// Use the GetDataPresent method to check for the presence of a desired data format.
// The autoconvert parameter is set to false to filter out auto-convertible data formats,
// returning true only if the specified data format is available natively.
if (dataObject.GetDataPresent(desiredFormat, noAutoConvert))
{
    // If the desired data format is present, use one of the GetData methods to retrieve the
    // data from the data object.
    data = dataObject.GetData(desiredFormat) as byte[];
}





How to: Store Multiple Data Formats in a Data Object


The following example shows how to use the SetData(String, Object) method to add data to a data object in multiple formats.

Example

Code

DataObject dataObject = new DataObject();
string sourceData = "Some string data to store...";

// Encode the source string into Unicode byte arrays.
byte[] unicodeText = Encoding.Unicode.GetBytes(sourceData); // UTF-16
byte[] utf8Text = Encoding.UTF8.GetBytes(sourceData);
byte[] utf32Text = Encoding.UTF32.GetBytes(sourceData);

// The DataFormats class does not provide data format fields for denoting
// UTF-32 and UTF-8, which are seldom used in practice; the following strings 
// will be used to identify these "custom" data formats.
string utf32DataFormat = "UTF-32";
string utf8DataFormat  = "UTF-8";

// Store the text in the data object, letting the data object choose
// the data format (which will be DataFormats.Text in this case).
dataObject.SetData(sourceData);
// Store the Unicode text in the data object.  Text data can be automatically
// converted to Unicode (UTF-16 / UCS-2) format on extraction from the data object; 
// Therefore, explicitly converting the source text to Unicode is generally unnecessary, and
// is done here as an exercise only.
dataObject.SetData(DataFormats.UnicodeText, unicodeText);
// Store the UTF-8 text in the data object...
dataObject.SetData(utf8DataFormat, utf8Text);
// Store the UTF-32 text in the data object...
dataObject.SetData(utf32DataFormat, utf32Text);







:
Posted by 지훈2
2016. 10. 18. 12:33

Predicate<T> Delegate 프로그래밍/C#2016. 10. 18. 12:33

Predicate<T> Delegate


Represents the method that defines a set of criteria and determines whether the specified object meets those criteria.

Namespace:   System
Assembly:  mscorlib (in mscorlib.dll)

Syntax

public delegate bool Predicate<in T>(
	T obj
)

Parameters

obj
Type: T

The object to compare against the criteria defined within the method represented by this delegate.

Return Value

Type: System.Boolean

true if obj meets the criteria defined within the method represented by this delegate; otherwise, false.

Type Parameters

inT

The type of the object to compare.

Remarks

This delegate is used by several methods of the Array and List<T> classes to search for elements in the collection.

Typically, the Predicate<T> delegate is represented by a lambda expression. Because locally scoped variables are available to the lambda expression, it is easy to test for a condition that is not precisely known at compile time. This is simulated in the following example, which defines a HockeyTeamclass that contains information about a National Hockey League team and the year in which it was founded. The example defines an array of integer values that represent years, and randomly assigns one element of the array to foundedBeforeYear, which is a variable that is locally scoped to the example's Main method. Because locally scoped variables are available to a lambda expression, the lambda expression passed to the List<T>.FindAllmethod is able to return a HockeyTeam object for each team founded on or before that year.

using System;
using System.Collections.Generic;

public class HockeyTeam
{
   private string _name;
   private int _founded;

   public HockeyTeam(string name, int year)
   {
      _name = name;
      _founded = year;
   }

   public string Name {
      get { return _name; }
   }

   public int Founded {
      get { return _founded; }
   }
}

public class Example
{
   public static void Main()
   {
      Random rnd = new Random();
      List<HockeyTeam> teams = new List<HockeyTeam>();
      teams.AddRange( new HockeyTeam[] { new HockeyTeam("Detroit Red Wings", 1926), 
                                         new HockeyTeam("Chicago Blackhawks", 1926),
                                         new HockeyTeam("San Jose Sharks", 1991),
                                         new HockeyTeam("Montreal Canadiens", 1909),
                                         new HockeyTeam("St. Louis Blues", 1967) } );
      int[] years = { 1920, 1930, 1980, 2000 };
      int foundedBeforeYear = years[rnd.Next(0, years.Length)];
      Console.WriteLine("Teams founded before {0}:", foundedBeforeYear);
      foreach (var team in teams.FindAll( x => x.Founded <= foundedBeforeYear))
         Console.WriteLine("{0}: {1}", team.Name, team.Founded);
   }
}
// The example displays output similar to the following:
//       Teams founded before 1930:
//       Detroit Red Wings: 1926
//       Chicago Blackhawks: 1926
//       Montreal Canadiens: 1909

Examples

The following code example uses a Predicate<T> delegate with the Array.Find<T> method to search an array of Point structures. The example explicitly defines a Predicate<T> delegate named predicate and assigns it a method named FindPoints that returns true if the product of the Point.X and Point.Y fields is greater than 100,000. Note that it is customary to use a lambda expression rather than to explicitly define a delegate of type Predicate<T>, as the second example illustrates.

using System;
using System.Drawing;

public class Example
{
   public static void Main()
   {
      // Create an array of Point structures.
      Point[] points = { new Point(100, 200), 
                         new Point(150, 250), new Point(250, 375), 
                         new Point(275, 395), new Point(295, 450) };

      // Define the Predicate<T> delegate.
      Predicate<Point> predicate = FindPoints;

      // Find the first Point structure for which X times Y  
      // is greater than 100000. 
      Point first = Array.Find(points, predicate);

      // Display the first structure found.
      Console.WriteLine("Found: X = {0}, Y = {1}", first.X, first.Y);
   }

   private static bool FindPoints(Point obj)
   {
      return obj.X * obj.Y > 100000;
   }
}
// The example displays the following output:
//        Found: X = 275, Y = 395

The following example is identical to the previous example, except that it uses a lambda expression to represent the Predicate<T> delegate. Each element of the points array is passed to the lambda expression until the expression finds an element that meets the search criteria. In this case, the lambda expression returns true if the product of the X and Y fields is greater than 100,000.

using System;
using System.Drawing;

public class Example
{
   public static void Main()
   {
      // Create an array of Point structures.
      Point[] points = { new Point(100, 200), 
                         new Point(150, 250), new Point(250, 375), 
                         new Point(275, 395), new Point(295, 450) };

      // Find the first Point structure for which X times Y  
      // is greater than 100000. 
      Point first = Array.Find(points, x => x.X * x.Y > 100000 );

      // Display the first structure found.
      Console.WriteLine("Found: X = {0}, Y = {1}", first.X, first.Y);
   }
}
// The example displays the following output:
//        Found: X = 275, Y = 395




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

Operators  (0) 2016.11.14
IEnumerable Interface  (0) 2016.11.14
DateTime, TimeSpan  (0) 2016.10.12
C# 코딩 규칙  (0) 2016.08.28
예외 및 예외 처리  (0) 2016.08.26
:
Posted by 지훈2
2016. 10. 15. 18:56

WPF 고급 - 입력 (Input) 프로그래밍/WPF2016. 10. 15. 18:56

Input


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




Input Overview


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


The Windows Presentation Foundation (WPF) subsystem provides a powerful API for obtaining input from a variety of devices, including the mouse, keyboard, touch, and stylus. This topic describes the services provided by WPF and explains the architecture of the input systems.

Input API

The primary input API exposure is found on the base element classes: UIElementContentElementFrameworkElement, and FrameworkContentElement. For more information about the base elements, see Base Elements Overview. These classes provide functionality for input events related to key presses, mouse buttons, mouse wheel, mouse movement, focus management, and mouse capture, to name a few. By placing the input API on the base elements, rather than treating all input events as a service, the input architecture enables the input events to be sourced by a particular object in the UI, and to support an event routing scheme whereby more than one element has an opportunity to handle an input event. Many input events have a pair of events associated with them. For example, the key down event is associated with the KeyDown and PreviewKeyDown events. The difference in these events is in how they are routed to the target element. Preview events tunnel down the element tree from the root element to the target element. Bubbling events bubble up from the target element to the root element. Event routing in WPF is discussed in more detail later in this overview and in the Routed Events Overview.

Keyboard and Mouse Classes

In addition to the input API on the base element classes, the Keyboard class and Mouse classes provide additional API for working with keyboard and mouse input.

Examples of input API on the Keyboard class are the Modifiers property, which returns the ModifierKeys currently pressed, and the IsKeyDown method, which determines whether a specified key is pressed.

The following example uses the GetKeyStates method to determine if a Key is in the down state.

// Uses the Keyboard.GetKeyStates to determine if a key is down.
// A bitwise AND operation is used in the comparison. 
// e is an instance of KeyEventArgs.
if ((Keyboard.GetKeyStates(Key.Return) & KeyStates.Down) > 0)
{
    btnNone.Background = Brushes.Red;
}

Examples of input API on the Mouse class are MiddleButton, which obtains the state of the middle mouse button, and DirectlyOver, which gets the element the mouse pointer is currently over.

The following example determines whether the LeftButton on the mouse is in the Pressed state.

if (Mouse.LeftButton == MouseButtonState.Pressed)
{
    UpdateSampleResults("Left Button Pressed");
}

The Mouse and Keyboard classes are covered in more detail throughout this overview.

Stylus Input

WPF has integrated support for the Stylus. The Stylus is a pen input made popular by the Tablet PC. WPF applications can treat the stylus as a mouse by using the mouse API, but WPF also exposes a stylus device abstraction that use a model similar to the keyboard and mouse. All stylus-related APIs contain the word "Stylus".

Because the stylus can act as a mouse, applications that support only mouse input can still obtain some level of stylus support automatically. When the stylus is used in such a manner, the application is given the opportunity to handle the appropriate stylus event and then handles the corresponding mouse event. In addition, higher-level services such as ink input are also available through the stylus device abstraction. For more information about ink as input, see Getting Started with Ink.

Event Routing

FrameworkElement can contain other elements as child elements in its content model, forming a tree of elements. In WPF, the parent element can participate in input directed to its child elements or other descendants by handing events. This is especially useful for building controls out of smaller controls, a process known as "control composition" or "compositing." For more information about element trees and how element trees relate to event routes, see Trees in WPF.

Event routing is the process of forwarding events to multiple elements, so that a particular object or element along the route can choose to offer a significant response (through handling) to an event that might have been sourced by a different element. Routed events use one of three routing mechanisms: direct, bubbling, and tunneling. In direct routing, the source element is the only element notified, and the event is not routed to any other elements. However, the direct routed event still offers some additional capabilities that are only present for routed events as opposed to standard CLR events. Bubbling works up the element tree by first notifying the element that sourced the event, then the parent element, and so on. Tunneling starts at the root of the element tree and works down, ending with the original source element. For more information about routed events, see Routed Events Overview.

WPF input events generally come in pairs that consists of a tunneling event and a bubbling event. Tunneling events are distinguished from bubbling events with the "Preview" prefix. For instance, PreviewMouseMove is the tunneling version of a mouse move event and MouseMove is the bubbling version of this event. This event pairing is a convention that is implemented at the element level and is not an inherent capability of the WPF event system. For details, see the WPF Input Events section in Routed Events Overview.

Handling Input Events

To receive input on an element, an event handler must be associated with that particular event. In XAML this is straightforward: you reference the name of the event as an attribute of the element that will be listening for this event. Then, you set the value of the attribute to the name of the event handler that you define, based on a delegate. The event handler must be written in code such as C# and can be included in a code-behind file.

Keyboard events occur when the operating system reports key actions that occur while keyboard focus is on an element. Mouse and stylus events each fall into two categories: events that report changes in pointer position relative to the element, and events that report changes in the state of device buttons.

Keyboard Input Event Example

The following example listens for a left arrow key press. A StackPanel is created that has a Button. An event handler to listen for the left arrow key press is attached to the Button instance.

The first section of the example creates the StackPanel and the Button and attaches the event handler for the KeyDown.

<StackPanel>
  <Button Background="AliceBlue"
          KeyDown="OnButtonKeyDown"
          Content="Button1"/>
</StackPanel>
// Create the UI elements.
StackPanel keyboardStackPanel = new StackPanel();
Button keyboardButton1 = new Button();

// Set properties on Buttons.
keyboardButton1.Background = Brushes.AliceBlue;
keyboardButton1.Content = "Button 1";

// Attach Buttons to StackPanel.
keyboardStackPanel.Children.Add(keyboardButton1);

// Attach event handler.
keyboardButton1.KeyDown += new KeyEventHandler(OnButtonKeyDown);

The second section is written in code and defines the event handler. When the left arrow key is pressed and the Button has keyboard focus, the handler runs and the Background color of the Button is changed. If the key is pressed, but it is not the left arrow key, the Background color of the Button is changed back to its starting color.

private void OnButtonKeyDown(object sender, KeyEventArgs e)
{
    Button source = e.Source as Button;
    if (source != null)
    {
        if (e.Key == Key.Left)
        {
            source.Background = Brushes.LemonChiffon;
        }
        else
        {
            source.Background = Brushes.AliceBlue;
        }
    }
}

Mouse Input Event Example

In the following example, the Background color of a Button is changed when the mouse pointer enters the Button. The Background color is restored when the mouse leaves the Button.

The first section of the example creates the StackPanel and the Button control and attaches the event handlers for the MouseEnter and MouseLeave events to the Button.

<StackPanel>
  <Button Background="AliceBlue"
          MouseEnter="OnMouseExampleMouseEnter"
          MouseLeave="OnMosueExampleMouseLeave">Button

  </Button>
</StackPanel>
// Create the UI elements.
StackPanel mouseMoveStackPanel = new StackPanel();
Button mouseMoveButton = new Button();

// Set properties on Button.
mouseMoveButton.Background = Brushes.AliceBlue;
mouseMoveButton.Content = "Button";

// Attach Buttons to StackPanel.
mouseMoveStackPanel.Children.Add(mouseMoveButton);

// Attach event handler.
mouseMoveButton.MouseEnter += new MouseEventHandler(OnMouseExampleMouseEnter);
mouseMoveButton.MouseLeave += new MouseEventHandler(OnMosueExampleMouseLeave);

The second section of the example is written in code and defines the event handlers. When the mouse enters the Button, the Background color of the Button is changed to SlateGray. When the mouse leaves the Button, the Background color of the Button is changed back to AliceBlue.

private void OnMouseExampleMouseEnter(object sender, MouseEventArgs e)
{
    // Cast the source of the event to a Button.
    Button source = e.Source as Button;

    // If source is a Button.
    if (source != null)
    {
        source.Background = Brushes.SlateGray;
    }
}
private void OnMosueExampleMouseLeave(object sender, MouseEventArgs e)
{
    // Cast the source of the event to a Button.
    Button source = e.Source as Button;

    // If source is a Button.
    if (source != null)
    {
        source.Background = Brushes.AliceBlue;
    }
}

Text Input

The TextInput event enables you to listen for text input in a device-independent manner. The keyboard is the primary means of text input, but speech, handwriting, and other input devices can generate text input also.

For keyboard input, WPF first sends the appropriate KeyDown/KeyUp events. If those events are not handled and the key is textual (rather than a control key such as directional arrows or function keys), then a TextInput event is raised. There is not always a simple one-to-one mapping between KeyDown/KeyUp and TextInput events because multiple keystrokes can generate a single character of text input and single keystrokes can generate multi-character strings. This is especially true for languages such as Chinese, Japanese, and Korean which use Input Method Editors (IMEs) to generate the thousands of possible characters in their corresponding alphabets.

When WPF sends a KeyUp/KeyDown event, Key is set to Key.System if the keystrokes could become part of a TextInput event (if ALT+S is pressed, for example). This allows code in a KeyDown event handler to check for Key.System and, if found, leave processing for the handler of the subsequently raised TextInput event. In these cases, the various properties of the TextCompositionEventArgs argument can be used to determine the original keystrokes. Similarly, if an IME is active, Key has the value of Key.ImeProcessed, and ImeProcessedKey gives the original keystroke or keystrokes.

The following example defines a handler for the Click event and a handler for the KeyDown event.

The first segment of code or markup creates the user interface.

<StackPanel KeyDown="OnTextInputKeyDown">
  <Button Click="OnTextInputButtonClick"
          Content="Open" />
  <TextBox> . . . </TextBox>
</StackPanel>
// Create the UI elements.
StackPanel textInputStackPanel = new StackPanel();
Button textInputeButton = new Button();
TextBox textInputTextBox = new TextBox();
textInputeButton.Content = "Open";

// Attach elements to StackPanel.
textInputStackPanel.Children.Add(textInputeButton);
textInputStackPanel.Children.Add(textInputTextBox);

// Attach event handlers.
textInputStackPanel.KeyDown += new KeyEventHandler(OnTextInputKeyDown);
textInputeButton.Click += new RoutedEventHandler(OnTextInputButtonClick);

The second segment of code contains the event handlers.

private void OnTextInputKeyDown(object sender, KeyEventArgs e)
{
    if (e.Key == Key.O && Keyboard.Modifiers == ModifierKeys.Control)
    {
        handle();
        e.Handled = true;
    }
}

private void OnTextInputButtonClick(object sender, RoutedEventArgs e)
{
    handle();
    e.Handled = true;
} 

public void handle()
{
    MessageBox.Show("Pretend this opens a file");
}

Because input events bubble up the event route, the StackPanel receives the input regardless of which element has keyboard focus. The TextBoxcontrol is notified first and the OnTextInputKeyDown handler is called only if the TextBox did not handle the input. If the PreviewKeyDown event is used instead of the KeyDown event, the OnTextInputKeyDown handler is called first.

In this example, the handling logic is written two times—one time for CTRL+O, and again for button's click event. This can be simplified by using commands, instead of handling the input events directly. Commands are discussed in this overview and in Commanding Overview.

Touch and Manipulation

New hardware and API in the Windows 7 operating system provide applications the ability to receive input from multiple touches simultaneously. WPF enables applications to detect and respond to touch in a manner similar to responding to other input, such as the mouse or keyboard, by raising events when touch occurs.

WPF exposes two types of events when touch occurs: touch events and manipulation events. Touch events provide raw data about each finger on a touchscreen and its movement. Manipulation events interpret the input as certain actions. Both types of events are discussed in this section.

Prerequisites

You need the following components to develop an application that responds to touch.

  • Microsoft Visual Studio 2010.

  • Windows 7.

  • A device, such as a touchscreen, that supports Windows Touch.

Terminology

The following terms are used when touch is discussed.

  • Touch is a type of user input that is recognized by Windows 7. Usually, touch is initiated by putting fingers on a touch-sensitive screen. Note that devices such as a touchpad that is common on laptop computers do not support touch if the device merely converts the finger's position and movement as mouse input.

  • Multitouch is touch that occurs from more than one point simultaneously. Windows 7 and WPF supports multitouch. Whenever touch is discussed in the documentation for WPF, the concepts apply to multitouch.

  • manipulation occurs when touch is interpreted as a physical action that is applied to an object. In WPF, manipulation events interpret input as a translation, expansion, or rotation manipulation.

  • touch device represents a device that produces touch input, such as a single finger on a touchscreen.

  

Controls that Respond to Touch

The following controls can be scrolled by dragging a finger across the control if it has content that is scrolled out of view.

The ScrollViewer defines the ScrollViewer.PanningMode attached property that enables you to specify whether touch panning is enabled horizontally, vertically, both, or neither. The ScrollViewer.PanningDeceleration property specifies how quickly the scrolling slows down when the user lifts the finger from the touchscreen. The ScrollViewer.PanningRatio attached property specifies the ratio of scrolling offset to translate manipulation offset.

Touch Events

The base classes, UIElementUIElement3D, and ContentElement, define events that you can subscribe to so your application will respond to touch. Touch events are useful when your application interprets touch as something other than manipulating an object. For example, an application that enables a user to draw with one or more fingers would subscribe to touch events.

All three classes define the following events, which behave similarly, regardless of the defining class.

Like keyboard and mouse events, the touch events are routed events. The events that begin with Preview are tunneling events and the events that begin with Touch are bubbling events. For more information about routed events, see Routed Events Overview. When you handle these events, you can get the position of the input, relative to any element, by calling the GetTouchPoint or GetIntermediateTouchPoints method.

To understand the interaction among the touch events, consider the scenario where a user puts one finger on an element, moves the finger in the element, and then lifts the finger from the element. The following illustration shows the execution of the bubbling events (the tunneling events are omitted for simplicity).

The sequence of touch events.

Touch events

The following list describes the sequence of the events in the preceding illustration.

  1. The TouchEnter event occurs one time when the user puts a finger on the element.

  2. The TouchDown event occurs one time.

  3. The TouchMove event occurs multiple times as the user moves the finger within the element.

  4. The TouchUp event occurs one time when the user lifts the finger from the element.

  5. The TouchLeave event occurs one time.

When more than two fingers are used, the events occur for each finger.

Manipulation Events

For cases where an application enables a user to manipulate an object, the UIElement class defines manipulation events. Unlike the touch events that simply report the position of touch, the manipulation events report how the input can be interpreted. There are three types of manipulations, translation, expansion, and rotation. The following list describes how to invoke the three types of manipulations.

  • Put a finger on an object and move the finger across the touchscreen to invoke a translation manipulation. This usually moves the object.

  • Put two fingers on an object and move the fingers closer together or farther apart from one another to invoke an expansion manipulation. This usually resizes the object.

  • Put two fingers on an object and rotate the fingers around each other to invoke a rotation manipulation. This usually rotates the object.

More than one type of manipulation can occur simultaneously.

When you cause objects to respond to manipulations, you can have the object appear to have inertia. This can make your objects simulate the physical world. For example, when you push a book across a table, if you push hard enough the book will continue to move after you release it. WPF enables you to simulate this behavior by raising manipulation events after the user's fingers releases the object.

For information about how to create an application that enables the user to move, resize, and rotate an object, see Walkthrough: Creating Your First Touch Application.

The UIElement defines the following manipulation events.

By default, a UIElement does not receive these manipulation events. To receive manipulation events on a UIElement, set UIElement.IsManipulationEnabled to true.

The Execution Path of Manipulation Events

Consider a scenario where a user "throws" an object. The user puts a finger on the object, moves the finger across the touchscreen for a short distance, and then lifts the finger while it is moving. The result of this is that the object will move under the user's finger and continue to move after the user lifts the finger.

The following illustration shows the execution path of manipulation events and important information about each event.

The sequence of manipulation events.

Manipulation events

The following list describes the sequence of the events in the preceding illustration.

  1. The ManipulationStarting event occurs when the user places a finger on the object. Among other things, this event allows you to set the ManipulationContainer property. In the subsequent events, the position of the manipulation will be relative to the ManipulationContainer. In events other than ManipulationStarting, this property is read-only, so the ManipulationStarting event is the only time that you can set this property.

  2. The ManipulationStarted event occurs next. This event reports the origin of the manipulation.

  3. The ManipulationDelta event occurs multiple times as a user's fingers move on a touchscreen. The DeltaManipulation property of the ManipulationDeltaEventArgs class reports whether the manipulation is interpreted as movement, expansion, or translation. This is where you perform most of the work of manipulating an object.

  4. The ManipulationInertiaStarting event occurs when the user's fingers lose contact with the object. This event enables you to specify the deceleration of the manipulations during inertia. This is so your object can emulate different physical spaces or attributes if you choose. For example, suppose your application has two objects that represent items in the physical world, and one is heavier than the other. You can make the heavier object decelerate faster than the lighter object.

  5. The ManipulationDelta event occurs multiple times as inertia occurs. Note that this event occurs when the user's fingers move across the touchscreen and when WPF simulates inertia. In other words, ManipulationDelta occurs before and after the ManipulationInertiaStartingevent. The ManipulationDeltaEventArgs.IsInertial property reports whether the ManipulationDelta event occurs during inertia, so you can check that property and perform different actions, depending on its value.

  6. The ManipulationCompleted event occurs when the manipulation and any inertia ends. That is, after all the ManipulationDelta events occur, the ManipulationCompleted event occurs to signal that the manipulation is complete.

The UIElement also defines the ManipulationBoundaryFeedback event. This event occurs when the ReportBoundaryFeedback method is called in the ManipulationDelta event. The ManipulationBoundaryFeedback event enables applications or components to provide visual feedback when an object hits a boundary. For example, the Window class handles the ManipulationBoundaryFeedback event to cause the window to slightly move when its edge is encountered.

You can cancel the manipulation by calling the Cancel method on the event arguments in any manipulation event except ManipulationBoundaryFeedback event. When you call Cancel, the manipulation events are no longer raised and mouse events occur for touch. The following table describes the relationship between the time the manipulation is canceled and the mouse events that occur.

The event that Cancel is called in

The mouse events that occur for input that already occurred

ManipulationStarting and ManipulationStarted

Mouse down events.

ManipulationDelta

Mouse down and mouse move events.

ManipulationInertiaStarting and ManipulationCompleted 

Mouse down, mouse move, and mouse up events.

Note that if you call Cancel when the manipulation is in inertia, the method returns false and the input does not raise mouse events.

The Relationship Between Touch and Manipulation Events

UIElement can always receive touch events. When the IsManipulationEnabled property is set to true, a UIElement can receive both touch and manipulation events. If the TouchDown event is not handled (that is, the Handled property is false), the manipulation logic captures the touch to the element and generates the manipulation events. If the Handled property is set to true in the TouchDown event, the manipulation logic does not generate manipulation events. The following illustration shows the relationship between touch events and manipulation events.

Relationship between touch and manipulation events

Touch and manipulation events

The following list describes the relationship between the touch and manipulation events that is shown in the preceding illustration.

Focus

There are two main concepts that pertain to focus in WPF: keyboard focus and logical focus.

Keyboard Focus

Keyboard focus refers to the element that is receiving keyboard input. There can be only one element on the whole desktop that has keyboard focus. In WPF, the element that has keyboard focus will have IsKeyboardFocused set to true. The static Keyboard method FocusedElement returns the element that currently has keyboard focus.

Keyboard focus can be obtained by tabbing to an element or by clicking the mouse on certain elements, such as a TextBox. Keyboard focus can also be obtained programmatically by using the Focus method on the Keyboard class. Focus attempts to give the specified element keyboard focus. The element returned by Focus is the element that currently has keyboard focus.

In order for an element to obtain keyboard focus the Focusable property and the IsVisible properties must be set to true. Some classes, such as Panel, have Focusable set to false by default; therefore, you may have to set this property to true if you want that element to be able to obtain focus.

The following example uses Focus to set keyboard focus on a Button. The recommended place to set initial focus in an application is in the Loadedevent handler.

private void OnLoaded(object sender, RoutedEventArgs e)
{
    // Sets keyboard focus on the first Button in the sample.
    Keyboard.Focus(firstButton);
}

For more information about keyboard focus, see Focus Overview.

Logical Focus

Logical focus refers to the FocusManager.FocusedElement in a focus scope. There can be multiple elements that have logical focus in an application, but there may only be one element that has logical focus in a particular focus scope.

A focus scope is a container element that keeps track of the FocusedElement within its scope. When focus leaves a focus scope, the focused element will lose keyboard focus but will retain logical focus. When focus returns to the focus scope, the focused element will obtain keyboard focus. This allows for keyboard focus to be changed between multiple focus scopes but insures that the focused element within the focus scope remains the focused element when focus returns.

An element can be turned into a focus scope in Extensible Application Markup Language (XAML) by setting the FocusManager attached property IsFocusScope to true, or in code by setting the attached property by using the SetIsFocusScope method.

The following example makes a StackPanel into a focus scope by setting the IsFocusScope attached property.

<StackPanel Name="focusScope1" 
            FocusManager.IsFocusScope="True"
            Height="200" Width="200">
  <Button Name="button1" Height="50" Width="50"/>
  <Button Name="button2" Height="50" Width="50"/>
</StackPanel>
StackPanel focuseScope2 = new StackPanel();
FocusManager.SetIsFocusScope(focuseScope2, true);

Classes in WPF which are focus scopes by default are WindowMenuToolBar, and ContextMenu.

An element that has keyboard focus will also have logical focus for the focus scope it belongs to; therefore, setting focus on an element with the Focus method on the Keyboard class or the base element classes will attempt to give the element keyboard focus and logical focus.

To determine the focused element in a focus scope, use GetFocusedElement. To change the focused element for a focus scope, use SetFocusedElement.

For more information about logical focus, see Focus Overview.

Mouse Position

The WPF input API provides helpful information with regard to coordinate spaces. For example, coordinate (0,0) is the upper-left coordinate, but the upper-left of which element in the tree? The element that is the input target? The element you attached your event handler to? Or something else? To avoid confusion, the WPF input API requires that you specify your frame of reference when you work with coordinates obtained through the mouse. The GetPosition method returns the coordinate of the mouse pointer relative to the specified element.

Mouse Capture

Mouse devices specifically hold a modal characteristic known as mouse capture. Mouse capture is used to maintain a transitional input state when a drag-and-drop operation is started, so that other operations involving the nominal on-screen position of the mouse pointer do not necessarily occur. During the drag, the user cannot click without aborting the drag-and-drop, which makes most mouseover cues inappropriate while the mouse capture is held by the drag origin. The input system exposes APIs that can determine mouse capture state, as well as APIs that can force mouse capture to a specific element, or clear mouse capture state. For more information on drag-and-drop operations, see Drag and Drop Overview.

Commands

Commands enable input handling at a more semantic level than device input. Commands are simple directives, such as CutCopyPaste, or Open. Commands are useful for centralizing your command logic. The same command might be accessed from a Menu, on a ToolBar, or through a keyboard shortcut. Commands also provide a mechanism for disabling controls when the command becomes unavailable.

RoutedCommand is the WPF implementation of ICommand. When a RoutedCommand is executed, a PreviewExecuted and an Executed event are raised on the command target, which tunnel and bubble through the element tree like other input. If a command target is not set, the element with keyboard focus will be the command target. The logic that performs the command is attached to a CommandBinding. When an Executed event reaches a CommandBinding for that specific command, the ExecutedRoutedEventHandler on the CommandBinding is called. This handler performs the action of the command.

For more information on commanding, see Commanding Overview.

WPF provides a library of common commands which consists of ApplicationCommandsMediaCommandsComponentCommandsNavigationCommands, and EditingCommands, or you can define your own.

The following example shows how to set up a MenuItem so that when it is clicked it will invoke the Paste command on the TextBox, assuming the TextBox has keyboard focus.

<StackPanel>
  <Menu>
    <MenuItem Command="ApplicationCommands.Paste" />
  </Menu>
  <TextBox />
</StackPanel>
// Creating the UI objects
StackPanel mainStackPanel = new StackPanel();
TextBox pasteTextBox = new TextBox();
Menu stackPanelMenu = new Menu();
MenuItem pasteMenuItem = new MenuItem();

// Adding objects to the panel and the menu
stackPanelMenu.Items.Add(pasteMenuItem);
mainStackPanel.Children.Add(stackPanelMenu);
mainStackPanel.Children.Add(pasteTextBox);

// Setting the command to the Paste command
pasteMenuItem.Command = ApplicationCommands.Paste;

// Setting the command target to the TextBox
pasteMenuItem.CommandTarget = pasteTextBox;

For more information about commands in WPF, see Commanding Overview.

The Input System and Base Elements

Input events such as the attached events defined by the MouseKeyboard, and Stylus classes are raised by the input system and injected into a particular position in the object model based on hit testing the visual tree at run time.

Each of the events that MouseKeyboard, and Stylus define as an attached event is also re-exposed by the base element classes UIElement and ContentElement as a new routed event. The base element routed events are generated by classes handling the original attached event and reusing the event data.

When the input event becomes associated with a particular source element through its base element input event implementation, it can be routed through the remainder of an event route that is based on a combination of logical and visual tree objects, and be handled by application code. Generally, it is more convenient to handle these device-related input events using the routed events on UIElement and ContentElement, because you can use more intuitive event handler syntax both in XAML and in code. You could choose to handle the attached event that initiated the process instead, but you would face several issues: the attached event may be marked handled by the base element class handling, and you need to use accessor methods rather than true event syntax in order to attach handlers for attached events.

What's Next

You now have several techniques to handle input in WPF. You should also have an improved understanding of the various types of input events and the routed event mechanisms used by WPF.

Additional resources are available that explain WPF framework elements and event routing in more detail. See the following overviews for more information, Commanding OverviewFocus OverviewBase Elements OverviewTrees in WPF, and Routed Events Overview.





Commanding Overview


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



Commanding is an input mechanism in Windows Presentation Foundation (WPF) which provides input handling at a more semantic level than device input. Examples of commands are the CopyCut, and Paste operations found on many applications.

This overview defines what commands are in WPF, which classes are part of the commanding model, and how to use and create commands in your applications.

This topic contains the following sections:

What Are Commands?

Commands have several purposes. The first purpose is to separate the semantics and the object that invokes a command from the logic that executes the command. This allows for multiple and disparate sources to invoke the same command logic, and it allows the command logic to be customized for different targets. For example, the editing operations CopyCut, and Paste, which are found in many applications, can be invoked by using different user actions if they are implemented by using commands. An application might allow a user to cut selected objects or text by either clicking a button, choosing an item in a menu, or using a key combination, such as CTRL+X. By using commands, you can bind each type of user action to the same logic.

Another purpose of commands is to indicate whether an action is available. To continue the example of cutting an object or text, the action only makes sense when something is selected. If a user tries to cut an object or text without having anything selected, nothing would happen. To indicate this to the user, many applications disable buttons and menu items so that the user knows whether it is possible to perform an action. A command can indicate whether an action is possible by implementing the CanExecute method. A button can subscribe to the CanExecuteChanged event and be disabled if CanExecute returns false or be enabled if CanExecute returns true.

The semantics of a command can be consistent across applications and classes, but the logic of the action is specific to the particular object acted upon. The key combination CTRL+X invokes the Cut command in text classes, image classes, and Web browsers, but the actual logic for performing the Cut operation is defined by the application that performs the cut. A RoutedCommand enables clients to implement the logic. A text object may cut the selected text into the clipboard, while an image object may cut the selected image. When an application handles the Executed event, it has access to the target of the command and can take appropriate action depending on the target's type.

Simple Command Example in WPF

The simplest way to use a command in WPF is to use a predefined RoutedCommand from one of the command library classes; use a control that has native support for handling the command; and use a control that has native support for invoking a command. The Paste command is one of the predefined commands in the ApplicationCommands class. The TextBox control has built in logic for handling the Paste command. And the MenuItemclass has native support for invoking commands.

The following example shows how to set up a MenuItem so that when it is clicked it will invoke the Paste command on a TextBox, assuming the TextBox has keyboard focus.

<StackPanel>
  <Menu>
    <MenuItem Command="ApplicationCommands.Paste" />
  </Menu>
  <TextBox />
</StackPanel>
// Creating the UI objects
StackPanel mainStackPanel = new StackPanel();
TextBox pasteTextBox = new TextBox();
Menu stackPanelMenu = new Menu();
MenuItem pasteMenuItem = new MenuItem();

// Adding objects to the panel and the menu
stackPanelMenu.Items.Add(pasteMenuItem);
mainStackPanel.Children.Add(stackPanelMenu);
mainStackPanel.Children.Add(pasteTextBox);

// Setting the command to the Paste command
pasteMenuItem.Command = ApplicationCommands.Paste;

// Setting the command target to the TextBox
pasteMenuItem.CommandTarget = pasteTextBox;

Four Main Concepts in WPF Commanding

The routed command model in WPF can be broken up into four main concepts: the command, the command source, the command target, and the command binding:

  • The command is the action to be executed.

  • The command source is the object which invokes the command.

  • The command target is the object that the command is being executed on.

  • The command binding is the object which maps the command logic to the command.

In the previous example, the Paste command is the command, the MenuItem is the command source, the TextBox is the command target, and the command binding is supplied by the TextBox control. It is worth noting that it is not always the case that the CommandBinding is supplied by the control that is the command target class. Quite often the CommandBinding must be created by the application developer, or the CommandBindingmight be attached to an ancestor of the command target.

Commands

Commands in WPF are created by implementing the ICommand interface. ICommand exposes two methods, Execute, and CanExecute, and an event, CanExecuteChangedExecute performs the actions that are associated with the command. CanExecute determines whether the command can execute on the current command target. CanExecuteChanged is raised if the command manager that centralizes the commanding operations detects a change in the command source that might invalidate a command that has been raised but not yet executed by the command binding. The WPF implementation of ICommand is the RoutedCommand class and is the focus of this overview.

The main sources of input in WPF are the mouse, the keyboard, ink, and routed commands. The more device-oriented inputs use a RoutedEvent to notify objects in an application page that an input event has occurred. A RoutedCommand is no different. The Execute and CanExecute methods of a RoutedCommand do not contain the application logic for the command, but rather they raise routed events that tunnel and bubble through the element tree until they encounter an object with a CommandBinding. The CommandBinding contains the handlers for these events and it is the handlers that perform the command. For more information on event routing in WPF, see Routed Events Overview.

The Execute method on a RoutedCommand raises the PreviewExecuted and the Executed events on the command target. The CanExecute method on a RoutedCommand raises the CanExecute and PreviewCanExecute events on the command target. These events tunnel and bubble through the element tree until they encounter an object which has a CommandBinding for that particular command.

WPF supplies a set of common routed commands spread across several classes: MediaCommandsApplicationCommandsNavigationCommandsComponentCommands, and EditingCommands. These classes consist only of the RoutedCommand objects and not the implementation logic of the command. The implementation logic is the responsibility of the object on which the command is being executed on.

Command Sources

A command source is the object which invokes the command. Examples of command sources are MenuItemButton, and KeyGesture.

Command sources in WPF generally implement the ICommandSource interface.

 

ICommandSource exposes three properties: CommandCommandTarget, and CommandParameter:

The WPF classes that implement ICommandSource are ButtonBaseMenuItemHyperlink, and InputBindingButtonBaseMenuItem, and Hyperlinkinvoke a command when they are clicked, and an InputBinding invokes a command when the InputGesture associated with it is performed.

The following example shows how to use a MenuItem in a ContextMenu as a command source for the Properties command.

<StackPanel>
  <StackPanel.ContextMenu>
    <ContextMenu>
      <MenuItem Command="ApplicationCommands.Properties" />
    </ContextMenu>
  </StackPanel.ContextMenu>
</StackPanel>
StackPanel cmdSourcePanel = new StackPanel();
ContextMenu cmdSourceContextMenu = new ContextMenu();
MenuItem cmdSourceMenuItem = new MenuItem();

// Add ContextMenu to the StackPanel.
cmdSourcePanel.ContextMenu = cmdSourceContextMenu;
cmdSourcePanel.ContextMenu.Items.Add(cmdSourceMenuItem);

// Associate Command with MenuItem.
cmdSourceMenuItem.Command = ApplicationCommands.Properties;

Typically, a command source will listen to the CanExecuteChanged event. This event informs the command source that the ability of the command to execute on the current command target may have changed. The command source can query the current status of the RoutedCommand by using the CanExecute method. The command source can then disable itself if the command cannot execute. An example of this is a MenuItemgraying itself out when a command cannot execute.

An InputGesture can be used as a command source. Two types of input gestures in WPF are the KeyGesture and MouseGesture. You can think of a KeyGesture as a keyboard shortcut, such as CTRL+C. A KeyGesture is comprised of a Key and a set of ModifierKeys. A MouseGesture is comprised of a MouseAction and an optional set of ModifierKeys.

In order for an InputGesture to act as a command source, it must be associated with a command. There are a few ways to accomplish this. One way is to use an InputBinding.

The following example shows how to create a KeyBinding between a KeyGesture and a RoutedCommand.

<Window.InputBindings>
  <KeyBinding Key="B"
              Modifiers="Control" 
              Command="ApplicationCommands.Open" />
</Window.InputBindings>
KeyGesture OpenKeyGesture = new KeyGesture(
    Key.B,
    ModifierKeys.Control);

KeyBinding OpenCmdKeybinding = new KeyBinding(
    ApplicationCommands.Open,
    OpenKeyGesture);

this.InputBindings.Add(OpenCmdKeybinding);

Another way to associate an InputGesture to a RoutedCommand is to add the InputGesture to the InputGestureCollection on the RoutedCommand.

The following example shows how to add a KeyGesture to the InputGestureCollection of a RoutedCommand.

KeyGesture OpenCmdKeyGesture = new KeyGesture(
    Key.B,
    ModifierKeys.Control);

ApplicationCommands.Open.InputGestures.Add(OpenCmdKeyGesture);

CommandBinding

CommandBinding associates a command with the event handlers that implement the command.

The CommandBinding class contains a Command property, and PreviewExecutedExecutedPreviewCanExecute, and CanExecute events.

Command is the command that the CommandBinding is being associated with. The event handlers which are attached to the PreviewExecuted and Executed events implement the command logic. The event handlers attached to the PreviewCanExecute and CanExecute events determine if the command can execute on the current command target.

The following example shows how to create a CommandBinding on the root Window of an application. The CommandBinding associates the Opencommand with Executed and CanExecute handlers.

<Window.CommandBindings>
  <CommandBinding Command="ApplicationCommands.Open"
                  Executed="OpenCmdExecuted"
                  CanExecute="OpenCmdCanExecute"/>
</Window.CommandBindings>
// Creating CommandBinding and attaching an Executed and CanExecute handler
CommandBinding OpenCmdBinding = new CommandBinding(
    ApplicationCommands.Open,
    OpenCmdExecuted,
    OpenCmdCanExecute);

this.CommandBindings.Add(OpenCmdBinding);

Next, the ExecutedRoutedEventHandler and a CanExecuteRoutedEventHandler are created. The ExecutedRoutedEventHandler opens a MessageBoxthat displays a string saying the command has been executed. The CanExecuteRoutedEventHandler sets the CanExecute property to true.

void OpenCmdExecuted(object target, ExecutedRoutedEventArgs e)
{
    String command, targetobj;
    command = ((RoutedCommand)e.Command).Name;
    targetobj = ((FrameworkElement)target).Name;
    MessageBox.Show("The " + command +  " command has been invoked on target object " + targetobj);
}
void OpenCmdCanExecute(object sender, CanExecuteRoutedEventArgs e)
{
    e.CanExecute = true;
}

CommandBinding is attached to a specific object, such as the root Window of the application or a control. The object that the CommandBindingis attached to defines the scope of the binding. For example, a CommandBinding attached to an ancestor of the command target can be reached by the Executed event, but a CommandBinding attached to a descendant of the command target cannot be reached. This is a direct consequence of the way a RoutedEvent tunnels and bubbles from the object that raises the event.

In some situations the CommandBinding is attached to the command target itself, such as with the TextBox class and the CutCopy, and Pastecommands. Quite often though, it is more convenient to attach the CommandBinding to an ancestor of the command target, such as the main Window or the Application object, especially if the same CommandBinding can be used for multiple command targets. These are design decisions you will want to consider when you are creating your commanding infrastructure.

Command Target

The command target is the element on which the command is executed. With regards to a RoutedCommand, the command target is the element at which routing of the Executed and CanExecute starts. As noted previously, in WPF the CommandTarget property on ICommandSource is only applicable when the ICommand is a RoutedCommand. If the CommandTarget is set on an ICommandSource and the corresponding command is not a RoutedCommand, the command target is ignored.

The command source can explicitly set the command target. If the command target is not defined, the element with keyboard focus will be used as the command target. One of the benefits of using the element with keyboard focus as the command target is that it allows the application developer to use the same command source to invoke a command on multiple targets without having to keep track of the command target. For example, if a MenuItem invokes the Paste command in an application that has a TextBox control and a PasswordBox control, the target can be either the TextBox or PasswordBox depending on which control has keyboard focus.

The following example shows how to explicitly set the command target in markup and in code behind.

<StackPanel>
  <Menu>
    <MenuItem Command="ApplicationCommands.Paste"
              CommandTarget="{Binding ElementName=mainTextBox}" />
  </Menu>
  <TextBox Name="mainTextBox"/>
</StackPanel>
// Creating the UI objects
StackPanel mainStackPanel = new StackPanel();
TextBox pasteTextBox = new TextBox();
Menu stackPanelMenu = new Menu();
MenuItem pasteMenuItem = new MenuItem();

// Adding objects to the panel and the menu
stackPanelMenu.Items.Add(pasteMenuItem);
mainStackPanel.Children.Add(stackPanelMenu);
mainStackPanel.Children.Add(pasteTextBox);

// Setting the command to the Paste command
pasteMenuItem.Command = ApplicationCommands.Paste;

// Setting the command target to the TextBox
pasteMenuItem.CommandTarget = pasteTextBox;

The CommandManager

The CommandManager serves a number of command related functions. It provides a set of static methods for adding and removing PreviewExecutedExecutedPreviewCanExecute, and CanExecute event handlers to and from a specific element. It provides a means to register CommandBinding and InputBinding objects onto a specific class. The CommandManager also provides a means, through the RequerySuggestedevent, to notify a command when it should raise the CanExecuteChanged event.

The InvalidateRequerySuggested method forces the CommandManager to raise the RequerySuggested event. This is useful for conditions that should disable/enable a command but are not conditions that the CommandManager is aware of.

Command Library

WPF provides a set of predefined commands. The command library consists of the following classes: ApplicationCommandsNavigationCommandsMediaCommandsEditingCommands, and the ComponentCommands. These classes provide commands such as CutBrowseBack and BrowseForwardPlayStop, and Pause.

Many of these commands include a set of default input bindings. For example, if you specify that your application handles the copy command, you automatically get the keyboard binding "CTRL+C" You also get bindings for other input devices, such as Tablet PC pen gestures and speech information.

When you reference commands in the various command libraries using XAML, you can usually omit the class name of the library class that exposes the static command property. Generally, the command names are unambiguous as strings, and the owning types exist to provide a logical grouping of commands but are not necessary for disambiguation. For instance, you can specify Command="Cut" rather than the more verbose Command="ApplicationCommands.Cut". This is a convenience mechanism that is built in to the WPF XAML processor for commands (more precisely, it is a type converter behavior of ICommand, which the WPF XAML processor references at load time).

Creating Custom Commands

If the commands in the command library classes do not meet your needs, then you can create your own commands. There are two ways to create a custom command. The first is to start from the ground up and implement the ICommand interface. The other way, and the more common approach, is to create a RoutedCommand or a RoutedUICommand.

For an example of creating a custom RoutedCommand, see Create a Custom RoutedCommand Sample.






Focus Overview


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


In WPF there are two main concepts that pertain to focus: keyboard focus and logical focus. Keyboard focus refers to the element that receives keyboard input and logical focus refers to the element in a focus scope that has focus. These concepts are discussed in detail in this overview. Understanding the difference in these concepts is important for creating complex applications that have multiple regions where focus can be obtained.

The major classes that participate in focus management are the Keyboard class, the FocusManager class, and the base element classes, such as UIElement and ContentElement. For more information about the base elements, see the Base Elements Overview.

The Keyboard class is concerned primarily with keyboard focus and the FocusManager is concerned primarily with logical focus, but this is not an absolute distinction. An element that has keyboard focus will also have logical focus, but an element that has logical focus does not necessarily have keyboard focus. This is apparent when you use the Keyboard class to set the element that has keyboard focus, for it also sets logical focus on the element.

Keyboard Focus

Keyboard focus refers to the element that is currently receiving keyboard input. There can be only one element on the whole desktop that has keyboard focus. In WPF, the element that has keyboard focus will have IsKeyboardFocused set to true. The static property FocusedElement on the Keyboard class gets the element that currently has keyboard focus. 

In order for an element to obtain keyboard focus, the Focusable and the IsVisible properties on the base elements must be set to true. Some classes, such as the Panel base class, have Focusable set to false by default; therefore, you must set Focusable to true if you want such an element to be able to obtain keyboard focus.

Keyboard focus can be obtained through user interaction with the UI, such as tabbing to an element or clicking the mouse on certain elements. Keyboard focus can also be obtained programmatically by using the Focus method on the Keyboard class. The Focus method attempts to give the specified element keyboard focus. The returned element is the element that has keyboard focus, which might be a different element than requested if either the old or new focus object block the request. 

The following example uses the Focus method to set keyboard focus on a Button.

private void OnLoaded(object sender, RoutedEventArgs e)
{
    // Sets keyboard focus on the first Button in the sample.
    Keyboard.Focus(firstButton);
}

The IsKeyboardFocused property on the base element classes gets a value indicating whether the element has keyboard focus. The IsKeyboardFocusWithin property on the base element classes gets a value indicating whether the element or any one of its visual child elements has keyboard focus.

When setting initial focus at application startup, the element to receive focus must be in the visual tree of the initial window loaded by the application, and the element must have Focusable and IsVisible set to true. The recommended place to set initial focus is in the Loaded event handler. Dispatcher callback can also be used by calling Invoke or BeginInvoke.

Logical Focus

Logical focus refers to the FocusManager.FocusedElement in a focus scope. A focus scope is an element that keeps track of the FocusedElement within its scope. When keyboard focus leaves a focus scope, the focused element will lose keyboard focus but will retain logical focus. When keyboard focus returns to the focus scope, the focused element will obtain keyboard focus. This allows for keyboard focus to be changed between multiple focus scopes but ensures that the focused element in the focus scope regains keyboard focus when focus returns to the focus scope.

There can be multiple elements that have logical focus in an application, but there may only be one element that has logical focus in a particular focus scope.

An element that has keyboard focus has logical focus for the focus scope it belongs to.

An element can be turned into a focus scope in Extensible Application Markup Language (XAML) by setting the FocusManager attached property IsFocusScope to true. In code, an element can be turned into a focus scope by calling SetIsFocusScope.

The following example makes a StackPanel into a focus scope by setting the IsFocusScope attached property.

<StackPanel Name="focusScope1" 
            FocusManager.IsFocusScope="True"
            Height="200" Width="200">
  <Button Name="button1" Height="50" Width="50"/>
  <Button Name="button2" Height="50" Width="50"/>
</StackPanel>
StackPanel focuseScope2 = new StackPanel();
FocusManager.SetIsFocusScope(focuseScope2, true);

GetFocusScope returns the focus scope for the specified element.

Classes in WPF which are focus scopes by default are WindowMenuItemToolBar, and ContextMenu.

GetFocusedElement gets the focused element for the specified focus scope. SetFocusedElement sets the focused element in the specified focus scope. SetFocusedElement is typically used to set the initial focused element.

The following example sets the focused element on a focus scope and gets the focused element of a focus scope.

// Sets the focused element in focusScope1
// focusScope1 is a StackPanel.
FocusManager.SetFocusedElement(focusScope1, button2);

// Gets the focused element for focusScope 1
IInputElement focusedElement = FocusManager.GetFocusedElement(focusScope1);

Keyboard Navigation

The KeyboardNavigation class is responsible for implementing default keyboard focus navigation when one of the navigation keys is pressed. The navigation keys are: TAB, SHIFT+TAB, CTRL+TAB, CTRL+SHIFT+TAB, UPARROW, DOWNARROW, LEFTARROW, and RIGHTARROW keys.

The navigation behavior of a navigation container can be changed by setting the attached KeyboardNavigation properties TabNavigationControlTabNavigation, and DirectionalNavigation. These properties are of type KeyboardNavigationMode and the possible values are ContinueLocalContainedCycleOnce, and None. The default value is Continue, which means the element is not a navigation container.

The following example creates a Menu with a number of MenuItem objects. The TabNavigation attached property is set to Cycle on the Menu. When focus is changed using the tab key within the Menu, focus will move from each element and when the last element is reached focus will return to the first element.

<Menu KeyboardNavigation.TabNavigation="Cycle">
  <MenuItem Header="Menu Item 1" />
  <MenuItem Header="Menu Item 2" />
  <MenuItem Header="Menu Item 3" />
  <MenuItem Header="Menu Item 4" />
</Menu>
Menu navigationMenu = new Menu();
MenuItem item1 = new MenuItem();
MenuItem item2 = new MenuItem();
MenuItem item3 = new MenuItem();
MenuItem item4 = new MenuItem();

navigationMenu.Items.Add(item1);
navigationMenu.Items.Add(item2);
navigationMenu.Items.Add(item3);
navigationMenu.Items.Add(item4);

KeyboardNavigation.SetTabNavigation(navigationMenu, 
    KeyboardNavigationMode.Cycle);

Navigating Focus Programmatically

Additional API to work with focus are MoveFocus and PredictFocus.

MoveFocus changes focus to the next element in the application. A TraversalRequest is used to specify the direction. The FocusNavigationDirectionpassed to MoveFocus specifies the different directions focus can be moved, such as FirstLastUp and Down.

The following example uses MoveFocus to change the focused element.

// Creating a FocusNavigationDirection object and setting it to a
// local field that contains the direction selected.
FocusNavigationDirection focusDirection = _focusMoveValue;

// MoveFocus takes a TraveralReqest as its argument.
TraversalRequest request = new TraversalRequest(focusDirection);

// Gets the element with keyboard focus.
UIElement elementWithFocus = Keyboard.FocusedElement as UIElement;

// Change keyboard focus.
if (elementWithFocus != null)
{
    elementWithFocus.MoveFocus(request);
}

PredictFocus returns the object which would receive focus if focus were to be changed. Currently, only UpDownLeft, and Right are supported by PredictFocus.

Focus Events

The events related to keyboard focus are PreviewGotKeyboardFocusGotKeyboardFocus and PreviewLostKeyboardFocusLostKeyboardFocus. The events are defined as attached events on the Keyboard class, but are more readily accessible as equivalent routed events on the base element classes. For more information about events, see the Routed Events Overview.

GotKeyboardFocus is raised when the element obtains keyboard focus. LostKeyboardFocus is raised when the element loses keyboard focus. If the PreviewGotKeyboardFocus event or the PreviewLostKeyboardFocusEvent event is handled and Handled is set to true, then focus will not change.

The following example attaches GotKeyboardFocus and LostKeyboardFocus event handlers to a TextBox.

<Border BorderBrush="Black" BorderThickness="1"
        Width="200" Height="100" Margin="5">
  <StackPanel>
    <Label HorizontalAlignment="Center" Content="Type Text In This TextBox" />
    <TextBox Width="175"
             Height="50" 
             Margin="5"
             TextWrapping="Wrap"
             HorizontalAlignment="Center"
             VerticalScrollBarVisibility="Auto"
             GotKeyboardFocus="TextBoxGotKeyboardFocus"
             LostKeyboardFocus="TextBoxLostKeyboardFocus"
             KeyDown="SourceTextKeyDown"/>
  </StackPanel>
</Border>

When the TextBox obtains keyboard focus, the Background property of the TextBox is changed to LightBlue.

private void TextBoxGotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
{
    TextBox source = e.Source as TextBox;

    if (source != null)
    {
        // Change the TextBox color when it obtains focus.
        source.Background = Brushes.LightBlue;

        // Clear the TextBox.
        source.Clear();
    }
}

When the TextBox loses keyboard focus, the Background property of the TextBox is changed back to white.

private void TextBoxLostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
{
    TextBox source = e.Source as TextBox;

    if (source != null)
    {
        // Change the TextBox color when it loses focus.
        source.Background = Brushes.White;

        // Set the  hit counter back to zero and updates the display.
        this.ResetCounter();
    }
} 

The events related to logical focus are GotFocus and LostFocus. These events are defined on the FocusManager as attached events, but the FocusManager does not expose CLR event wrappers. UIElement and ContentElement expose these events more conveniently.



Styling for Focus in Controls, and FocusVisualStyle


Windows Presentation Foundation (WPF) provides two parallel mechanisms for changing the visual appearance of a control when it receives keyboard focus. The first mechanism is to use property setters for properties such as IsKeyboardFocused within the style or template that is applied to the control. The second mechanism is to provide a separate style as the value of the FocusVisualStyle property; the "focus visual style" creates a separate visual tree for an adorner that draws on top of the control, rather than changing the visual tree of the control or other UI element by replacing it. This topic discusses the scenarios where each of these mechanisms is appropriate.

The Purpose of Focus Visual Style

The focus visual style feature provides a common "object model" for introducing visual user feedback based on keyboard navigation to any UI element. This is possible without applying a new template to the control, or knowing the specific template composition.

However, precisely because the focus visual style feature works without knowing the control templates, the visual feedback that can be displayed for a control using a focus visual style is necessarily limited. What the feature actually does is to overlay a different visual tree (an adorner) on top of the visual tree as created by a control's rendering through its template. You define this separate visual tree using a style that fills the FocusVisualStyleproperty.

Default Focus Visual Style Behavior

Focus visual styles act only when the focus action was initiated by the keyboard. Any mouse action or programmatic focus change disables the mode for focus visual styles. For more information about the distinctions between focus modes, see Focus Overview.

The themes for controls include a default focus visual style behavior that becomes the focus visual style for all controls in the theme. This theme style is identified by the value of the static key FocusVisualStyleKey. When you declare your own focus visual style at the application level, you replace this default style behavior from the themes. Alternatively, if you define the entire theme, then you should use this same key to define the style for the default behavior for your entire theme.

In the themes, the default focus visual style is generally very simple. The following is a rough approximation:

<Style x:Key="{x:Static SystemParameters.FocusVisualStyleKey}">
  <Setter Property="Control.Template">
    <Setter.Value>
      <ControlTemplate>
        <Rectangle StrokeThickness="1"
          Stroke="Black"
          StrokeDashArray="1 2"
          SnapsToDevicePixels="true"/>
      </ControlTemplate>
    </Setter.Value>
  </Setter>
</Style>

When to Use Focus Visual Styles

Conceptually, the appearance of focus visual styles applied to controls should be coherent from control to control. One way to ensure coherence is to change the focus visual style only if you are composing an entire theme, where each control that is defined in the theme gets either the very same focus visual style, or some variation of a style that is visually related from control to control. Alternatively, you might use the same style (or similar styles) to style every keyboard-focusable element on a page or in a UI.

Setting FocusVisualStyle on individual control styles that are not part of a theme is not the intended usage of focus visual styles. This is because an inconsistent visual behavior between controls can lead to a confusing user experience regarding keyboard focus. If you are intending control-specific behaviors for keyboard focus that are deliberately not coherent across a theme, a much better approach is to use triggers in styles for individual input state properties, such as IsFocused or IsKeyboardFocused.

Focus visual styles act exclusively for keyboard focus. As such, focus visual styles are a type of accessibility feature. If you want UI changes for any type of focus, whether via mouse, keyboard, or programmatically, then you should not use focus visual styles, and should instead use setters and triggers in styles or templates that are working from the value of general focus properties such as IsFocused or IsFocusWithin.

How to Create a Focus Visual Style

The style you create for a focus visual style should always have the TargetType of Control. The style should consist mainly of a ControlTemplate. You do not specify the target type to be the type where the focus visual style is assigned to the FocusVisualStyle.

Because the target type is always Control, you must style by using properties that are common to all controls (using properties of the Control class and its base classes). You should create a template that will properly function as an overlay to a UI element and that will not obscure functional areas of the control. Generally, this means that the visual feedback should appear outside the control margins, or as temporary or unobtrusive effects that will not block the hit testing on the control where the focus visual style is applied. Properties that you can use in template binding that are useful for determining sizing and positioning of your overlay template include ActualHeightActualWidthMargin, and Padding.

Alternatives to Using a Focus Visual Style

For situations where using a focus visual style is not appropriate, either because you are only styling single controls or because you want greater control over the control template, there are many other accessible properties and techniques that can create visual behavior in response to changes in focus.

Triggers, setters, and event setters are all discussed in detail in Styling and Templating. Routed event handling is discussed in Routed Events Overview.

IsKeyboardFocused

If you are specifically interested in keyboard focus, the IsKeyboardFocused dependency property can be used for a property Trigger. A property trigger in either a style or template is a more appropriate technique for defining a keyboard focus behavior that is very specifically for a single control, and which might not visually match the keyboard focus behavior for other controls.

Another similar dependency property is IsKeyboardFocusWithin, which might be appropriate to use if you want to visually call out that keyboard focus is somewhere within compositing or within the functional area of the control. For example, you might place an IsKeyboardFocusWithintrigger such that a panel that groups several controls appears differently, even though keyboard focus might more precisely be on an individual element within that panel.

You can also use the events GotKeyboardFocus and LostKeyboardFocus (as well as their Preview equivalents). You can use these events as the basis for an EventSetter, or you can write handlers for the events in code-behind.

If you want all possible causes of changing focus to produce a visual behavior, you should base a setter or trigger on the IsFocused dependency property, or alternatively on the GotFocus or LostFocus events used for an EventSetter.



Walkthrough: Creating Your First Touch Application


WPF enables applications to respond to touch. For example, you can interact with an application by using one or more fingers on a touch-sensitive device, such as a touchscreen This walkthrough creates an application that enables the user to move, resize, or rotate a single object by using touch.

Prerequisites

You need the following components to complete this walkthrough:

  • Microsoft Visual Studio 2010.

  • Windows 7.

  • A device that accepts touch input, such as a touchscreen, that supports Windows Touch.

Additionally, you should have a basic understanding of how to create an application in WPF, especially how to subscribe to and handle an event. For more information, see Walkthrough: My First WPF Desktop Application.

Creating the Application

To create the application

  1. Create a new WPF Application project in Visual Basic or Visual C# named BasicManipulation. For more information, see How to: Create a New WPF Application Project.

  2. Replace the contents of MainWindow.xaml with the following XAML.

    This markup creates a simple application that contains a red Rectangle on a Canvas. The IsManipulationEnabled property of the Rectangle is set to true so that it will receive manipulation events. The application subscribes to the ManipulationStartingManipulationDelta, and ManipulationInertiaStarting events. These events contain the logic to move the Rectangle when the user manipulates it.

    <Window x:Class="BasicManipulation.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="Move, Size, and Rotate the Square"
            WindowState="Maximized"
            ManipulationStarting="Window_ManipulationStarting"
            ManipulationDelta="Window_ManipulationDelta"
            ManipulationInertiaStarting="Window_InertiaStarting">
      <Window.Resources>
    
        <!--The movement, rotation, and size of the Rectangle is 
            specified by its RenderTransform.-->
        <MatrixTransform x:Key="InitialMatrixTransform">
          <MatrixTransform.Matrix>
            <Matrix OffsetX="200" OffsetY="200"/>
          </MatrixTransform.Matrix>
        </MatrixTransform>
    
      </Window.Resources>
    
      <Canvas>
        <Rectangle Fill="Red" Name="manRect"
                     Width="200" Height="200" 
                     RenderTransform="{StaticResource InitialMatrixTransform}"
                     IsManipulationEnabled="true" />
      </Canvas>
    </Window>
    
    
  3. If you are using Visual Basic, in the first line of MainWindow.xaml, replace x:Class="BasicManipulation.MainWindow" with x:Class="MainWindow".

  4. In the MainWindow class, add the following ManipulationStarting event handler.

    The ManipulationStarting event occurs when WPF detects that touch input begins to manipulate an object. The code specifies that the position of the manipulation should be relative to the Window by setting the ManipulationContainer property.

    void Window_ManipulationStarting(object sender, ManipulationStartingEventArgs e)
    {
        e.ManipulationContainer = this;
        e.Handled = true;
    }
    
  5. In the MainWindow class, add the following ManipulationDelta event handler.

    The ManipulationDelta event occurs when the touch input changes position and can occur multiple times during a manipulation. The event can also occur after a finger is raised. For example, if the user drags a finger across a screen, the ManipulationDelta event occurs multiple times as the finger moves. When the user raises a finger from the screen, the ManipulationDelta event keeps occurring to simulate inertia.

    The code applies the DeltaManipulation to the RenderTransform of the Rectangle to move it as the user moves the touch input. It also checks whether the Rectangle is outside the bounds of the Window when the event occurs during inertia. If so, the application calls the ManipulationDeltaEventArgs.Complete method to end the manipulation.

    void Window_ManipulationDelta(object sender, ManipulationDeltaEventArgs e)
    {
    
        // Get the Rectangle and its RenderTransform matrix.
        Rectangle rectToMove = e.OriginalSource as Rectangle;
        Matrix rectsMatrix = ((MatrixTransform)rectToMove.RenderTransform).Matrix;
    
        // Rotate the Rectangle.
        rectsMatrix.RotateAt(e.DeltaManipulation.Rotation, 
                             e.ManipulationOrigin.X, 
                             e.ManipulationOrigin.Y);
    
        // Resize the Rectangle.  Keep it square 
        // so use only the X value of Scale.
        rectsMatrix.ScaleAt(e.DeltaManipulation.Scale.X, 
                            e.DeltaManipulation.Scale.X, 
                            e.ManipulationOrigin.X,
                            e.ManipulationOrigin.Y);
    
        // Move the Rectangle.
        rectsMatrix.Translate(e.DeltaManipulation.Translation.X,
                              e.DeltaManipulation.Translation.Y);
    
        // Apply the changes to the Rectangle.
        rectToMove.RenderTransform = new MatrixTransform(rectsMatrix);
    
        Rect containingRect =
            new Rect(((FrameworkElement)e.ManipulationContainer).RenderSize);
    
        Rect shapeBounds =
            rectToMove.RenderTransform.TransformBounds(
                new Rect(rectToMove.RenderSize));
    
        // Check if the rectangle is completely in the window.
        // If it is not and intertia is occuring, stop the manipulation.
        if (e.IsInertial && !containingRect.Contains(shapeBounds))
        {
            e.Complete();
        }
    
    
        e.Handled = true;
    }
    

  6. In the MainWindow class, add the following ManipulationInertiaStarting event handler.

    The ManipulationInertiaStarting event occurs when the user raises all fingers from the screen. The code sets the initial velocity and deceleration for the movement, expansion, and rotation of the rectangle.

    void Window_InertiaStarting(object sender, ManipulationInertiaStartingEventArgs e)
    {
    
        // Decrease the velocity of the Rectangle's movement by 
        // 10 inches per second every second.
        // (10 inches * 96 pixels per inch / 1000ms^2)
        e.TranslationBehavior.DesiredDeceleration = 10.0 * 96.0 / (1000.0 * 1000.0);
    
        // Decrease the velocity of the Rectangle's resizing by 
        // 0.1 inches per second every second.
        // (0.1 inches * 96 pixels per inch / (1000ms^2)
        e.ExpansionBehavior.DesiredDeceleration = 0.1 * 96 / (1000.0 * 1000.0);
    
        // Decrease the velocity of the Rectangle's rotation rate by 
        // 2 rotations per second every second.
        // (2 * 360 degrees / (1000ms^2)
        e.RotationBehavior.DesiredDeceleration = 720 / (1000.0 * 1000.0);
    
        e.Handled = true;
    }
    

  7. Build and run the project.

    You should see a red square appear in the window.

Testing the Application

To test the application, try the following manipulations. Note that you can do more than one of the following at the same time.

  • To move the Rectangle, put a finger on the Rectangle and move the finger across the screen.

  • To resize the Rectangle, put two fingers on the Rectangle and move the fingers closer together or farther apart from each other.

  • To rotate the Rectangle, put two fingers on the Rectangle and rotate the fingers around each other.

To cause inertia, quickly raise your fingers from the screen as you perform the previous manipulations. The Rectangle will continue to move, resize, or rotate for a few seconds before it stops.



Input and Commands How-to Topics


The following example demonstrates how to use commanding in Windows Presentation Foundation (WPF). The example shows how to associate a RoutedCommand to a Button, create a CommandBinding, and create the event handlers which implement the RoutedCommand. For more information on commanding, see the Commanding Overview.

Example

The first section of code creates the user interface (UI), which consists of a Button and a StackPanel, and creates a CommandBinding that associates the command handlers with the RoutedCommand.

The Command property of the Button is associated with the Close command.

The CommandBinding is added to the CommandBindingCollection of the root Window. The Executed and CanExecute event handlers are attached to this binding and associated with the Close command.

Without the CommandBinding there is no command logic, only a mechanism to invoke the command. When the Button is clicked, the PreviewExecuted RoutedEvent is raised on the command target followed by the Executed RoutedEvent. These events traverse the element tree looking for a CommandBinding for that particular command. It is worth noting that because RoutedEvent tunnel and bubble through the element tree, care must be taken in where the CommandBinding is put. If the CommandBinding is on a sibling of the command target or another node that is not on the route of the RoutedEvent, the CommandBinding will not be accessed.

<Window x:Class="WCSamples.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="CloseCommand"
    Name="RootWindow"
    >
  <Window.CommandBindings>
    <CommandBinding Command="ApplicationCommands.Close"
                    Executed="CloseCommandHandler"
                    CanExecute="CanExecuteHandler"
                    />
  </Window.CommandBindings>
  <StackPanel Name="MainStackPanel">
    <Button Command="ApplicationCommands.Close" 
            Content="Close File" />
  </StackPanel>
</Window>
// Create ui elements.
StackPanel CloseCmdStackPanel = new StackPanel();
Button CloseCmdButton = new Button();
CloseCmdStackPanel.Children.Add(CloseCmdButton);

// Set Button's properties.
CloseCmdButton.Content = "Close File";
CloseCmdButton.Command = ApplicationCommands.Close;

// Create the CommandBinding.
CommandBinding CloseCommandBinding = new CommandBinding(
    ApplicationCommands.Close, CloseCommandHandler, CanExecuteHandler);

// Add the CommandBinding to the root Window.
RootWindow.CommandBindings.Add(CloseCommandBinding);

The next section of code implements the Executed and CanExecute event handlers.

The Executed handler calls a method to close the open file. The CanExecute handler calls a method to determine whether a file is open. If a file is open, CanExecute is set to true; otherwise, it is set to false.

// Executed event handler.
private void CloseCommandHandler(object sender, ExecutedRoutedEventArgs e)
{
    // Calls a method to close the file and release resources.
    CloseFile();
}

// CanExecute event handler.
private void CanExecuteHandler(object sender, CanExecuteRoutedEventArgs e)
{
    // Call a method to determine if there is a file open.
    // If there is a file open, then set CanExecute to true.
    if (IsFileOpened())
    {
        e.CanExecute = true;
    }
    // if there is not a file open, then set CanExecute to false.
    else
    {
        e.CanExecute = false;
    }
}



How to: Change the Cursor Type


This example shows how to change the Cursor of the mouse pointer for a specific element and for the application.

This example consists of a Extensible Application Markup Language (XAML) file and a code behind file.

Example

The user interface is created, which consists of a ComboBox to select the desired Cursor, a pair of RadioButton objects to determine if the cursor change applies to only a single element or applies to the entire application, and a Border which is the element that the new cursor is applied to.

<StackPanel>
  <Border Width="300">
    <StackPanel Orientation="Horizontal"
                HorizontalAlignment="Center">
      <StackPanel Margin="10">
        <Label HorizontalAlignment="Left">Cursor Type</Label>
        <ComboBox Width="100"
                  SelectionChanged="CursorTypeChanged"
                  HorizontalAlignment="Left"
                  Name="CursorSelector">
          <ComboBoxItem Content="AppStarting" />
          <ComboBoxItem Content="ArrowCD" />
          <ComboBoxItem Content="Arrow" />
          <ComboBoxItem Content="Cross" />
          <ComboBoxItem Content="HandCursor" />
          <ComboBoxItem Content="Help" />
          <ComboBoxItem Content="IBeam" />
          <ComboBoxItem Content="No" />
          <ComboBoxItem Content="None" />
          <ComboBoxItem Content="Pen" />
          <ComboBoxItem Content="ScrollSE" />
          <ComboBoxItem Content="ScrollWE" />
          <ComboBoxItem Content="SizeAll" />
          <ComboBoxItem Content="SizeNESW" />
          <ComboBoxItem Content="SizeNS" />
          <ComboBoxItem Content="SizeNWSE" />
          <ComboBoxItem Content="SizeWE" />
          <ComboBoxItem Content="UpArrow" />
          <ComboBoxItem Content="WaitCursor" />
          <ComboBoxItem Content="Custom" />
        </ComboBox>
      </StackPanel>
      <!-- The user can select different cursor types using this ComboBox -->
      <StackPanel Margin="10">
        <Label HorizontalAlignment="Left">Scope of Cursor</Label>
        <StackPanel>
          <RadioButton Name="rbScopeElement" IsChecked="True"
                       Checked="CursorScopeSelected">Display Area Only</RadioButton>
          <RadioButton Name="rbScopeApplication"
                       Checked="CursorScopeSelected">Entire Appliation</RadioButton>
        </StackPanel>
      </StackPanel>
    </StackPanel>
  </Border>
  <!-- When the mouse pointer is over this Border -->
  <!-- the selected cursor type is shown -->
  <Border Name="DisplayArea" Height="250" Width="400"
          Margin="20" Background="AliceBlue">
    <Label HorizontalAlignment="Center">
      Move Mouse Pointer Over This Area
    </Label>
  </Border>
</StackPanel>

The following code behind creates a SelectionChanged event handler which is called when the cursor type is changed in the ComboBox. A switch statement filters on the cursor name and sets the Cursor property on the Border which is named DisplayArea.

If the cursor change is set to "Entire Application", the OverrideCursor property is set to the Cursor property of the Border control. This forces the cursor to change for the whole application.

private void CursorTypeChanged(object sender, SelectionChangedEventArgs e)
{
    ComboBox source = e.Source as ComboBox;

    if (source != null)
    {
        ComboBoxItem selectedCursor = source.SelectedItem as ComboBoxItem;

        // Changing the cursor of the Border control 
        // by setting the Cursor property
        switch (selectedCursor.Content.ToString())
        {
            case "AppStarting":
                DisplayArea.Cursor = Cursors.AppStarting;
                break;
            case "ArrowCD":                        
                DisplayArea.Cursor = Cursors.ArrowCD;
                break;
            case "Arrow":
                DisplayArea.Cursor = Cursors.Arrow;
                break;
            case "Cross":
                DisplayArea.Cursor = Cursors.Cross;
                break;
            case "HandCursor":
                DisplayArea.Cursor = Cursors.Hand;
                break;
            case "Help":
                DisplayArea.Cursor = Cursors.Help;
                break;
            case "IBeam":
                DisplayArea.Cursor = Cursors.IBeam;
                break;
            case "No":
                DisplayArea.Cursor = Cursors.No;
                break;
            case "None":
                DisplayArea.Cursor = Cursors.None;
                break;
            case "Pen":
                DisplayArea.Cursor = Cursors.Pen;
                break;
            case "ScrollSE":
                DisplayArea.Cursor = Cursors.ScrollSE;
                break;
            case "ScrollWE":
                DisplayArea.Cursor = Cursors.ScrollWE;
                break;
            case "SizeAll":
                DisplayArea.Cursor = Cursors.SizeAll;
                break;
            case "SizeNESW":
                DisplayArea.Cursor = Cursors.SizeNESW;
                break;
            case "SizeNS":
                DisplayArea.Cursor = Cursors.SizeNS;
                break;
            case "SizeNWSE":
                DisplayArea.Cursor = Cursors.SizeNWSE;
                break;
            case "SizeWE":
                DisplayArea.Cursor = Cursors.SizeWE;
                break;
            case "UpArrow":
                DisplayArea.Cursor = Cursors.UpArrow;
                break;
            case "WaitCursor":
                DisplayArea.Cursor = Cursors.Wait;
                break;
            case "Custom":
                DisplayArea.Cursor = CustomCursor;
                break;
            default:
                break;
        }

        // If the cursor scope is set to the entire application
        // Use OverrideCursor to force the cursor for all elements
        if (cursorScopeElementOnly == false)
        {
            Mouse.OverrideCursor = DisplayArea.Cursor;
        }
    }
}





How to: Change the Color of an Element Using Focus Events

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

This example shows how to change the color of an element when it gains and loses focus by using the GotFocus and LostFocus events.

This example consists of a Extensible Application Markup Language (XAML) file and a code-behind file.

Example

The following XAML creates the user interface, which consists of two Button objects, and attaches event handlers for the GotFocus and LostFocus events to the Button objects.

<StackPanel>
  <StackPanel.Resources>
    <Style TargetType="{x:Type Button}">
      <Setter Property="Height" Value="20"/>
      <Setter Property="Width" Value="250"/>
      <Setter Property="HorizontalAlignment" Value="Left"/>
    </Style>
  </StackPanel.Resources>
  <Button
      GotFocus="OnGotFocusHandler"
      LostFocus="OnLostFocusHandler">Click Or Tab To Give Keyboard Focus</Button>
  <Button
      GotFocus="OnGotFocusHandler"
      LostFocus="OnLostFocusHandler">Click Or Tab To Give Keyborad Focus</Button>
</StackPanel>

The following code behind creates the GotFocus and LostFocus event handlers. When the Button gains keyboard focus, the Background of the Button is changed to red. When the Button loses keyboard focus, the Background of the Button is changed back to white.

public partial class Window1 : Window
{
    public Window1()
    {
        InitializeComponent();
    }

    // Raised when Button gains focus.
    // Changes the color of the Button to Red.
    private void OnGotFocusHandler(object sender, RoutedEventArgs e)
    {
        Button tb = e.Source as Button;
        tb.Background = Brushes.Red;
    }
    // Raised when Button losses focus. 
    // Changes the color of the Button back to white.
    private void OnLostFocusHandler(object sender, RoutedEventArgs e)
    {
        Button tb = e.Source as Button;
        tb.Background = Brushes.White;
    }
}




How to: Apply a FocusVisualStyle to a Control


This example shows you how to create a focus visual style in resources and apply the style to a control, using the FocusVisualStyle property.

Example

The following example defines a style that creates additional control compositing that only applies when that control is keyboard focused in the user interface (UI). This is accomplished by defining a style with a ControlTemplate, then referencing that style as a resource when setting the FocusVisualStyle property.

An external rectangle resembling a border is placed outside of the rectangular area. Unless otherwise modified, the sizing of the style uses the ActualHeight and ActualWidth of the rectangular control where the focus visual style is applied. This example sets negative values for the Margin to make the border appear slightly outside the focused control.

<Page
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
>
  <Page.Resources>
    <Style x:Key="MyFocusVisual">
      <Setter Property="Control.Template">
        <Setter.Value>
          <ControlTemplate>
            <Rectangle Margin="-2" StrokeThickness="1" Stroke="Red" StrokeDashArray="1 2"/>
          </ControlTemplate>
        </Setter.Value>
      </Setter>
    </Style>
  </Page.Resources>
  <StackPanel Background="Ivory" Orientation="Horizontal">
    <Canvas Width="10"/>
    <Button Width="100" Height="30" FocusVisualStyle="{DynamicResource MyFocusVisual}">
      Focus Here</Button>
    <Canvas Width="100"/>
    <Button Width="100" Height="30" FocusVisualStyle="{DynamicResource MyFocusVisual}">
      Focus Here</Button>
  </StackPanel>
</Page>

FocusVisualStyle is additive to any control template style that comes either from an explicit style or a theme style; the primary style for a control can still be created by using a ControlTemplate and setting that style to the Style property.

Focus visual styles should be used consistently across a theme or a UI, rather than using a different one for each focusable element. For details, see Styling for Focus in Controls, and FocusVisualStyle.




How to: Detect When the Enter Key Pressed


This example shows how to detect when the Enter key is pressed on the keyboard.

This example consists of a Extensible Application Markup Language (XAML) file and a code-behind file.

Example

When the user presses the Enter key in the TextBox, the input in the text box appears in another area of the user interface (UI).

The following XAML creates the user interface, which consists of a StackPanel, a TextBlock, and a TextBox.

<StackPanel>
  <TextBlock Width="300" Height="20">
    Type some text into the TextBox and press the Enter key.
  </TextBlock>
  <TextBox Width="300" Height="30" Name="textBox1"
           KeyDown="OnKeyDownHandler"/>
  <TextBlock Width="300" Height="100" Name="textBlock1"/>
</StackPanel>

The following code behind creates the KeyDown event handler. If the key that is pressed is the Enter key, a message is displayed in the TextBlock.

private void OnKeyDownHandler(object sender, KeyEventArgs e)
{
    if (e.Key == Key.Return)
    {
        textBlock1.Text = "You Entered: " + textBox1.Text;
    }
}




How to: Create a Rollover Effect Using Events


This example shows how to change the color of an element as the mouse pointer enters and leaves the area occupied by the element.

This example consists of a Extensible Application Markup Language (XAML) file and a code-behind file.

System_CAPS_noteNote

This example demonstrates how to use events, but the recommended way to achieve this same effect is to use a Trigger in a style. For more information, see Styling and Templating.

Example

The following XAML creates the user interface, which consists of Border around a TextBlock, and attaches the MouseEnter and MouseLeave event handlers to the Border.

<StackPanel>
  <Border MouseEnter="OnMouseEnterHandler"
          MouseLeave="OnMouseLeaveHandler"
          Name="border1" Margin="10"
          BorderThickness="1"
          BorderBrush="Black"
          VerticalAlignment="Center"
          Width="300" Height="100">
    <Label Margin="10" FontSize="14"
           HorizontalAlignment="Center">Move Cursor Over Me</Label>
  </Border>
</StackPanel>

The following code behind creates the MouseEnter and MouseLeave event handlers. When the mouse pointer enters the Border, the background of the Border is changed to red. When the mouse pointer leaves the Border, the background of the Border is changed back to white.

public partial class Window1 : Window
{
    public Window1()
    {
        InitializeComponent();
    }

    // raised when mouse cursor enters the area occupied by the element
    void OnMouseEnterHandler(object sender, MouseEventArgs e)
    {
        border1.Background = Brushes.Red;
    }

    // raised when mouse cursor leaves the area occupied by the element
    void OnMouseLeaveHandler(object sender, MouseEventArgs e)
    {
        border1.Background = Brushes.White;
    }
}




How to: Make an Object Follow the Mouse Pointer


This example shows how to change the dimensions of an object when the mouse pointer moves on the screen.

The example includes an Extensible Application Markup Language (XAML) file that creates the user interface (UI) and a code-behind file that creates the event handler.

Example

The following XAML creates the UI, which consists of an Ellipse inside of a StackPanel, and attaches the event handler for the MouseMove event.

<Window x:Class="WCSamples.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="mouseMoveWithPointer"
    Height="400"
    Width="500"
    >
  <Canvas MouseMove="MouseMoveHandler"
          Background="LemonChiffon">
    <Ellipse Name="ellipse" Fill="LightBlue" 
             Width="100" Height="100"/>
  </Canvas>
</Window>

The following code behind creates the MouseMove event handler. When the mouse pointer moves, the height and the width of the Ellipse are increased and decreased.

// raised when the mouse pointer moves.
// Expands the dimensions of an Ellipse when the mouse moves.
private void MouseMoveHandler(object sender, MouseEventArgs e)
{
    // Get the x and y coordinates of the mouse pointer.
    System.Windows.Point position = e.GetPosition(this);
    double pX = position.X;
    double pY = position.Y;

    // Sets the Height/Width of the circle to the mouse coordinates.
    ellipse.Width = pX;
    ellipse.Height = pY;
}





How to: Create a RoutedCommand


This example shows how to create a custom RoutedCommand and how to implement the custom command by creating a ExecutedRoutedEventHandlerand a CanExecuteRoutedEventHandler and attaching them to a CommandBinding. For more information on commanding, see the Commanding Overview.

Example

The first step in creating a RoutedCommand is defining the command and instantiating it.

public static RoutedCommand CustomRoutedCommand = new RoutedCommand();

In order to use the command in an application, event handlers which define what the command does must be created

private void ExecutedCustomCommand(object sender,
    ExecutedRoutedEventArgs e)
{
    MessageBox.Show("Custom Command Executed");
}
// CanExecuteRoutedEventHandler that only returns true if
// the source is a control.
private void CanExecuteCustomCommand(object sender, 
    CanExecuteRoutedEventArgs e)
{
    Control target = e.Source as Control;

    if(target != null)
    {
        e.CanExecute = true;
    }
    else
    {
        e.CanExecute = false;
    }
}

Next, a CommandBinding is created which associates the command with the event handlers. The CommandBinding is created on a specific object. This object defines the scope of the CommandBinding in the element tree

<Window x:Class="SDKSamples.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:custom="clr-namespace:SDKSamples"
    Height="600" Width="800"
    >
  <Window.CommandBindings>
    <CommandBinding Command="{x:Static custom:Window1.CustomRoutedCommand}"
                    Executed="ExecutedCustomCommand"
                    CanExecute="CanExecuteCustomCommand" />
  </Window.CommandBindings>
CommandBinding customCommandBinding = new CommandBinding(
    CustomRoutedCommand, ExecutedCustomCommand, CanExecuteCustomCommand);

// attach CommandBinding to root window
this.CommandBindings.Add(customCommandBinding);

The final step is invoking the command. One way to invoke a command is to associate it with a ICommandSource, such as a Button.

<StackPanel>
  <Button Command="{x:Static custom:Window1.CustomRoutedCommand}"
          Content="CustomRoutedCommand"/>
</StackPanel>
// create the ui
StackPanel CustomCommandStackPanel = new StackPanel();
Button CustomCommandButton = new Button();
CustomCommandStackPanel.Children.Add(CustomCommandButton);

CustomCommandButton.Command = CustomRoutedCommand; 

When the Button is clicked, the Execute method on the custom RoutedCommand is called. The RoutedCommand raises the PreviewExecuted and Executed routed events. These events traverse the element tree looking for a CommandBinding for this particular command. If a CommandBinding is found, the ExecutedRoutedEventHandler associated with CommandBinding is called.


<Code-behind>

public static RoutedCommand CustomRoutedCommand = new RoutedCommand();


private void ExecutedCustomCommand(object sender,

    ExecutedRoutedEventArgs e)

        {

            MessageBox.Show("Custom Command Executed");

        }


private void CanExecuteCustomCommand(object sender,

    CanExecuteRoutedEventArgs e)

        {

            Control target = e.Source as Control;


            if (target != null)

            {

                e.CanExecute = true;

            }

            else

            {

                e.CanExecute = false;

            }

        }


private void Window_Loaded(object sender, RoutedEventArgs e)

        {

            CommandBinding customCommandBinding = new CommandBinding(CustomRoutedCommand, ExecutedCustomCommand, CanExecuteCustomCommand);


            CommandBindings.Add(customCommandBinding);


            StackPanel CustomCommandStackPanel = new StackPanel();

            Button CustomCommandButton = new Button();

            CustomCommandButton.Content = "버튼";

            CustomCommandStackPanel.Children.Add(CustomCommandButton);


            CustomCommandButton.Command = CustomRoutedCommand;


            Content = CustomCommandStackPanel;

        }


<XAML>

<Window.CommandBindings>

        <CommandBinding Command="{x:Static local:Window1.CustomRoutedCommand}"

                    Executed="ExecutedCustomCommand"

                    CanExecute="CanExecuteCustomCommand" />

    </Window.CommandBindings>

    <StackPanel>

        <Button Command="{x:Static local:Window1.CustomRoutedCommand}" Content="CustomRoutedCommand"/>

    </StackPanel>


public static RoutedCommand CustomRoutedCommand = new RoutedCommand();


        private void ExecutedCustomCommand(object sender,

    ExecutedRoutedEventArgs e)

        {

            MessageBox.Show("Custom Command Executed");

        }


        private void CanExecuteCustomCommand(object sender,

    CanExecuteRoutedEventArgs e)

        {

            Control target = e.Source as Control;            


            if (target != null)

            {

                e.CanExecute = true;

            }

            else

            {

                e.CanExecute = false;

            }

        }




How to: Implement ICommandSource


This example shows how to create a command source by implementing ICommandSource. A command source is an object that knows how to invoke a command. The ICommandSource interface exposes three members: Command, CommandParameter, and CommandTarget. Command is the command which will be invoked. The CommandParameter is a user-defined data type which is passed from the command source to the method which handles the command. The CommandTarget is the object that the command is being executed on.

In this example, a class is created which subclasses the Slider control and implements ICommandSource.

Example

WPF provides a number of classes which implement ICommandSource, such as ButtonMenuItem, and ListBoxItem. A command source defines how it invokes a command. Button and MenuItem invoke a command when they are clicked. A ListBoxItem invokes a command when it is double clicked. These classes only become a command source when their Command property is set.

For this example we will invoke the command when the slider is moved, or more accurately, when the Value property is changed.

The following is the class definition.

public class CommandSlider : Slider, ICommandSource
{
    public CommandSlider() : base()
    {

    }

The next step is to implement the ICommandSource members. In this example, the properties are implemented as DependencyProperty objects. This enables the properties to use data binding. For more information about the DependencyProperty class, see the Dependency Properties Overview. For more information about data binding, see the Data Binding Overview.

Only the Command property is shown here.

// Make Command a dependency property so it can use databinding.
public static readonly DependencyProperty CommandProperty =
    DependencyProperty.Register(
        "Command",
        typeof(ICommand),
        typeof(CommandSlider),
        new PropertyMetadata((ICommand)null,
        new PropertyChangedCallback(CommandChanged)));

public ICommand Command
{
    get 
    {
        return (ICommand)GetValue(CommandProperty);
    }
    set 
    {
        SetValue(CommandProperty, value);
    }
}

The following is the DependencyProperty change callback.

// Command dependency property change callback.
private static void CommandChanged(DependencyObject d,
    DependencyPropertyChangedEventArgs e)
{
    CommandSlider cs = (CommandSlider)d;
    cs.HookUpCommand((ICommand)e.OldValue,(ICommand)e.NewValue);
}

The next step is to add and remove the command which is associated with the command source. The Command property cannot simply be overwritten when a new command is added, because the event handlers associated with the previous command, if there was one, must be removed first.

// Add a new command to the Command Property.
private void HookUpCommand(ICommand oldCommand, ICommand newCommand)
{
    // If oldCommand is not null, then we need to remove the handlers.
    if (oldCommand != null)
    {
        RemoveCommand(oldCommand, newCommand);
    }
    AddCommand(oldCommand, newCommand);
}

// Remove an old command from the Command Property.
private void RemoveCommand(ICommand oldCommand, ICommand newCommand)
{
    EventHandler handler = CanExecuteChanged;
    oldCommand.CanExecuteChanged -= handler;
}

// Add the command.
private void AddCommand(ICommand oldCommand, ICommand newCommand)
{
    EventHandler handler = new EventHandler(CanExecuteChanged);
    canExecuteChangedHandler = handler;
    if (newCommand != null)
    {
        newCommand.CanExecuteChanged += canExecuteChangedHandler;
    }
}

The last step is to create logic for the CanExecuteChanged handler and the Execute method.

The CanExecuteChanged event notifies the command source that the ability of the command to execute on the current command target may have changed. When a command source receives this event, it typically calls the CanExecute method on the command. If the command cannot execute on the current command target, the command source will typically disable itself. If the command can execute on the current command target, the command source will typically enable itself.

private void CanExecuteChanged(object sender, EventArgs e)
{

    if (this.Command != null)
    {
        RoutedCommand command = this.Command as RoutedCommand;

        // If a RoutedCommand.
        if (command != null)
        {
            if (command.CanExecute(CommandParameter, CommandTarget))
            {
                this.IsEnabled = true;
            }
            else
            {
                this.IsEnabled = false;
            }
        }
        // If a not RoutedCommand.
        else
        {
            if (Command.CanExecute(CommandParameter))
            {
                this.IsEnabled = true;
            }
            else
            {
                this.IsEnabled = false;
            }
        }
    }
}

The last step is the Execute method. If the command is a RoutedCommand, the RoutedCommand Execute method is called; otherwise, the ICommand Execute method is called.

// If Command is defined, moving the slider will invoke the command;
// Otherwise, the slider will behave normally.
protected override void OnValueChanged(double oldValue, double newValue)
{
    base.OnValueChanged(oldValue, newValue);

    if (this.Command != null)
    {
        RoutedCommand command = Command as RoutedCommand;

        if (command != null)
        {
            command.Execute(CommandParameter, CommandTarget);
        }
        else
        {
            ((ICommand)Command).Execute(CommandParameter);
        }
    }
}




How to: Hook Up a Command to a Control with No Command Support


The following example shows how to hook up a RoutedCommand to a Control which does not have built in support for the command. For a complete sample which hooks up commands to multiple sources, see the Create a Custom RoutedCommand Sample sample.

Example

Windows Presentation Foundation (WPF) provides a library of common commands which application programmers encounter regularly. The classes which comprise the command library are: ApplicationCommandsComponentCommandsNavigationCommandsMediaCommands, and EditingCommands.

The static RoutedCommand objects which make up these classes do not supply command logic. The logic for the command is associated with the command with a CommandBinding. Many controls in WPF have built in support for some of the commands in the command library. TextBox, for example, supports many of the application edit commands such as PasteCopyCutRedo, and Undo. The application developer does not have to do anything special to get these commands to work with these controls. If the TextBox is the command target when the command is executed, it will handle the command using the CommandBinding that is built into the control.

The following shows how to use a Button as the command source for the Open command. A CommandBinding is created that associates the specified CanExecuteRoutedEventHandler and the CanExecuteRoutedEventHandler with the RoutedCommand.

First, the command source is created. A Button is used as the command source.

<Button Command="ApplicationCommands.Open" Name="MyButton"
        Height="50" Width="200">
  Open (KeyBindings: Ctrl+R, Ctrl+0)
</Button>
// Button used to invoke the command
Button CommandButton = new Button();
CommandButton.Command = ApplicationCommands.Open;
CommandButton.Content = "Open (KeyBindings: Ctrl-R, Ctrl-0)";
MainStackPanel.Children.Add(CommandButton);

Next, the ExecutedRoutedEventHandler and the CanExecuteRoutedEventHandler are created. The ExecutedRoutedEventHandler simply opens a MessageBox to signify that the command executed. The CanExecuteRoutedEventHandler sets the CanExecute property to true. Normally, the can execute handler would perform more robust checks to see if the command could execute on the current command target.

void OpenCmdExecuted(object target, ExecutedRoutedEventArgs e)
{
    String command, targetobj;
    command = ((RoutedCommand)e.Command).Name;
    targetobj = ((FrameworkElement)target).Name;
    MessageBox.Show("The " + command +  " command has been invoked on target object " + targetobj);
}
void OpenCmdCanExecute(object sender, CanExecuteRoutedEventArgs e)
{
    e.CanExecute = true;
}

Finally, a CommandBinding is created on the root Window of the application that associates the routed events handlers to the Open command.

<Window.CommandBindings>
  <CommandBinding Command="ApplicationCommands.Open"
                  Executed="OpenCmdExecuted"
                  CanExecute="OpenCmdCanExecute"/>
</Window.CommandBindings>
// Creating CommandBinding and attaching an Executed and CanExecute handler
CommandBinding OpenCmdBinding = new CommandBinding(
    ApplicationCommands.Open,
    OpenCmdExecuted,
    OpenCmdCanExecute);

this.CommandBindings.Add(OpenCmdBinding);




How to: Hook Up a Command to a Control with Command Support


The following example shows how to hook up a RoutedCommand to a Control which has built in support for the command. For a complete sample which hooks up commands to multiple sources, see the Create a Custom RoutedCommand Sample sample.

Example

Windows Presentation Foundation (WPF) provides a library of common commands which application programmers encounter regularly. The classes which comprise the command library are: ApplicationCommandsComponentCommandsNavigationCommandsMediaCommands, and EditingCommands.

The static RoutedCommand objects which make up these classes do not supply command logic. The logic for the command is associated with the command with a CommandBinding. Some controls have built in CommandBindings for some commands. This mechanism allows the semantics of a command to stay the same, while the actual implementation is can change. A TextBox, for example, handles the Paste command differently than a control designed to support images, but the basic idea of what it means to paste something stays the same. The command logic cannot be supplied by the command, but rather must be supplied by the control or the application.

Many controls in WPF do have built in support for some of the commands in the command library. TextBox, for example, supports many of the application edit commands such as PasteCopyCutRedo, and Undo. The application developer does not have to do anything special to get these commands to work with these controls. If the TextBox is the command target when the command is executed, it will handle the command using the CommandBinding that is built into the control.

The following shows how to use a MenuItem as the command source for the Paste command, where a TextBox is the target of the command. All the logic that defines how the TextBox performs the paste is built into the TextBox control.

MenuItem is created and it's Command property is set to the Paste command. The CommandTarget is not explicitly set to the TextBox object. When the CommandTarget is not set, the target for the command is the element which has keyboard focus. If the element which has keyboard focus does not support the Paste command or cannot currently execute the paste command (the clipboard is empty, for example) then the MenuItem would be grayed out.

<Window x:Class="SDKSamples.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MenuItemCommandTask"
    >
    <DockPanel>
      <Menu DockPanel.Dock="Top">
        <MenuItem Command="ApplicationCommands.Paste" Width="75" />
      </Menu>
      <TextBox BorderBrush="Black" BorderThickness="2" Margin="25"
               TextWrapping="Wrap">
        The MenuItem will not be enabled until
        this TextBox gets keyboard focus  
      </TextBox>
    </DockPanel>
</Window>
// Window1 constructor
public Window1()
{
    InitializeComponent();

    // Instantiating UIElements.
    DockPanel mainPanel = new DockPanel();
    Menu mainMenu = new Menu();
    MenuItem pasteMenuItem = new MenuItem();
    TextBox mainTextBox = new TextBox();

    // Associating the MenuItem with the Paste command.
    pasteMenuItem.Command = ApplicationCommands.Paste;

    // Setting properties on the TextBox.
    mainTextBox.Text =
        "The MenuItem will not be enabled until this TextBox receives keyboard focus.";
    mainTextBox.Margin = new Thickness(25);
    mainTextBox.BorderBrush = Brushes.Black;
    mainTextBox.BorderThickness = new Thickness(2);
    mainTextBox.TextWrapping = TextWrapping.Wrap;

    // Attaching UIElements to the Window.
    this.AddChild(mainPanel);
    mainMenu.Items.Add(pasteMenuItem);
    mainPanel.Children.Add(mainMenu);
    mainPanel.Children.Add(mainTextBox);

    // Defining DockPanel layout.
    DockPanel.SetDock(mainMenu, Dock.Top);
    DockPanel.SetDock(mainTextBox, Dock.Bottom);
}







:
Posted by 지훈2