In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-02-23 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/02 Report--
This article is about how C # implements the development of custom controls. The editor thinks it is very practical, so share it with you as a reference and follow the editor to have a look.
Brief introduction
Smart Device Extensions for Microsoft Visual Studio .NET (SDE) provides a nice basic control that can be used in applications. Unfortunately, embedded device applications are so extensive that developers will almost certainly lack the right controls in some places, and there are basically two options: redesign the application to use the available controls, or adopt your own custom controls.
The * versions of SDE do not support design-time custom controls, which means that in order to use them, you must manually write code to put them into the form and set their size and properties. It requires very little extra work and only requires you to accept the fact that there is no Form Design Support available for custom controls.
problem
Recently, I have been creating class libraries for Visual Studio .NET to wrap up a lot of hardware functionality. By using a class library that does all the P/Invoking and resource management for them, it is much easier for managed code developers to access airborne microcontrollers and Microsoft Windows CE ports. I developed the class library of Ibank O for Graphics Master devices to provide the ability to read and write pins on two separate heads.
I need a test and sample application that allows the user to easily set or read the digital Ihand O status and the analog ID O status through the appropriate graphical interface. I want something to look like a connector on a schematic or a physical plug on a board. Because I have to deal with two connectors of different physical sizes, I need multiple controls, or * * is a control that can define the size. Obviously, I don't have the controls I want in SDE's toolbox.
I could have used a lot of Label, CheckBox, PictureBox, and TextBox, but I think this alternative looks ugly. Let's try to write our own controls.
C# Custom Control object Model
The task is to determine the entire object model. What kind of components do we need, how will they fit together, how do they interact with each other, and how do they interact with their environment?
Figure 1. My Connector Control concept
We will create connectors to contain a collection of pins of variable size so that connectors of different sizes can be connected. Each pin must have an identification label that can be placed on the left or right side of the displayed "pin" (depending on whether it is an even or odd pin). Each pin can also be a digital or analog Istroke O, so each pin needs to have a separate value ranging from zero to 0xFFFF. * can recognize the type and value of each pin at a glance, so you will need to use some colors. Of course, not all pins on the connector can be used for Ipicuro, so we need to be able to disable some of them. In addition, we want the pins to be interactive so that when we turn on a pin, it can do something, such as changing the state.
Figure 1 is a good model of what a control looks like on the screen.
Based on these requirements, we propose an object model as shown in figure 2.
Figure 2. Control object model
The overall idea is that we will have a Connector base class and then derive several other custom Connector classes from it. Connector will contain a Pins class that simply exposes the ListArray of the Pin object by deriving from CollectionBase and using an indexer.
C# Custom controls: implementing Pin objects
Because the backbone of this control is a Pin object, let's introduce it first. The Pin object handles most of the display properties of the control and handles user interaction. Once we can successfully create, display, and interact with individual pins on the form, it is very easy to build a connector to combine them.
The Pin object has four properties that must be set when it is created. The default constructor sets each of them, but other constructors can also be used to allow the creator to pass non-default values.
The most important attribute is Alignment. This property determines the location of the text and pins when the object is drawn, but more importantly, when you set the property, it creates and places the rectangle used to draw the pins and text. The use of these rectangles will be discussed later in the interpretation of OnDraw.
Listing 1 shows the code for the basic constructor and the Alignment property. Constants are used for the offsets and borders defined around the pin subcomponent, but these constants can easily become other properties of the control.
Listing 1. Pin constructor and Alignment attribute
Public Pin () {showValue = false; pinValue = 0; type = PinType.Digital; Alignment = PinAlignment.PinOnRight;} public PinAlignment Alignment {/ / determines where the pin rectangle is placed set {align = value If (value = = PinAlignment.PinOnRight) {this.pinBorder = new Rectangle (this.ClientRectangle.Width-(pinSize.Width + 10), 1, pinSize.Width + 9, this.ClientRectangle.Height-2) This.pinBounds = new Rectangle (this.ClientRectangle.Width-(pinSize.Width + 5), ((this.ClientRectangle.Height-pinSize.Height) / 2) + 1, pinSize.Width, pinSize.Height) This.textBounds = new Rectangle (5,5, this.ClientRectangle.Width-(pinSize.Width + 10), 20);} else {this.pinBorder = new Rectangle (1,1, pinSize.Width + 9, this.ClientRectangle.Height-2) This.pinBounds = new Rectangle (6, this.ClientRectangle.Height-(pinSize.Height + 4), pinSize.Width, pinSize.Height); this.textBounds = new Rectangle (pinSize.Width + 10,5, this.ClientRectangle.Width-(pinSize.Width + 10), 20) } this.Invalidate ();} get {return align;}}
Since the Pin object does not provide good user interaction or customizability, the core function of the pin is the drawing routine we will rewrite, OnDraw, so that we can draw the entire pin.
Each pin will draw three parts: the pin itself will be a circle (unless it is Pin 1, then it will be a square), and we will draw a border rectangle around the pin, and then leave an area on the left or right side of the pin to draw the text of the pin.
To draw the pin, we first determine the color used by the circle that represents the actual pin. If the pin is disabled, its color is gray. If enabled, determine what type it is. The analog pin will be green, while the digital pin will vary depending on the situation, blue if low (off) and orange if high (on).
Next, we use FillEllipse to draw all the actual pins, except in the case of PinNumber=1, when we use FillRectangle to draw pins. By drawing in a rectangle (pinBounds) instead of on the boundary of the control, we can set the position of the pin (left or right) when creating the pin, and from this point on, we can draw without paying attention to the position of the pin.
Next we draw the label, which will be the text of the pin or the value of the pin, depending on the ShowValue attribute.
We use a similar strategy to draw text as when drawing pins, but this time we have to calculate the horizontal and vertical offsets, because in the Microsoft .NET compression framework, the DrawText method does not allow TextAlign parameters.
Finally, we clean up the Brush object we used manually by calling the Dispose method.
Listing 2 shows the complete OnDraw routine.
Listing 2. OnDraw () method
Protected override void OnPaint (PaintEventArgs pe) {Brush b; / / determine the Pin color if (this.Enabled) {if (type = = PinType.Digital) {/ / digital pins have different on/off color b = new System.Drawing.SolidBrush (this.Value = = 0? (digitalOffColor): (digitalOnColor);} else {/ / analog pin b = new System.Drawing.SolidBrush (analogColor);}} else {/ / disabled pin b = new System.Drawing.SolidBrush (disabledColor);} / / draw the pin if (this.PinNumber = = 1) pe.Graphics.FillRectangle (b, pinBounds); else pe.Graphics.FillEllipse (b, pinBounds) / / draw a border Rectangle around the pin pe.Graphics.DrawRectangle (new Pen (Color.Black), pinBorder); / / draw the text centered in the text bound string drawstring; / / are we showing the Text or Value? If (showValue) drawstring = Convert.ToString (this.Value); else drawstring = this.Text; / / determine the actual string size SizeF fs = pe.Graphics.MeasureString (drawstring, new Font (FontFamily.GenericMonospace, 8f, FontStyle.Regular)) / / draw the string pe.Graphics.DrawString (drawstring, new Font (FontFamily.GenericMonospace, 8f, FontStyle.Regular), new SolidBrush ((showValue? AnalogColor: Color.Black), textBounds.X + (textBounds.Width-fs.ToSize (). Width) / 2, textBounds.Y + (textBounds.Height-fs.ToSize (). Height) / 2); / / clean up the Brush b.Dispose ();}}
The * * step in building the Pin class is to add a Click handler. For our Pin class, we will use a custom EventArg so that the text and number of the pin can be passed to the event handler. To create a custom EventArg, we simply create a class that derives from the EventArgs class:
Public class PinClickEventArgs: EventArgs {/ / a PinClick passes the PinNumber and the Pin's Text public int number; public string text; public PinClickEventArgs (int PinNumber, string PinText) {number = PinNumber; text = PinText;}}
Next, we add a delegate to the namespace:
Public delegate void PinClickHandler (Pin source, PinClickEventArgs args)
Now we need to add code to determine when the click occurs and then raise the event. For our Pin class, it is a logical click when the MouseDown and MouseUp events occur inside the border rectangle of the pin-so that if the user clicks on the text part of the pin, the Click event is not triggered, but if the click represents the area of the actual pin, the event is triggered.
First, we need a public PinClickHandler event, which is defined as follows:
Public event PinClickHandler PinClick
We also need a private Boolean variable that we will set when the MouseDown event occurs to indicate that we are in the process of clicking. Then, we examine the variable of the MouseUp event to determine whether the events occur in a sequential order:
Bool midClick
Next, we need to add two event handlers for MouseDown and MouseUp, as shown in listing 3.
Listing 3. Event handlers for implementing PinClick events
Private void PinMouseDown (object sender, MouseEventArgs e) {if (! this.Enabled) return; / / if the user clicked in the "pin" rectangle, start a click process midClick = pinBorder.Contains (e.X, e.Y) } private void PinMouseUp (object sender, MouseEventArgs e) {/ / if we had a mousedown and then up inside the "pin" rectangle, / / fire a click if ((midClick) & & (pinBorder.Contains (e.X, e.Y)) {if (PinClick! = null) PinClick (this, new PinClickEventArgs (this.PinNumber, this.Text)) }}
*, we need to implement an event handler for each pin. The basic constructor of the pin is a good place to add these hooks, which we can do by adding the following code directly to the constructor: view plaincopy to clipboardprint?this.MouseDown + = new MouseEventHandler (PinMouseDown); this.MouseUp + = new MouseEventHandler (PinMouseUp); this.MouseDown + = new MouseEventHandler (PinMouseDown)
This.MouseUp + = new MouseEventHandler (PinMouseUp); implement the Pins class once you have the Pin class, you can create a Pins class that derives from CollectionBase. The purpose of this class is to provide indexers so that we can easily add, remove, and manipulate Pin classes within the collection.
Listing 4. Pins class
Public class Pins: CollectionBase {public void Add (Pin PinToAdd) {List.Add (PinToAdd);} public void Remove (Pin PinToRemove) {List.Remove (PinToRemove);} / / Indexer for Pins public Pin this [byte Index] {get {return (Pin) List [Index];} set {List [Index] = value }} public Pins () {}}
Implementing the Connector class now that we have the Pins class, we need to build the Connector class, which will be a simple wrapper class that contains the Pins class and marshals the PinClick event between each pin and the connector container, and has a constructor that represents the number of pins on the connector. Listing 5 shows the complete Connector class.
Listing 5. Connector class
Public class Connector: System.Windows.Forms.Control {public event PinClickHandler PinClick; protected Pins pins; byte pincount; public Connector (byte TotalPins) {pins = new Pins (); pincount = TotalPins; InitializeComponent ();} private void InitializeComponent () {for (int I = 0; I < pincount) Pin +) {Pin p = new Pin (PinType.Digital, (PinAlignment) ((I + 1)% 2), 0); p.PinClick + = new PinClickHandler (OnPinClick); p.PinNumber = I + 1; p.Text = Convert.ToString (I); p.Top = (I / 2) * p.Height; p.Left = (I% 2) * p.Width This.Pins.Add (p); this.Controls.Add (p);} this.Width = Pins [0] .width * 2; this.Height = Pins [0] .height * this.Pins.Count / 2;} public Pins Pins {set {pins = value;} get {return pins }} private void OnPinClick (Pin sender, PinClickEventArgs e) {/ / pass on the event if (PinClick! = null) {PinClick (sender, e); if (sender.Type = = PinType.Digital) sender.Value = sender.Value = = 0? 1: 0; else sender.DisplayValue =! sender.DisplayValue } protected override void Dispose (bool disposing) {base.Dispose (disposing);}}
Connector's InitializeComponent method is where all the included Pin classes are created and added to the connector's control, and where the connector itself is resized. InitializeComponent is also the method eventually used by Form Designer to display our connectors.
C# custom controls: building custom connectors
The Connector class itself is simple and does not modify any default pin settings. However, we can now build a custom connector by deriving a new class from the Connector class and modify individual pins (for example, to make some pins analog or disable them).
In the sample application, I created two connectors for Applied Data Systems's Graphics Master board, one for J2 and one for J7. The constructor sets the type of pin and the text of the pin based on the connector. Figure 2 is a screenshot of a sample application with J2 and J7 on the form.
Figure 3. Forms that use two Connector objects
Thank you for reading! This is the end of this article on "how to realize the development of custom controls in C#". I hope the above content can be of some help to you, so that you can learn more knowledge. If you think the article is good, you can share it out for more people to see!
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.