Tải bản đầy đủ - 0 (trang)
7-18. Use a Drag-and-Drop Operation

7-18. Use a Drag-and-Drop Operation

Tải bản đầy đủ - 0trang

CHAPTER 7 ■ WINDOWS FORMS



How It Works

A drag-and-drop operation allows the user to transfer information from one place to another by clicking

an item and dragging it to another location. A drag-and-drop operation consists of the following three

basic steps:

1.



The user clicks a control, holds down the mouse button, and begins dragging.

If the control supports the drag-and-drop feature, it sets aside some

information.



2.



The user drags the mouse over another control. If this control accepts the

dragged type of content, the mouse cursor changes to the special drag-anddrop icon (arrow and page). Otherwise, the mouse cursor becomes a circle

with a line drawn through it.



3.



When the user releases the mouse button, the data is sent to the control, which

can then process it appropriately.



To support drag-and-drop functionality, you must handle the DragEnter, DragDrop, and (typically)

MouseDown events. To start a drag-and-drop operation, you call the source control’s DoDragDrop method.

At this point, you submit the data and specify the type of operations that will be supported (copying,

moving, and so on). Controls that can receive dragged data must have the AllowDrop property set to true.

These controls will receive a DragEnter event when the mouse drags the data over them. At this point,

you can examine the data that is being dragged, decide whether the control can accept the drop, and set

the DragEventArgs.Effect property accordingly. The final step is to respond to the DragDrop event, which

occurs when the user releases the mouse button.



■ Note It is very important that the Main method of your Windows application be annotated with the STAThread

attribute if your application will provide drag-and-drop functionality.



The Code

The following example allows you to drag content between a RichTextBox and a standard TextBox

control. Using the standard TextBox, it is not possible to drag only the currently selected text because as

soon as you click the selected text to initiate a drag operation, the selection is cleared. Even handling the

MouseDown event will not allow you to work around this because the selected text is already cleared by the

event is raised.

However, the RichTextBox leaves the selection in place, avoiding the problem. Unfortunately, the

RichTextBox has quirks of its own. To drop successfully onto a RichTextBox, you must be holding down

the Ctrl key when you let go of the mouse button. You can also use the example with other applications

that support text drag-and-drop operations.



351



www.it-ebooks.info



CHAPTER 7 ■ WINDOWS FORMS



using System;

using System.Drawing;

using System.Windows.Forms;

namespace Apress.VisualCSharpRecipes.Chapter07

{

public partial class Recipe07_18 : Form

{

public Recipe07_18()

{

// Initialization code is designer generated and contained

// in a separate file named Recipe07-18.Designer.cs.

InitializeComponent();

this.richTextBox1.AllowDrop = true;

this.richTextBox1.EnableAutoDragDrop = false;

this.richTextBox1.DragDrop

+= new System.Windows.Forms.DragEventHandler

(this.RichTextBox_DragDrop);

this.richTextBox1.DragEnter

+= new System.Windows.Forms.DragEventHandler

(this.RichTextBox_DragEnter);

}

private void RichTextBox_DragDrop(object sender, DragEventArgs e)

{

RichTextBox txt = sender as RichTextBox;

if (txt != null)

{

// Insert the dragged text.

int pos = txt.SelectionStart;

string newText = txt.Text.Substring(0, pos)

+ e.Data.GetData(DataFormats.Text).ToString()

+ txt.Text.Substring(pos);

txt.Text = newText;

}

}

private void RichTextBox_DragEnter(object sender, DragEventArgs e)

{

if (e.Data.GetDataPresent(DataFormats.Text))

{

e.Effect = DragDropEffects.Copy;

}



352



www.it-ebooks.info



CHAPTER 7 ■ WINDOWS FORMS



else

{

e.Effect = DragDropEffects.None;

}

}

private void RichTextBox_MouseDown(object sender, MouseEventArgs e)

{

RichTextBox txt = sender as RichTextBox;

// If the left mouse button is pressed and text is selected,

// this is a possible drag event.

if (sender != null && txt.SelectionLength > 0

&& Form.MouseButtons == MouseButtons.Left)

{

// Only initiate a drag if the cursor is currently inside

// the region of selected text.

int pos = txt.GetCharIndexFromPosition(e.Location);

if (pos >= txt.SelectionStart

&& pos <= (txt.SelectionStart + txt.SelectionLength))

{

txt.DoDragDrop(txt.SelectedText, DragDropEffects.Copy);

}

}

}

private void TextBox_DragDrop(object sender, DragEventArgs e)

{

TextBox txt = sender as TextBox;

if (txt != null)

{

txt.Text = (string)e.Data.GetData(DataFormats.Text);

}

}

private void TextBox_DragEnter(object sender, DragEventArgs e)

{

if (e.Data.GetDataPresent(DataFormats.Text))

{

e.Effect = DragDropEffects.Copy;

}

else

{

e.Effect = DragDropEffects.None;

}

}



353



www.it-ebooks.info



CHAPTER 7 ■ WINDOWS FORMS



private void TextBox_MouseDown(object sender, MouseEventArgs e)

{

TextBox txt = sender as TextBox;

if (txt != null && Form.MouseButtons == MouseButtons.Left)

{

txt.SelectAll();

txt.DoDragDrop(txt.Text, DragDropEffects.Copy);

}

}

[STAThread]

public static void Main(string[] args)

{

Application.Run(new Recipe07_18());

}

}

}



7-19. Update the User Interface in a Multithreaded

Application

Problem

You need to ensure a Windows Forms user interface is updated correctly in a multithreaded application.



Solution

Ensure all interaction with a control is performed on the thread that initially created the control. When

calling operations on controls from a thread that did not create the control, make the call using the

control’s Invoke or BeginInvoke methods and pass in a delegate to the code you want executed.



How It Works

Windows Forms is not inherently thread safe, meaning you are not free to interact with controls from

just any thread. Instead, you must marshal all calls to a control onto the thread that owns the message

queue for that control (i.e., the thread that created the control).

You can determine if the executing thread can call a control directly by testing the control’s

InvokeRequired property. If the value is false, then the currently executing thread can interact with the

control directly; otherwise, you must marshal any interaction back onto the correct thread. This

potentially difficult task is made trivial through the use of the Invoke and BeginInvoke methods

implemented by the Control base class.

Both methods take a delegate (or an equivalent anonymous method or lambda expression) and

invoke the specified method on the control using the correct thread. Invoke executes the delegate



354



www.it-ebooks.info



CHAPTER 7 ■ WINDOWS FORMS



synchronously and BeginInvoke executes the delegate asynchronously. To complete an asynchronous

operation initiated using BeginInvoke, you call the Control.EndInvoke method. The BeginInvoke and

EndInvoke methods make up a common asynchronous execution pattern known as the Classic Async

pattern. The details of this pattern and the options you have available for handling method completion

are discussed in recipe 4-2.



The Code

The following example shows how to update a Windows Forms control from multiple threads. The

example uses two timers that fire at differing intervals to change the color of a Button control between

red and green. The code shows how to use both an anonymous method and a lambda expression with

the Invoke call. Both approaches use System.Action, a delegate type that can encapsulate any method

that returns void and takes no arguments.

using

using

using

using

using

using

using



System;

System.Collections.Generic;

System.ComponentModel;

System.Data;

System.Drawing;

System.Text;

System.Windows.Forms;



namespace Apress.VisualCSharpRecipes.Chapter07

{

public partial class Recipe07_19 : Form

{

// Declare timers that change the button color.

System.Timers.Timer greenTimer;

System.Timers.Timer redTimer;

public Recipe07_19()

{

// Initialization code is designer generated and contained

// in a separate file named Recipe07-19.Designer.cs.

InitializeComponent();

// Create autoreset timers that fire at varying intervals

// to change the color of the button on the form.

greenTimer = new System.Timers.Timer(3000);

greenTimer.Elapsed +=

new System.Timers.ElapsedEventHandler(greenTimer_Elapsed);

greenTimer.Start();

redTimer = new System.Timers.Timer(5000);

redTimer.Elapsed +=

new System.Timers.ElapsedEventHandler(redTimer_Elapsed);

redTimer.Start();

}



355



www.it-ebooks.info



Tài liệu bạn tìm kiếm đã sẵn sàng tải về

7-18. Use a Drag-and-Drop Operation

Tải bản đầy đủ ngay(0 tr)

×