How to Design Controls in SharpDevelop

in #utopian-io7 years ago (edited)

I add rollover images to my panel and explain how to debug a user control from inside SharpDevelop. SharpDevelop is a free IDE for CSharp. This IDE is open-source and can be downloaded from here.

<p dir="auto">In this tutorial I'll put the finishing touches on the control to improve its appearance and give it extra design time features. I've been programming a custom control to implement a collapsible panel. This enables me to drop other controls onto it at design time just like a regular panel. However, it also has a special 'control button' which can be clicked in order to collapse the panel along with all the controls it contains out of sight. <p dir="auto"><img src="https://images.hive.blog/768x0/https://res.cloudinary.com/hpiynhbhq/image/upload/v1515485340/rqhhl9b9b6rvpzrf7dhi.png" alt="image.png" srcset="https://images.hive.blog/768x0/https://res.cloudinary.com/hpiynhbhq/image/upload/v1515485340/rqhhl9b9b6rvpzrf7dhi.png 1x, https://images.hive.blog/1536x0/https://res.cloudinary.com/hpiynhbhq/image/upload/v1515485340/rqhhl9b9b6rvpzrf7dhi.png 2x" /> <p dir="auto">Before we get down to the business of adding new features, there's one existing feature that has to be given a slight makeover. After using my control a few times, I noticed that its button seemed oddly prominent when the panel was in the collapsed state. In particular, when the focus was on some other control, the control button appeared to be surrounded by a thick border. After some thought, I realised that this was due to the fact that, when collapsed, the panel's border surrounded that of the button. I therefore decided that I would need to recode the control to turn the panel's border off when collapsed and turn it on again when expanded. This has been done in the timer's tick event-handler, 'timer1_Elapsed()', which you'll find in the 'CollapseControl.cs' unit of the TestCtrl2.sln solution. This sets the panel's BorderStyle property to 'BorderStyle.None', when collapsed and to '_defaultBorderStyle' when expanded. Here _defaultBorderStyle is a variable which stores the BorderStyle property at the time the control first becomes visible. This is done in the CollapsiblePanel_VisibleChanged() method. This same method also turns off the panel border if the panel is collapsed initially. <p dir="auto">One consequence of removing the panel's border when collapsed is that we no longer need to calculate a 'padding' value to take account of the width of the pixels used in the panel's border when collapsed. For that reason, our CollapsedHeight property now returns the height of the button with no account taken of the panel. <h3>How to Create Rollover Buttons <p dir="auto">Up to now, the control button on our panel has been of the plain text-only variety. You might prefer to have a graphic button – either one which displays a single graphic image or one that has 'rollover' behaviour, which changes the image when the mouse passes over it. Rollover buttons are commonplace in web pages. With a little effort, similar behaviour can be added to the control button on our panel. We created a standalone rollover button control in a previous C# Workshop, so we can adapt the code from that in order to provide rollover behaviour for the button in our CollapsiblePanel control. <p dir="auto">First, let's take a look at the original rollover button control. We've included the RolloverButton project in the TestCtrl2.sln solution long with the TestAppButton project, which contains three RolloverButton controls. In order to run this application, select the TestAppButton branch in the 'Solution Explorer' panel, right-click and either select 'Debug', 'Start New Instance' to run it once or 'Set As Startup Project' to run it as the default project whenever you press [F5]. As you can see, each of the three buttons on this form has an 'Up', a 'Down' and an 'Over' state. <h3>Adding Image Properties <p dir="auto">To understand how this works, turn to the Design page of UserControl1.cs. Note the imageList control at the bottom of the workspace. Select this and click the ellipsis button alongside its Images property. This displays the Image Collection Editor. In this you will see that three bitmaps have been loaded with indexes from 0 to 2. These bitmaps have previously been created in a graphics application and have been loaded into the imageList using the 'Add' Button of the Collection Editor. Close the editor and turn to the code unit of UserControl1.cs. <p dir="auto">Note that we have added a 'Roller Images' category which has the properties, 'BtnUp', 'BtnDown' and 'BtnOver'. These are used to get or set the bitmaps from index '' to '2' in the imageList. When a new bitmap is specified, it's added at the appropriate index to the imageList. The default image, BtnUp, is also placed in the background image of the control: <pre><code>if (imageList1.Images.Count > 0) { imageList1.Images[0] = value; this.BackgroundImage = value; } <p dir="auto">When you create a browsable image property, you'll be able to load new images from disk with the help of the Properties panel. To see this, view the Design page of Form1.cs in the TestAppButton project. Select one of the controls and click the ellipsis button next to one of the properties in the RollOver Images category. This displays a dialog which you can use to load new images. We've already done this to the first and third controls on this form. <h3>How to Create A Rollover Control Button <p dir="auto">We have taken the features of our standalone RolloverButton control and adapted them for use with the CollapsiblePanel control. The Up, Down and Over states have been given their own properties, grouped beneath a new category, 'Control Button Images'. The BtnUp property has been renamed to 'BtnDefault', simply so it appears at the top of the category group when sorted alphabetically. Note that an additional test for null values has been added to the set accessors. This is to ensure that an exception is not produced if a null value is passed. <p dir="auto">We've also added an assignment statement to the constructor method, CollapsiblePanel(), to ensure that the default image is displayed even in the form designer. It may seem odd that we need to program design-time behaviour in our code. It is tempting to think that the control's code is only executed at runtime. In fact, the control is 'run' even in the designer. Obviously, the behaviour of a control at runtime and design time is different (see the box-out below). Even so, you must bear in mind that the controls in the design environment are 'active' and may execute some of your code. <h3>Stretching The Images <p dir="auto">By default, any graphic that's assigned to the BackgroundImage property is tiled onto the control. Often you might prefer the image to be stretched to fill the entire control. You would think that we would only need to assign the button's Size property to the existing BackgroundImage's Size property in order to make the image fill the button. Unfortunately, if you try to do this, the compiler refuses to do its job, as the Size property is read-only. There's a sneaky way around this problem, however. When you create a bitmap object, you can specify a size as the second argument to its constructor. A bitmap can be assigned to an image. So all we need to do is to create a new bitmap object from the button's BackgroundImage, giving it the size of the button. Then, we assign this bitmap to the button's BackgroundImage: <pre><code>Bitmap myBitmap = new Bitmap(img, btn.Size); btn.BackgroundImage = (Image) myBitmap; <p dir="auto">The StretchImageToBtn() method is called in CollapsiblePanel_VisibleChanged() to display the image stretched or tiled on start-up. It's also called by the three mouse event-handlers that deal with the button's mouse 'Enter', 'Leave', 'Down' and 'Up' events. For example, this is the code in RollBtnControl_MouseDown(): <pre><code>if (ShowImages) { StretchImageToBtn( this.BtnDown, CtrlBtn, StretchImage); } <p dir="auto">Here, the value of the first argument is the image returned by the BtnDown property. The second argument is the button whose BackgroundImage is to be set and the third argument is the Boolean value returned by the StretchImage property which has been set by the user via the Properties panel. Turning off images Just because the button can now display images, you may not want it to. If you look at the code fragment above, you will see that it includes this test before it calls the code to display an image: <pre><code>if (ShowImages) <p dir="auto">Here, 'ShowImages' is the name of another custom property. It's a Boolean property, which the user can set at design time. When it's 'True', the BackgroundImage is drawn on the button, when it's 'False' the BackgroundImage is set to null. Before any attempt is made to draw the image the value of ShowImages is tested and only if it's true is the image drawn. <p dir="auto">That brings us neatly to the end of this project. We now have a custom collapsible panel onto which other controls can be dropped. The speed and smoothness of the scrolling can be adjusted by setting properties and the appearance, font, colour and background image can all be customised at design time. There are, of course, many features that you could add, but even as it stands our CollapsiblePanel control makes a useful alternative to the ubiquitous tab. <h3>Adding Design Time Features <p dir="auto">Use this simple trick to make your control behave itself in your IDE's form designer. <p dir="auto">As we've pointed out, the controls that you place onto a form in the design workspace aren't just static shapes. They are, in fact, active, running objects. It is true that most of the behaviour that you code into a control is intended for runtime only. The obvious exceptions are the browsable properties (and possibly events too). In our CollapsiblePanel control, for instance, we have a number of properties which change the appearance of the panel and its control button at design time as well as runtime. Of course, it is not always desirable that a control behaves in precisely the same way at both runtime and design time. For example, you might have a property that executes some time-consuming calculations or graphics operations. It's, in fact, pretty simple to code different behaviour for the two modes. You can see an example of this in our Expand property: <pre><code>if (this.DesignMode) CtrlBtn.Text = “This control is expanded in the designer!”; else CtrlBtn.Text = BtnTextExpanded; <p dir="auto">Each .NET component has a Boolean DesignMode property which is 'True' if the component is currently running in the form designer and 'False', if it is running in an application. When you set the Expand property in the Properties panel, the control button will display "This control is expanded in the designer!". When it's expanded and contracted in a running application, it displays the string specified by the BtnTextExpanded property. While this is a fairly trivial example, the same technique can equally be used to add all kinds of design time features. <p dir="auto"><br /><hr /><em>Posted on <a href="https://utopian.io/utopian-io/@elissa/our-control-gets-graphical-in-sharpdevelop" target="_blank" rel="noreferrer noopener" title="This link will take you away from hive.blog" class="external_link">Utopian.io - Rewarding Open Source Contributors<hr /><p>
Sort:  

Your contribution cannot be approved yet. See the Utopian Rules. Please edit your contribution to reapply for approval.

  • Explain what the software does in brief.
  • Explain the purpose of this tutorial in brief.
  • Change the title to reflect what it actually is about.
  • Improve formatting by arranging information into headings and sub headings.
  • Give a step by step tutorial with each step supported by images.

You may edit your post here, as shown below:

You can contact us on Discord.
[utopian-moderator]

Edited. I have added more details. Please check again.

Thank you for the contribution. It has been approved.

You can contact us on Discord.
[utopian-moderator]

Hey @elissa I am @utopian-io. I have just upvoted you!

Achievements

  • You have less than 500 followers. Just gave you a gift to help you succeed!
  • Seems like you contribute quite often. AMAZING!

Suggestions

  • Contribute more often to get higher and higher rewards. I wish to see you often!
  • Work on your followers to increase the votes/rewards. I follow what humans do and my vote is mainly based on that. Good luck!

Get Noticed!

  • Did you know project owners can manually vote with their own voting power or by voting power delegated to their projects? Ask the project owner to review your contributions!

Community-Driven Witness!

I am the first and only Steem Community-Driven Witness. Participate on Discord. Lets GROW TOGETHER!

mooncryption-utopian-witness-gif

Up-vote this comment to grow my power and help Open Source contributions like this one. Want to chat? Join me on Discord https://discord.gg/Pc8HG9x

thanks very much for this tutorial