How do I click a usercontrols child in designer? - c#

I'm having a bit of trouble with creating one of my custom controls.
What I've got is a listbox within a usercontrol, and I need to be able to click on the lists items while still in the designer. This would make it act much like the tabcontrol.
I haven't dealt much with usercontrols but I've tried catching some overide events without success.
protected override void OnClick(EventArgs e)
{
if (DesignMode)
{
InvokeOnClick(listBox1, e);
}
base.OnClick(e);
}
I haven't been able to find anything on the web.. Any ideas on how I can do this?
Thanks in advance =)

#Bradley: thanks for pointing me in the right direction
You will need to write a ControlDesigner class, then use it in a [Designer( ... )] attribute on your UserControl.
See the example here:
http://msdn.microsoft.com/en-us/library/sycctd1z(v=VS.90).aspx
For the actual click:
http://msdn.microsoft.com/en-us/library/system.windows.forms.design.controldesigner.gethittest(v=VS.90).aspx
The ControlDesigner has a protected bool GetHitTest(Point point) method - you can implement this in your ControlDesigner and return true when you want your control to handle a click, based on the click's location on the screen.

I found this link that says you need to implement a custom designer to get the desired behavior, and explains how to make it happen.
http://social.msdn.microsoft.com/Forums/pl-PL/winforms/thread/0b6ed0cb-907c-4733-b245-ae5d0b0e6606

You may be able to get away with catching the MouseDown event in the custom control and forwarding it on to the inner control. I'm not sure how MouseDown behaves in design mode though.

Related

VCL's CustomControl equivalent in Windows Forms

Delphi's VCL has a very useful class, CustomControl. This class is a direct base class of Control, which is equivalent to C# WF's UserControl.
For those, who are not familiar with VCL, CustomControl differs very little from Control; the main difference is that most of properties are protected; when implementing the new control, developer may decide, which ones does he want to publish and which ones shall remain hidden.
I'm developing my own control for Windows Forms and I want to hide some properties and events. For instance, I don't want to expose the MouseDown event - instead I allow capturing clicking on control's elements.
Is there an equivalent of VCL's CustomControl in Windows Forms? If not, how can I hide unwanted public properties and events in my control?
In response to answers:
This is not a matter of security, but rather a matter of code elegance. In Delphi I can derive from CustomControl, leave the OnMouseDown event protected (as in C#'s protected) and say to the control's user:
You cannot use OnMouseDown, because there is none. If you want to react to user clicking on control, simply use OnElementClicked - you'll even get detailed information about which element was clicked and what was its state.
I may disable calling the MouseDown event as Hans Passant suggested, but then I would have to include the following in the control's user's manual:
Please do not use the MouseDown event, because I've overridden the OnMouseDown method, such that it won't call the MouseDown event. This is because the control's logic is designed in such way, that you should use OnElementClicked rather than OnMouseDown. Please don't criticize the control because of MouseDown not working. Please don't report it as a bug, because it is by design. Please don't post messages in forums or create blog entries explaining how to fix the MouseDown problem by inheriting the class and manually calling the MouseDown event, because it would break the control's logic. Pleas don't... damnit, told you so!
If someone actually inherits from my control - I assume then, that he knows, what he's doing (also because one would then gain access to my control's internal logic as well). But if someone just uses my control, I would give him only these properties, events and methods, that I'm sure will work as designed.
I hope it explains my motives :)
There's a fundamental difference between hiding, what you asked for, and making it inaccessible, what I assume Delphi does. Hiding is simple, just repeat the declaration and apply attributes:
using System;
using System.ComponentModel;
using System.Windows.Forms;
class MyControl : Control {
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
private new event MouseEventHandler MouseDown;
}
Which prevents the event from being displayed in the Properties window, it won't show up in the IntelliSense dropdown and generates a compile error when he tries to assign the event in code anyway.
It is however not an absolute guarantee that the client programmer couldn't work around the restriction anyway. By casting or overriding your class for example. But the ultimate backdoor is implementing the IMessageFilter interface, nothing you can do about that. So this ought to be good enough if elegance is the goal.

Winforms Designer: How to disable my usercontrol from being a container?

I have a relatively simple setup. I have a custom usercontrol that has a bunch of components on it, some text boxes, and a listview.
In the designer, I can drag and drop other controls into my usercontrol, and it adds them to the usercontrol instance. I don't want this.
How can I explicitly say "Don't allow additional controls to be added to this usercontrol?"
That's not the way it works. When you drop your user control on a form then adding controls to it isn't supported. That requires a special designer, this answer shows what is required. Maybe it looks like the controls get added but they merely overlap your user control. Their parent is still the form.
If a programmer opens your user control class itself in the designer then, sure, he can add controls as he pleases. The only way to stop that is to not ship the source code and use the sealed keyword to prevent deriving from it.
You could create a boolean property MyContainer.DisableAddControls or something.
If your MyContainer.Controls.Add(..) is overridden, then you can throw some custom exception in that Add() method as follows:
if(DisableAddControls)
{
throw new DisableAddControlsException();
}
If you are inheriting that method straight from ContainerControl, then you can handle the ControlAdded event and throw the exception there.
myContainer.ControlAdded += myContainerControlAdded;
private void Control_Added(object sender, System.Windows.Forms.ControlEventArgs e)
{
if(DisableAddControls)
{
throw new DisableAddControlsException();
}
}
On second thought, this won't throw out your designer at design time... nevermind.

Interactive Design-Time User Control

I apologise if the title was confusing, it took me nearly 5 minutes to finally think of a title for this one...
Okay, you know how in Visual Studio Express when you add a TabControl to the Form, and you can click on the right-arrow on the top right of the TabControl and it will add a new TabPage, or remove one?
Well, I'm creating a User Control where I need people to be able to switch between Panels (my user control is made up of several Panels). I know this is possible as I've used a Ribbon Control in the past and you could add new buttons etc in the Designer View.
Can somebody please provide any suggestions/advice on how I might go about acheiving this?
Thank you
If I understand your question correctly, you're talking about smart tags.
The process is a little bit involved, so I'm not going to try to post a complete sample. Instead, I'll refer you to this tutorial on the subject. To make a long story short, you have to create a custom designer, and register one or more custom actions. You can use this to create a combo box listing the available panels and switch between them when the selected item is changed.
(Note - the term "smart tags" has two distinct meanings in Visual Studio - I'm specifically talking about the visual designer smart tags, not smart tags in the code editor).
When you make a control that is inherited from Control, you have to make use of a couple of properties such as IsDesignMode, you can then construct event handlers especially for within Design Mode:
if (IsDesignMode){
// Handle the interactivity in Design mode, such as changing a property on the
// Properties toolbox
}
Suppose the control has an event such as MouseClick, you can do this:
private void control_MouseClick(object sender, MouseEventArgs e){
if (IsDesignMode){
// Do something here depending on the Click event within the Designer
}else{
// This is at run-time...
}
}
Another I can think of is 'ShouldSerialize' followed by a publicly accessible property in order to persist the property to the designer-generated code, suppose for example a Control has a boolean property Foo
public bool Foo{
get{ return this._foo; }
set{ if (this._foo != value){
this._foo = value;
}
}
}
public bool ShouldSerializeFoo(){
return true; // The property will be persisted in the designer-generated code
// Check in Form.Designer.cs...
}
If ShouldSerializeFoo returned false, no property is persisted, its the opposite when true, it will be buried within the Form.Designer.cs code...
Hope this helps,
Best regards,
Tom.

How to inherit base Textbox to provide colored borders

I have a winform app that we use in house. It has many individual controls on each of it's 25 "pages"(usercontrols). Our user base prefers very technicolor apps...they want a TextBox to be outlined Blue if it is a required field (color should go away if data entered). They want a TextBox to change to outlined Green if data has been changed in it to remind them to save. They want a currently highlighted TextBox to be outlined RedOrange.
I have been trying to come at this from many different angles (some of you have probably seen similar posts by me lately). Non of them work... So one way I KNOW will work is to register the paint event for every control and check for a "required" tag for the required portion. The OnFocus for the current field portion and finally the Validate event for the data changed portion.
I know this is not the best way or at least I STRONGLY suspect it isn't but I am out of time, nearly, and nearing my point of frustration. That being said, will that DESTROY my app's responsiveness? Is there a better way? Can I override the base control to color on different premises so that I don't have to go to each of the 100+ controls?
Any idea would be welcome because I am between my stupid Paint_Event idea and rewriting all the controls in WPF... :)
I will be rewarding a solution that works for me and that I can implement shortly with a Bounty.
I am so sick of colors...
Here is my attempt based on suggestions.
public class MyTextBox : TextBox
{
private bool _isRequired;
public bool isRequired
{
get
{
return _isRequired;
}
set
{
_isRequired = value;
}
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
if (isRequired && base.Text.Equals(string.Empty))
{
HighlightControl(e.Graphics);
}
}
private void HighlightControl(Graphics graphics)
{
ControlPaint.DrawBorder(
graphics,
this.ClientRectangle,
Properties.Settings.Default.RequiredFieldColor,
Properties.Settings.Default.BorderWidth,
Properties.Settings.Default.BorderStyle,
Properties.Settings.Default.RequiredFieldColor,
Properties.Settings.Default.BorderWidth,
Properties.Settings.Default.BorderStyle,
Properties.Settings.Default.RequiredFieldColor,
Properties.Settings.Default.BorderWidth,
Properties.Settings.Default.BorderStyle,
Properties.Settings.Default.RequiredFieldColor,
Properties.Settings.Default.BorderWidth,
Properties.Settings.Default.BorderStyle);
}
}
I don't know the particulars of your app, but you could derive your own control from the base TextBox and let it handle much of this for you. Some thoughts:
Give it a bool Required property and some internal logic to color accordingly.
Have the textbox respond to its own
events - when text is entered, it can
do the right thing - change colors or
whatever is appropriate.
Provide your derived control with
properties to set the colors that get
used for each condition, then you can
switch them easily when the users
decide they want pink rather than
green.
You can utilize the focus events to "know" whether your TextBox (this is the one control you mentioned, so I'll assume this is the main control used here) has focus or lost it and the text change events can be used to drive all the color changes to the control.
You can certainly wire up all the
text boxes to control the
Apply/OK/whatever buttons to
determine if the buttons should be
enabled, assuming you have an Apply button or something like that which stores the data on click. There are a number of ways to communicate this. It's easy enough to iterate through the controls and ask their state.
Seems like this would work just fine.
What have you tried? You didn't really mention what you'd tried that didn't work.
You've got a problem, TextBox is, erm, special. Windows Forms leaves all painting to the native Windows EDITBOX control, the Paint event won't be raised. That can be fixed by setting the UserPaint control style to true:
using System;
using System.Drawing;
using System.Windows.Forms;
class MyTextBox : TextBox {
public MyTextBox() {
this.SetStyle(ControlStyles.UserPaint, true);
}
protected override void OnPaint(PaintEventArgs e) {
base.OnPaint(e);
// Paint something
//...
}
}
Copy and paste this into a new class, compile and drop the new control from the top of the toolbox. Try it out, you'll be quite disappointed. What you see is the result of close to 20 years of appcompat hacks on a control that dates back to Windows version 2. One of the grave crimes that EDITBOX commits is painting itself without generating a WM_PAINT message. That was important way back when Windows had to run on a 386SUX, keeping it compatible with old programs prevented Microsoft from fixing its behavior.
No happy answers here, you'll have to give up on the idea of customizing the border. What you can do is give the control a distinct BackColor when it has the focus. For example:
class MyTextBox : TextBox {
Color mBackColor;
protected override void OnEnter(EventArgs e) {
mBackColor = base.BackColor;
base.BackColor = Color.AliceBlue;
base.OnEnter(e);
}
protected override void OnLeave(EventArgs e) {
base.BackColor = mBackColor;
base.OnLeave(e);
}
}
You can inherit from base control classes and add your own drawing logic. That won't be very expensive performance-wise, but, if your app is of significant size, you'll have to replace each occurence of standard TextBox with your own implementation.

ASP.NET UserControl's and DefaultEvent

Outline
OK, I have Google'd this and already expecting a big fat NO!! But I thought I should ask since I know sometimes there can be the odd little gem of knowledge lurking around in peoples heads ^_^
I am working my way through some excercises in a book for study, and this particular exercise is User Controls. I have cobbled together a control and would like to set the DefaultEvent for it (having done this for previous controls) so when I double-click it, the default event created is whatever I specify it to be.
NOTE: This is a standard User Control (.ascx), NOT a custom rendered control.
Current Code
Here is the class & event definition:
[System.ComponentModel.DefaultEvent("OKClicked")]
public partial class AddressBox : System.Web.UI.UserControl
{
public event EventHandler OKClicked;
Current Result
Now, when I double click the the control when it is on a ASPX page, the following is created:
protected void AddressBox1_Load(object sender, EventArgs e)
{
}
Not quite what I was expecting! So, my question:
Is it possible to define a DefaultEvent for a UserControl? Is it a hack? If it's [not] supported, is there a reason?
Side Note: How do we put underscores in code? I cant seem to put and escape char in?
Here is a possible answer, without testing (like martin did).
In reflector, you will see that the DefaultEventAttribute allows itself to be inherited.
In reflector, you see that the UserControl class has it's default event set to the Load event.
So the possible reason is that even though you are decorating your user control with the default event of OKClick, VS might still be thinking that the default event is load, as it's being inherited from UserControl whose default event is Load.
Just a high level guess at what might be happening.
OK, I checked this out, Inheriting from WebControl rather than UserControl.. All worked fine.
Looks like Darren Kopp takes the crown for this one! Thanks for the input!

Categories