Passing data from a UserControl to another - c#

I have a form and two custom UserControl that I made myself. one control has some buttons that each of these button have theire Tag property set to an array of PointF. I have another UserControl that has a ObservableCollection<PointF[]> that I set its event handler to draw the lines if data is being added to it. This works fine If I put the data points on its own class...just make to sure it works.
No my problem is, having this two control in one form, how can I set the click event of buttons in the first control, to add data points to the second control?
This two controls are both in two different projects in my soloution. and the form that these to controls are being showed in, is also in a different project (it is the launching project of soloution)

Add an event to the first control.
public event EventHandler<EventArgs> Control1ButtonClicked;
private void OnClicked()
{
var handler = Control1ButtonClicked;
if (handler != null)
{
handler(this, new EventArgs());
}
}
private void Button1_Click(object sender, EventArgs e)
{
OnClicked();
}
Add a property to the second control
public ObservableCollection<PointF[]> MyPoints{ get; set;};
Then in your main application add a listener
userControl1.Control1ButtonClicked += new EventHandler<EventArgs>(userControl1_Control1ButtonClicked);
void userControl1_Control1ButtonClicked()
{
//Do Something to control 2
userControl2.MyPoints.Add() = //Whatever
}

You could add a public method on the second usercontrol that receive an array of PointF, then inside this method you could add the PointF to your collection.
EDIT: To handle the click event inside the first user control
inside the first usercontrol add the event and the delegate required
public delegate void OnClickPointDataEvent(object sender, PointF[] data);
public event OnClickPointDataEvent ClickPointData;
then form_load event subscribe to the usercontrol1 event
uc1.ClickPointData += new UserControl1.OnClickPointDataEvent(form_subscribe_event);
private void form_subscribe_event(object sender, PointF[] data)
{
uc2.SomePublicMethod(data);
}
and finally, inside the first usercontrol button click call the code that handle the event inside the form
....
if(ClickPointData != null)
ClickPointData(pointf_array);
...

Related

C# Event driving between user controls on win forms

I have a main form (form1) which has a panel (panel1) -- see pic.
Form1 pic
Panel1 loads one of two different user controls based on which button is pressed (to simulate screen changes). I have a button on user control 1 which needs to act (change text) on user control 2.
The issue I have is the user controls are dynamically created with a button press on form 1 (see code below) which is causing me issues trying to link events-
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
panel1.Controls.Add(new Screens.UC1());
}
private void button1_Click(object sender, EventArgs e)
{
foreach (Control ctrl in panel1.Controls)
{
ctrl.Dispose();
}
panel1.Controls.Add(new Screens.UC1());
}
private void button2_Click(object sender, EventArgs e)
{
foreach (Control ctrl in panel1.Controls)
{
ctrl.Dispose();
}
panel1.Controls.Add(new Screens.UC2());
}
}
What is the best way to deal with linking these kinds of items with events when the instance of the objects are dynamically created. I also tried making instances of the screen and then referencing to those, but that ran into scope issues.
Code for UC1 (user control 1)
public partial class UC1 : UserControl
{
public UC1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
//Event to change text on UC2
}
}
Code for UC2 (user control 2)
public partial class UC2 : UserControl
{
public UC2()
{
InitializeComponent();
}
public void WriteText(object sender, EventArgs e)
{
label2.Text = "Text Changed...";
}
}
Any help greatly appreciated.
Why dispose and create all those controls when the operator presses a button?
Better is to create two UserControls. One with all the Controls you want to show when operator presses button 1 and one with all the Controls you want to show when operator presses button 2.
To create a user control use menu Project - Add User Control, or right click in solution explorer on your project and select add new item.
Layout your user controls with all the controls your want to show. Add event handlers etc.
Then in your form:
private readonly UserControl userControl!;
private readonly UserControl userControl2;
public MyForm()
{
InitializeComponent()
this.userControl1 = new UserControlA(...);
this.userControl2 = new UserControlB(...);
// make sure that the user controls are Disposed when this form is Disposed:
this.Components.Add(this.userControl1);
this.Components.Add(this.userControl2);
}
void OnButton1Clicked(object sender, ...)
{
// remove userControl2 from the panel
this.Panel1.Controls.Remove(this.userControl2);
// add userControl1 to the panel
this.Panel1.Controls.Add(this.userControl1);
}
This way all the overhead of creating / adding / positioning / add event handlers and all cleanup is only done once: during construction of your form. Switching the user controls will be done in a flash
I am not sure what you are trying to accomplish, but it looks like you are trying to change the state of objects from other objects that cannot have references to the objects they are trying to change.
In this case, I would create a type that functions as some kind of manager that subscribes to events of all of these controls. You can create your own events within a UC class, or just use the Windows Forms click event like you are already doing.
Since the handler of the events are defined in the manager, you can easily write logic that will work on the other user controls, as long as the manager has references to them.
Like this:
public class ClickTrafficer {
private UC target;
public void HandleClick(object sender, UCClickHandlerEventArgs ea) {
target.WriteText(ea.TextToWrite);
}
}
public Form1()
{
InitializeComponent();
var trafficer = new ClickTrafficer();
var screen1 = new Screens.UC1();
screen1.Click += trafficer.HandleClick;
panel1.Controls.Add(screen1);
}
This is a crude idea of what you could do. Missing here are the logic to set whatever the target field must be set to. You need to create logic that tells the trafficer which control sets which control's text.
Also, the ClickTrafficer I created uses a custom event with custom eventargs, you need to define those or find a way to pass the necessary information through the built in events. Creating events is really easy though so you can look that up online.

C# Forms: Raise mouse event (pass from child to parent)

Looking for any solution.
I have a user control with several textboxes. When placed on a form, MouseDown and MouseMove events are only triggered if clicked on user control body, but not when clicked in text box.
Is it possible to raise user control's mousedown event when textbox mousedown event happens?
Or is it possible to pass events from object to its parent? (and still be able to click the textbox to edit it?)
Thanks
In this example I have handled the TextBoxes MouseDown event. From here, you can raise the MouseDown event of the UserControl that holds your TextBox.
public partial class UserControl1 : UserControl
{
public UserControl1()
{
InitializeComponent();
}
private void textBox1_MouseDown(object sender, MouseEventArgs e)
{
OnMouseDown(e); // Goes through as a MouseDown Event from UserControl1
}
}
Depending on your requirements, this may not work for you as when the MouseDown of the UserControl is handled, it will come through as being originated by UserControl (The sender parameter will refer to UserControl1.
I also extracted the OnMouseDown implementation of the Control class to see if it could be used:
// Extracted using Reflection
// This will not compile as Control.EventMouseDown is a private member
System.Windows.Forms.MouseEventHandler mouseEventHandler = (System.Windows.Forms.MouseEventHandler)this.Events[System.Windows.Forms.Control.EventMouseDown];
if (mouseEventHandler == null)
return;
mouseEventHandler(sender, e);
Unfortunately, the events are stored in a Private member and not readily accessible.
If you want to know and handle the MouseDown event differently if it originates from a TextBox, you will have to declare and raise a custom event.
Declare Custom Event
public event EventHandler<MouseEventArgs> TextBoxMouseDownEvent;
Raise Custom Event from TextBox_MouseDown
private void textBox1_MouseDown(object sender, MouseEventArgs e)
{
EventHandler<MouseEventArgs> handler = TextBoxMouseDownEvent;
if (handler != null)
{
handler(sender, e);
}
}

Creating events for CustomControl

I am working on a UserControl for selecting special files, in this control there is a TreeView which gets populated with nodes when user selects some file. Also user can remove the files from this treeview!
I am using this control in a wizard form. In this wizard form there is a button named buttonNext and this button is disabled by default.
How can I create an event for the treeview in the usercontrol that when it gets populated it notify the next button in wizard form to get enabled and if user removes all files from that treeview it notify the button to get disabled again.
P.S: Selecting files (browser dialog and stuff like that) are all done within this usercontrol, so in my wizard form I have no access to the things that is going on in this component, but only I set the TreeView itself as public so I can read its nodes in my wizard form.
I know how to subscribe to events but never created any event myself :(
Declare events on your CustomControl:
public event EventHandler DataPopulated;
public event EventHandler DataRemoved;
Common practice is creating protected virtual methods (for possible overriding them in descendant classes), named On<EventName> which will verify that event has attached handlers and raise event, passing required arguments:
protected virtual void OnDataPopulated()
{
if (DataPopulated != null)
DataPopulated(this, EventArgs.Empty);
}
NOTE: If you need to pass some data to event handlers, then use generic EventHandler<DataPopulatedEventArgs> delegate as event type, where DataPopulatedEventArgs is a class, inherited from EventArgs.
Then just call this method just after your data was populated:
treeView.Nodes = GetNodes();
OnDataPopulated();
Then just subscribe to this event and enable your next button:
private void CustomControl_DataPopulated(object sender, EventArgs e)
{
buttonNext.Enabled = true;
}
Who is the one populating the TreeView? The one loading the data on it could enable the Next button when it has finished the loading. Am I missing something?
By the way, you create an event like this:
public event EventHandler<EventArgs> YouEventName;
And you call it like a method:
this.YourEventName(this,EventArgs.Emtpy);
Best practices say that you should create a method to call it like this:
protected virtual void OnYourEventName()
{
if (this.YourEventName != null)
{
this.YourEventName(this, EventArgs.Empty);
}
}
Check out this MSDN article for a complete tutorial on how to create and fire events.
http://msdn.microsoft.com/en-us/library/aa645739(v=vs.71).aspx
You can just propogate the event of the Treeview.
You can add this to your custom control, and it will have a SelectedNodeChanged event.
public event EventHandler SelectedNodeChanged
{
add { tree.SelectedNodeChanged += value; }
remove { tree.SelectedNodeChanged-= value; }
}
Creating a new event
public event EventHandler<EventArgs> myEvent;
You then invoke it from some method
this.myEvent(sender, e);
The actual event would look something like this:
protected void MyEvent(object sender, EventArgs e)
{
//Your code here
}
Your code can be like this:
public delegate void ChangedEventHandler(object sender, EventArgs e);
class TreeViewEx : TreeView
{
...
public event ChangedEventHandler Changed;
protected virtual void OnChanged(EventArgs e)
{
if (Changed != null)
Changed(this, e);
}
}
and it usage
TreeViewEx tree = ...
tree.Changed += new EventHandler(TreeChanged);
// This will be called whenever the tree changes:
private void TreeChanged(object sender, EventArgs e)
{
Console.WriteLine("This is called when the event fires.");
}

C# set dataTable generated in formname.designer.cs as static

I want to know if it's ok to modify the formname.designer.cs and to set a variable that is generated from design mode as private as static:
private dtableAdapters.llist nameTable;// this to become static
public static dtableAdapters.llist nameTable;//like this
I read here C# Set Checkbox to Static that is not a good method.
Maybe I can do this in other way. Here is what I want to do:
I have a Form that contain more forms, opened in a panel. One form contains some comboboxes with values from the database. The problem is that when I add more values to the database from another form with a textbox, the combobox needs to be filled again. I thought that it could be easy if I update the combobox immediatlly after i add some values.
(combobox and the textbox -that add values in the database which are shown by combobox- are in different forms).
Do you have an other ideea of doing this? I have tried also to fill the combobox again when it's clicked but because I have more comboboxes I get some fatal errors when I click fast from one to another.
edit: as a last method: I could add a button and fill the combobox when the button is pressed, but I want to do it automatically
(winforms not web forms)
One approach is to fire an event on FormA when a value is added.
Form B can subscribe to the event and update the list.
The only tricky bit is that FormB needs a reference to FormA to hook up to the event.
Something like this...
FormA
public delegate void DataAddedEventHandler(object sender, EventArgs e);
public partial class FormA : Form
{
public event DataAddedEventHandler DataAdded;
private void AddButton_Click(object sender, EventArgs e)
{
//do The database stuff...
//fire the event
OnDataAdded();
}
private void OnDataAdded()
{
if (DataAdded != null)
{
DataAdded(this, new EventArgs());
}
}
FormB
public void HookupListener(FormA dataform)
{
//hook up the event to the handler
dataform.DataAdded += new DataAddedEventHandler(dataform_DataAdded);
}
void dataform_DataAdded(object sender, EventArgs e)
{
//refresh the combo box
}

how do I subscribe to an event of a usercontrol

I have a group of usercontrols that I use multiple instances of through out my form.
The usercontrols have contain either a textbox, combobox, or checkbox and a get value method to return the value of it's repective control. Usually I have a button on the form whose clicked event calls the usercontrols getValue function, but now I need for something to happen on the form whenever the usercontrols controls changed event happens. Something like the following.
In form1.cs
form1.Controls.Add(UserControl1);
form1.Controls.Add(UserContorl2);
// gets called every time the combobox on UserControl1 has it's
// ValueChanged event raised
private void UserControl1_Changed(object Sender, EventArgs e)
{
form1.property1 = UserControl1.getValue();
}
// gets called everytime the textbox on UserControl2 has it's
// textChanged event raised
private void UserControl2_Changed(object Sender, EventArgs e)
{
form1.property2 = UserControl2.getValue();
}
I can't figure out how to throw/catch that event in form. I'm using VS 2005.
here is the code in one of my usercontrols. txtValue is a textbox
public partial class StringParameterControl : BaseParameterControl
{
public StringParameterControl(string aName, string aValue)
: base(aName)
{
InitializeComponent();
txtValue.Text = aValue;
}
public StringParameterControl(string aName)
: base(aName)
{
InitializeComponent();
}
public StringParameterControl()
: base()
{
InitializeComponent();
}
public void SetValue(string aValue)
{
txtValue.Text = aValue;
}
public override object GetValue()
{
return txtValue.Text;
}
}
UserControl1.Changed += UserControl1_Changed;
Update your control to include the following:
// A delegate type for hooking up change notifications.
// This is _what kind_ of event you want. It sets the signature your event handler methods must have.
public delegate void ChangedEventHandler(object sender, EventArgs e);
//the actual event
public event ChangedEventHandler Changed;
// Method to raise/fire the Changed event. Call this whenever something changes
protected virtual void OnChanged(EventArgs e)
{
ChangedEventHandler handler = Changed;
if (handler != null) handler(this, e);
}
//and update your existing SetValue() function like so:
public void SetValue(string aValue)
{
txtValue.Text = aValue;
OnChanged(EventArgs.Empty);
}
You can change your event signature to pass any information you want — for example the old or new value of the property (or both). I just used the standard event arguments for the example.
And speaking or properties, don't write separate Get/Set methods in C# like you just did. If you find yourself doing that, you probably want to use a property instead, which will enforce the correct get/set semantics automatically:
public string Value
{
get { return txtValue.Text;}
set {txtValue.Text = value; OnChanged(EventArgs.Emtpy); }
}
As far as I understand the usercontrols you are using do not fire events whenever their value changes, so you can't just subscribe to some "ValueChanged" event.
A possible solution might be to find the control you are interested in (Combobox, Textbox, etc.) in the usercontrols' "Controls" collection and directly subscribe to its appropriate events.
Or you can do with type inference style.
UserControl.Changed = (sender, e) => this.controlFired = true; //or whatever
The Changed is the public event you expose through a property in your control with the type of the delegate (void(object sender, EventArges e)). You can look up how to publish the event on msdn - there is plenty of articles on that.

Categories

Resources