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!
Related
I Have a Page Containing some controls, this page will be loaded into a ContentControl in a Window.
Now, How can i limit the focus cycle in my Page? I don't want to pass the focus to out of Page after pressing TAB in last item of my page.
As a brief, How Can I determine the next focus control and change it
It's always difficult to fully understand what a question author wants when they don't bother to provide you with more than a few hastily typed lines. However, as far as I understand your problem, it seems that you have some problem with focusing in your WPF Application.
The first thing to do is to direct you to the Focus Overview page on MSDN, where you can find out about the different focus types used in WPF. In particular, please pay attention to the Navigating Focus Programmatically section which discusses the TraversalRequest Class that can help developers to move focus programmatically.
You should also pay careful attention to the KeyboardNavigation section that discusses the KeyboardNavigation Class. This class contains some properties that enable you to define how the Tab key works in various scenarios, so this may be what you're after. It is used like this (from the last linked page on MSDN):
KeyboardNavigation.SetTabNavigation(navigationMenu, KeyboardNavigationMode.Cycle);
For future reference, you will get quicker and more accurate answers if you provide clear questions that include all of your requirements at the time of posting.
Have you tried looking at the FocusLost event - you might possibly be able to just refocus the page control with an event handler.
private void Page_LostFocus(object sender, System.Windows.RoutedEventArgs e)
{
((UIElement)sender).Focus();
}
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.
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.
Maintaining focus across post backs is an apparently difficult task. Searching Google, you will find a ton of people that desire the same thing, but all hook it up differently, and mostly, custom-ly. I would like to avoid a custom implementation, especially if there's a way it's supported by .NET. Only after some very deep searching, did I come across PostBackOptions.TrackFocus, mentioned quietly in another stack overflow post. According to MSDN:
Gets or sets a value indicating whether the postback event should return the page to the current scroll position and return focus to the current control."
Holy crap, this is supported by .NET 4? AWESOME. But we have a ton of custom controls, how does .NET know how to set the focus on a control? I have no idea. Looking a the MSDN documentation for System.Web.UI.Control, there's an interesting method:
public virtual void Focus()
"Use the Focus method to set the initial focus of the Web page to the
control. The page will be opened in the browser with the control
selected."
Alright, clearly overridable. But what is the recommended method of doing so? It returns void. No examples. Unable to find any examples of people overriding this method in their implementations. However, after overriding it and doing nothing more than throwing an exception, it becomes evident that this is not how ASP.NET gets focus on a control that had focus before the post back: it never gets called.
After a ton of debugging using Firebug, I have found that enabling PostBackOptions.TrackFocus works! Sometimes. It is apparent that the focus of a control is only maintained when the control calls the __doPostBack JavaScript method. Other controls that launch a PostBack (when pressing enter inside the control), call WebForm_OnSubmit(), which doesn't update the ASP hidden field __LASTFOCUS. __doPostBack calls WebForm_OnSubmit() after setting the hidden fields.
This is where I'm currently stuck. It's looks as if I need to get everything to call __doPostBack, no matter what. There's very, very little documentation on the use of TrackFocus. So does anyone have any tips from here?
I've been maintaining focus accross postbacks using the method in this article:
(ie: store focus in __LASTFOCUS hidden field on field enter event clientside for all controls)
http://www.codeproject.com/KB/aspnet/MainatinFocusASPNET.aspx
If you've gotten as far as having __LASTFOCUS show up on the page, this should get you most of the rest of the way...
Note: It'd be nice to find a way to keep the extra javascript from bloating __VIEWSTATE for example.
It was working pretty well for me until I figured out that some of my pages included the hidden __LASTFOCUS field and some of my pages didn't. (That's what prompted me to search around and find your question) Now I'm just trying to figure out how to make sure __LASTFOCUS always shows up on every page I want to keep track of focus on... (Looks like I'll have to open a separate question about it)
Here is what I just did. Assuming you have a handler in your code behind that takes care of the event and has a signature like this:
protected void myEventHandler(object sender, EventArgs e)
You can use this line of code to restore focus back to the sending object:
ScriptManager.RegisterStartupScript((WebControl) sender, sender.GetType(), "RestoreFocusMethod", "document.getElementById(\"" + ((WebControl) sender).ClientID + "\").focus();", true);
just using the Focus() method of the sending control will reposition the page (if you are scrolled down a bit), but this works beautifully. And if you have specific handlers for your control, you can just use the control itself rather than casting the sender to a WebControl, like this:
protected void CityListDropDown_SelectedIndexChanged(object sender, EventArgs e)
{
...
ScriptManager.RegisterStartupScript(CityListDropDown, CityListDropDown.GetType(), "CityDropDownRefocus", "document.getElementById(\"" + CityListDropDown.ClientID + "\").focus();", true);
}
I am guessing this could be related to this but unfortunately the workaround doesn't seem to work in this case.
After struggling with the larger implementation not working, I boiled it down to the simplest case. This does not work.
public class MyButton : Control
{
public MyButton()
: base()
{
LinkButton but = new LinkButton();
but.CommandName = "test";
but.CommandArgument = "test2";
but.Text = "Click Here";
Controls.Add(but);
}
}
What renders is:
Click Here
There are two major problems here. First, there is no ID. It should have tag id='ctl00$ctl11$ctl07'. So even though it will post, the events never get captured.
Second, it's ignoring the CommandName and CommandArgument, it should be rendering __doPostBackWithOptions anyway.
Am I being immensely stupid and just overlooking something obvious or is this a huge bug in ASP.NET?
I've done this lots of times before where there were many other controls rendered inside a Control or WebControl and never had any problems, so it must have something to do with the simplicity rather than the complexity, I guess.
If anyone can help me solve this it would be much appreciated.
That's because you should implement INamingContainer Interface
Set the ID property of your button.
but.ID = "MyLinkButtonID";
but.Command += new CommandEventHandler(EVENTHANDLER);
If the button is always a member of the class add the button as a member and add it to the Controls collection in the OnInit event.
Forgot to add the event handler for the Command Event.
ARGH! I am kicking myself, the answer is actually a naming container problem. This was one of those situations where all I could do was focus on some detail, which wasn't actually the problem.
My custom control gets emitted by another control... into yet a third control. But there can be several instances of "third control." (The big picture is, I'm making something that will allow me to put a copy of form control buttons both before and after a form. The main control determines which buttons to emit for a given form.).
So the "third control" was not a naming container. And that was killing it. But I never got any errors about ID conflicts, it just didn't work.