NET User Interfaces in Csharp Windows Forms and Custom Controls [Electronic resources] نسخه متنی

اینجــــا یک کتابخانه دیجیتالی است

با بیش از 100000 منبع الکترونیکی رایگان به زبان فارسی ، عربی و انگلیسی

NET User Interfaces in Csharp Windows Forms and Custom Controls [Electronic resources] - نسخه متنی

Matthew MacDonald

| نمايش فراداده ، افزودن یک نقد و بررسی
افزودن به کتابخانه شخصی
ارسال به دوستان
جستجو در متن کتاب
بیشتر
تنظیمات قلم

فونت

اندازه قلم

+ - پیش فرض

حالت نمایش

روز نیمروز شب
جستجو در لغت نامه
بیشتر
لیست موضوعات
توضیحات
افزودن یادداشت جدید




































Interacting with a Control



One interesting and little-known fact about .NET controls is that they provide two different forms of interaction. The first, and less common one, is by creating custom classes and overriding methods.


For example, imagine you have a text box that's designed for numeric entry, and you want to examine every key press to make sure that it corresponds to a number, and not a letter. To perform this type of task, you can create a customized text box, and override the OnKeyPress() method to add this extra verification logic.



public class NumericTextBox : System.Windows.Forms.TextBox
{
protected override void OnKeyPress(KeyPressEventArgs e)
{
base.OnKeyPress(e);
if (!char.IsControl(e.KeyChar) && !char.IsDigit(e.KeyChar))
{
e.Handled = true;
}
}
}


The OnKeyPress() method is invoked automatically by the Windows Forms engine when a key is pressed in a TextBox control. The overridden method in the example above checks to see if the entered character is a number. If it isn't, the Handled flag is set to true, which cancels all further processing, effectively making sure that the character will never end up in the text box.


This design pattern is useful if you use a number of controls with extremely similar behavior. If, on the other hand, you need to fine-tune behavior for distinct, even unique tasks, this approach is extremely poor. For example, consider a button control. You could react to a button click by creating a special class for every button on your application, and giving each button its own overridden OnClick() method. While your program would still be well encapsulated, it would quickly become completely disorganized, swamped by layers of button classes that have little to do with one another.



The View-Mediator Pattern



The approach that .NET encourages circumvents this problem by using events. When you create a form in Visual Studio .NET, a custom class is derived for the form, but all the contained classes are used as is. The event handling logic is inserted as a series of special methods, which are added to the custom form class.


In other words, every form acts as a giant switchboard for all the controls it contains. This type of design pattern, which is so natural to .NET and most Windows development that you might not have even noticed it, is called the View-Mediator pattern. It dictates that one central class organizes each individual window.


Here's the same text box example you saw earlier, rewritten as form-level event handler. The event handler is hooked up in the constructor for the form (although Visual Studio .NET would perform the same task with a dedicated InitializeComponent() method).



public class MainForm : System.Windows.Forms.Form
{
System.Windows.Forms.TextBox txtUserName;
public MainForm()
{
txtUserName = new System.Windows.Forms.TextBox();
txtUserName.Name = "txtUserName";
txtUserName.Location = New System.Drawing.Point(64, 88);
txtUserName.Size = New System.Drawing.Size(200, 20);
txtUserName.TabIndex = 1;
txtUserName.Text = "Enter text here!";
this.Controls.Add(txtUserName);
// Connect event handler.
this.textBox1.KeyPress += new
System.Windows.Forms.KeyPressEventHandler(this.textBox1_KeyPress);
}
private void textBox1_KeyPress(object sender,
System.Windows.Forms.KeyPressEventArgs e)
{
if (!char.IsControl(e.KeyChar) && !char.IsDigit(e.KeyChar))
{
e.Handled = true;
}
}
}


You'll notice that the actual logic for processing the key press is identical, but the way it's integrated into the application is completely different. The form is now responsible for the validation, not the control itself. This is an ideal approach if the form needs to handle the complex validation of multiple different controls. It's a less suitable approach if you need to perform the same type of validation for the same control in different windows, because you'll probably need to copy the code into multiple form-level event handlers.


You should also remember that the point of a switchboard is to route calls to a new destination. In other words, when you create the event handler for a button's Click event, this event handler usually has two purposes:





Forward the command to another object that can handle the task.





Update the display.





Depending on the button, only one of these tasks may be necessary. But the important concept you should realize is that an event handler is generally part of a user interface object-the form switchboard. It's meant to handle user interface tasks, and delegate more complicated operations to other objects.





Smart Controls



So far you have seen two distinct ways to use controls from the .NET class library:





Create an instance of a generic control class "as is." Then, configure its properties.





Define a new class that inherits from a generic control class, and customize this class for your needs. Then, create an object based on this specialized class.





The difference is shown in Figure 2-3.




Figure 2-3: Two ways to interact with controls


Visual Studio .NET uses inheritance (the first method) when you create forms. When you configure controls, however, it inserts them as is, and adds the appropriate logic for modifying their properties (the second method). This is the default approach in .NET, but it is not the only approach.


When Visual Studio .NET adds controls and derives a custom form class, it is making a design decision for you. This decision helps clear out the clutter that would result from creating dozens of custom control classes. However, like all design decisions, it's not always right for all people and in all situations. For example, if you use numerous similar controls (like text boxes that refuse numeric input), you may find yourself duplicating the same code in event handlers all over your program. In this case, you might be better off to step beyond Visual Studio .NET's default behavior, and create customized controls with some additional intelligence.


When you are creating a new application and planning how to program its user interface, one of the most important tasks is deciding where to draw the line between smart controls (custom control classes) and smart switchboards (custom forms with event handling logic). A good decision can save a lot of repetitive work. 9 consider some examples that show how you can add a bit of sense to important controls like the TreeView and ListView. Hopefully, you'll realize that custom controls are not just for redistributing neat user interface elements, but also for building intelligence into parts of a large application, and helping to reduce repetition and enforce consistency across different modules.



Note


This book includes a special chapter about custom controls, which describes how to package them for redistribution, and covers some advanced options. However, unlike most .NET books, I also explore custom control classes throughout. Creating these smart controls is a crucial ingredient in designing a user interface framework, not just an additional topic.






Smart Forms



As explained earlier, every form class in your application is a custom class that derives from System.Windows.Forms. However, you can use multiple layers of form inheritance to centralize and reuse important form functionality. This topic is commonly referred to as visual inheritance (although it's no different than any other type of control class inheritance), and it's described in detail in Figure 2-4 diagrams this relationship.




Figure 2-4: Ordinary forms and visual inheritance


So far, you've explored the basic object-oriented foundation of .NET user interface programming. The remainder of the chapter considers some higher-level architectural topics like encapsulation and three-tier design. These are the best practices you'll want to keep in mind when planning your user interface classes.






/ 142