I have a control which extends UserControl. This control contains two ComboBox controls. I've created an event handler which fires when either of the combos changes:
public event EventHandler ComboChanged
{
add { cmbA.SelectedIndexChanged += value; cmbB.SelectedIndexChanged += value; }
remove {...}
}
When I add an event handler to this event, is there any way for the sender to be reported as the custom control (i.e. the ComboBox's parent control) rather than the ComboBox itself? Or am I trying to do something I shouldn't be doing here?
You should have something like this :
public event EventHandler MyControlChanged
and then in your userControl two functions for each of the ComboBox
protected void oncmbA_SelectedIndexChanged(object sender, EventArgs e)
{
if (MyControlChanged!=null)
MyControlChanged(this, e);//or some new Eventagrs that you wish to communicate
}
protected void oncmbB_SelectedIndexChanged(object sender, EventArgs e)
{
if (MyControlChanged!=null)
MyControlChanged(this, e);//or some new Eventagrs that you wish to communicate
}
this would then refer to the UserControl and not to the combobox that fired your UserControl's event.
Yoann's answer is the way to go. Here's a similar pattern, but with some minor differences.
// Default listener makes null-check unnecessary when raising event.
// Note that no custom implementations are provided for add, remove.
public event EventHandler ComboChanged = delegate { };
...
foreach(var comboxBox in new[] {cmbA, cmbA})
{
// Attach listener to combo-box's event that raises our own event.
// Lambda-expression is ok since we don't intend to ever unsubscribe.
comboBox.SelectedIndexChanged += (sender, args) => ComboChanged(this, args);
}
Related
I have a customized control inside the splitview's pane. Now I have the method hideinternal() defined inside the control which makes the control invisible. However, at the same time I also want to close the pane. What should I do? (I know it is SplitView.IsPaneOpen = false; I don't know how to get access to it inside the control's code behind)
I would raise an event from within hideinternal that can then be subscribed to in your view where you could hide the Pane.
eg in your Custom Control the event
public event EventHandler CloseSplitViewPane;
public void OnCloseSplitPaneView(object sender, EventArgs e)
{
CloseSplitViewPane?.Invoke(sender, e);
}
in hideinternal
public void hideinternal()
{
OnCloseSplitViewPane(this, new EventArgs());
}
in your view for example MainPage.xaml.cs constructor (Your Custom Control is called MyControl in this example)
public MainPage()
{
this.InitializeComponent();
MyControl.CloseSplitViewPane += (sender, e) =>
{
SplitView.IsPaneOpen = false;
};
}
Hope that helps
I finally defined an event handler inside the control;
public event EventHandler handlesomething;
then in hideinternal I notify the event;
private void hideinternal()
{
doSomething();
this.NotifyEvent(handlesomething);
}
in the main page's XAML I sign the event handler to some events inside the page
<Control
handlesomething ="SomeMethodsInsideMainPage"
/>
I have a class called TextBoxPlus that inherits from UserControl and holds multiple regular TextBox instances, while also exapnding on their functionality. I have an instace of TextBoxPlus in my Windows Form that is calling the TextChanged event. The issue I have is I want it to pass through to the TextChanged event of one of the TextBox instances within the TextBoxPlus. I don't want to make the TextBox public so I'm likely looking at an override but I'm not sure on how to do this as this does not work:
protected override void TextChanged(EventArgs e)
{
this.textbox.TextChanged(e);
}
obviously due to the TextChanged event not calling a method. How can I achieve this?
Define an event on the containing class whose implementation adds its handlers to the contained object's events:
public event EventHandler TextChanged
{
add
{
textbox.TextChanged += value;
}
remove
{
textbox.TextChanged -= value;
}
}
I have a control which has an Event handler. I normally used this control on many pages where I manage the raised event. But now, just once I need to put this control into another control and subsequently on a page. Is there a way to trespassing the event from the original control?
Normal situation
Control1 > Page
Control1
public event EventHandler MyEvent;
protected virtual void OnMyEvent(EventArgs e)
{
if(this.MyEvent != null) this.MyEvent(this, e);
}
Page.aspx
<ASP:Control1 id="ctrl1" runat="server" OnMyEvent="ctrl1_MyEvent" />
Page.aspx.cs
protected void ctrl1_MyEvent(object sender, EventArgs e)
{
....
}
Exceptional case
Control1 > Control2 > Page
How can I do to re-raise the event to be managed on the page as described above? Is it possible?
I was planning to declare again on the second control an event handler and then create a method that raise the event, but I was thinking if there is another way to do this.
I'd suggest creating your own class, which I would call 'SomeNameEventManager'.
In your parent control, you directly subscribe / unsubscribe via this class.
And in your child control, you can raise the event by calling the method (e.g. OnChanged).
Example code:
public class SomeNameEventManager
{
ChangedEventHandler(object sender, EventArgs e);
public static event ChangedEventHandler Changed;
public static void OnChanged(EventArgs e) { Changed(this, e); }
}
Maybe you come up with a more dynamic way to do this.
In any case I guess, the way to go is to have a class in the middle.
I am creating a C# WinForms user control. There will be times when the user control will need data from the form it's contained in. How do I go about having the user control tell the form containing it that it needs some data?
Thanks!
You can subscribe the form to an event raised on the UserControl.
Your archiecture dictates where and when you need to subscribe to the data event. We can't answer that without knowing a little more about how your whether you are adding the control at runtime or design time. Each case will require a little derivation. From the perspective of adding your control at runtime, you could do something similar to the following:
// Your sample control
public class MyUserControl : Control
{
public event EventHandler<EventArgs> INeedData;
public Data Data {get; set;}
private class DoSomething()
{
if(INeedData!=null) INeedData(this,null);
}
}
...
// Your Form, in the case that the control isn't already added.
var _myUserControl = new MyUserControl();
private void Form1_Load(object sender, EventArgs e)
{
_myUserControl.INeedData += new EventHandler<EventArgs>(MyUserControl_INeedData);
this.Controls.Add(myUserControl);
}
void MyUserControl_INeedData(object sender, EventArgs e)
{
_myUserControl.Data = SomeData;
}
Create a custom event in the user control and have the form hook into it. If you need custom event arguments, you can create those too.
In user control:
//Define your Custom Event argument
public class MyEventArgs : EventArgs
{
//Define some fields of your custom event argument
private int m_SomeValue = 0;
//Define some properties of your custom event argument
public int SomeValue
{
get { return m_SomeValue; }
set { m_SomeValue = value; }
}
}
//Define the event handler data type
public delegate void MyEventHandler(object sender, MyEventArgs e);
//Define the object which holds the outside event handlers
public event MyEventHandler SomeEvent;
//Define the function which will generate the event
public virtual void OnSomeEvent(MyEventArgs e)
{
if (SomeEvent != null)
SomeEvent(this, e);
}
.
. //Then later in the control
.
{
//We need new data
//Create the event arguments
MyEventArgs newEvent = new MyEventArgs();
//Set the values
newEvent.SomeValue = 17;
//Call the event generating function
OnSomeEvent(newEvent);
}
In your form just use something like:
myControl.SomeEvent += new MyEventHandler(handlerName);
Since your event is public, you should see it in the Properties window of your control as well.
You can fancy up the event using Metadata attributes, but I leave it up to you to discover these.
Create an event on the user control where the event args are editable. Let the form attach a handler to that event, which updates those fields. Use those fields in the OnEvent method.
[untested]
eg.
public delegate void NeedsUserDataEventHandler(object sender, NeedsUserDataEventArgs args);
public class NeedsUserDataEventArgs : EventArgs
{
public UserData UserData { get; set; }
}
// In Control
public event NeedsUserDataEventHandler NeedsUserData;
public void OnNeedsUserData(NeedsUserDataEventArgs args)
{
NeedsUserDataEventHandler handler = NeedsUserData;
if (handler != null) handler(this, args);
// store your data somewhere here
}
// In Form
public override void OnLoad(object sender, EventArgs args)
{
control.NeedsUserData += ControlNeedsUserData;
}
public override void OnClosed(object sender, EventArgs args)
{
control.NeedsUserData -= ControlNeedsUserData;
}
public void ControlNeedsUserData (object sender, NeedsUserDataEventArgs args)
{
args.UserData = // set whatever here
}
Seems a bit vague to me, but:
Make it an event in the containing WinForm, so that every time some data is ready all the subscribers can be notified in a one-to-many model; or make it an event in the subscribed control, in a one-to-one model, in which it calls the container's method that retrieves such data?
It's dependent on when that data needs to be pushed to the UserControl. Are there events taking place on the Form that will drive the need to move data within the UserControl? If so...simply grab your instance at that point and push the data down to the UserControl via a public property.
If this is a case where events are not being used or the Form in some fashion or another "receives the data" then exposing an event on the Form such as...
public event DataHandler ReceivedData;
...and allow the UserControl or any other container to register for the event and receive the data via your custom event args. Pushing the event into the UserControl and forcing the Form to latch onto the UserControl seems backwards since the Form is the initiator of the data.
If I have a DropDownList control that makes up part of a CompositeControl how can I expose the SelectedIndexChanged event to the consuming aspx page?
Thanks
There is a much simpler way that is a direct pass through.
Try this:
public event EventHandler SelectedIndexChanged
{
add { this.TargetControl.SelectedIndexChanged += value; }
remove { this.TargetControl.SelectedIndexChanged -= value; }
}
[Edit] Unless of course you need to inject custom logic.
Here's what you do. First declare an event like this:
public event EventHandler SelectedIndexChanged;
Then, internally, hook up to the DropDownList's SelectedIndexChangedEvent. In your event handler do something like this:
protected void DropDownList1_SelectedIndexChanged(object sender, EventArgs e)
{
if (this.SelectedIndexChanged != null)
{
this.SelectedIndexChanged(sender, e);
}
}
All you're really doing is wrapping the original event and re-raising it.
EDIT: See Brian Rudolph's answer. That's in fact a much simple way of doing it.