Calling a method in a UserControl from another UserControl - c#

I've been researching this problem for some time now and I cannot seem to find a solution that works. I want to call a method a UserControl from a method in another UserControl.
In UserControl1 I have a method:
public void update(int lineNum, double price)
{
// do stuff...
// then call the method in another UserControl
UserControl2 uc2 = new UserControl2();
uc2.refreshList();
}
And in UserControl2, I have a method:
public void refreshList()
{
// do stuff....
}
Of course, I have tried other methods of doing this other than simply creating an object of the UserControl and calling the method that way but nothing seems to work.

Having such dependencies between user controls is not good: it limits the use and makes them hardly testable in isolation.
You have several options to achieve what you want.
Let the caller do the orchestration
You did not state where the code resides that calls update. But since the method is public, I assume that this is called from outside UserControl1. Maybe it is possible to put the userControl2.refreshList() call there just after the call to userControl1.update()
Use an event
You could define an event in UserControl1 e.g. public event EventHandler UpdatePerformed and raise it at the end of the update method. Then in your form, subscribe to this event and call refreshList from there:
userControl1.UpdatePerformed += (s, e) => userControl2.refreshList();

Related

What is the most elegant way to call an event of another Form?

Let's say I have a Form called Form1 which will somehow (how is not relevant) calls another form Form2
(Form1)
Form2 f2= new Form2();
f2.ShowDialog();
This Form2 has a button that will do some operation everytime the user clicks on this button.
However, I want that the first time i.e. when Form2 is just shown, the code in the button (some operation) gets executed.
In other words I have to be able to call the code in Form2's button_Click which is private.
Now I can think of some ways to make this possible(making the click event public etc) , but my question is what is the most elegant (or correct) way to do this?
I would add a property to Form2 to tell the form I like to automatically executed an action.
class Form2
{
public bool AutoExecuteSomeOperation { get; set; }
}
In Form1, you would set that property and in Form2 you would check and execute appropriate code if the property was set.
I would recommend that you refactor button_Click to call another method which you can also call for automatic execution. I like to keep event handler simple and executed only for the event on the control that served to name the event handler. Thus, you know that button_Click is an handler for a Click event on a control named button. It makes the code easier to maintain.
You can decide if you want to reset the property once the code is executed or you can add some validation that the property changes are valid. For exemple, you might want to ensure that the property is called before displaying the form.
In all cases, you should avoid having any reference to a control from an external form. Only Form1 itself should know that it contains a button. Any use from outside world should be done through a public property or public event of the form. That way, if you decide that the button should be replaced by an hyperlink, a menu item, a checkbox or anything else Form1 does not need to be updated. This is very similar to what should be done for UserControl. The less internal details leak, the easier it will be to make internal changes without having to update all caller.
The easiest approach is just make it public, however its not the bastion of great design.
Decoupled messaging is probably where you want to be, event aggregator or any pub sub method messaging system. This is a more modern and scalable approach, the participants need not know about each other allowing you to make the methods private and giving you a more maintainable decoupled solution, and keep your classes self consistent.
Unity, MvvmLight both have these sorts of messaging systems, however there are lots of them.
Example of how this might work
public Form1()
{
InitializeComponent();
EventPublisher.Instance.Subscribe<NewUserCreated>
(n => listBoxUsers.Items.Add(n.User.Name));
}
...
// some other class
private void Form2()
{
var user = new User()
{
Name = textBoxUserName.Text,
Password = textBoxPassword.Text,
Email = textBoxEmail.Text
};
EventPublisher.Instance.Publish(new NewUserRequested(user));
}
Move the code from the OnClick event into its own method (e.g. "DoWork"), then call that method from the OnClick event.
Either call it when you create the form
var frm = new demoForm();
frm.DoWork();
frm.Show();
Or call it in the forms constructor.
public partial class demoForm : Form {
public demoForm() {
InitializeComponent();
DoWork();
}
private void button1_Click(object sender, EventArgs e) {
DoWork();
}
public void DoWork() {
//Code here
}
}

How to call a UserControl's methods from a Windows.Form

The form has a button and a panel with a UserControl which has a ListBox and a TextBox.
When I click the Windows.Form button it calls UserControl's Add()
listBoxTitles.Items.Add(metroTextBoxTitles.Text);
metroTextBoxTitles.Clear();
Which simply adds whatever the UserControl's TextBox.Text has to the UserControl's ListBox.
For some reason nothing happens when i click the button.
Why. Nothing on the UserControl can be changed or used? Or does it change but doesn't update/show what's going on?
The best way to deal with communication between containers is to implement an observer class
The observer pattern is a software design pattern in which an object, called the subject, maintains a list of its dependents, called observers, and notifies them automatically of any state changes, usually by calling one of their methods.
(wikipedia)
the way i do this is creating an Observer class:
1 public delegate void dlFuncToBeImplemented(int signal);
2 public static event dlFuncToBeImplemented OnFuncToBeImplemented;
3 public static void FuncToBeImplemented(int signal)
4 {
5 OnFuncToBeImplemented(signal);
6 }
so basically: first line says that there would be a function that somebody else will implement
second line is creating an event that occur when the delegated function will call
and the third line is the creation of the function that calls the event
so in your UserControl you should add a function like this:
private void ObserverRegister()//will contain all observer function registration
{
Observer.OnFuncToBeImplemented += Observer_OnFuncToBeImplemented;
/*and more observer function registration............*/
}
void Observer_OnFuncToBeImplemented(int signal)//the function that will occur when FuncToBeImplemented(signal) will call
{
MessageBox.Show("Signal received!", "Atention!", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
}
and in your Form you should do something like:
public static int signal = 0;
public void button1_Click(object sender, EventArgs e)
{
Observer.FuncToBeImplemented(signal);//will call the event in the user control
}
and now, you can register this function to a whole bunch of other controls and containers and they will all get the signal
I hope this would help :)
So, what was happening was, when you create a UserControl and add it to the Window.Form the Form's designer already initiates that UserControl:
private UserControl userControl1;
So in order to solve the issue i just needed to use the UserControl which the designer code created:
usercontrol1.add();
And everything is working perfectly.

Windows Forms Binding: is there an event similar to DataBindingComplete, but fired when ALL bindings are completed?

I need to change a certain DataGridView's property (a DataSourceUpdateMode for one of its binding) only when ALL of its initial data bindings are completed.
I tried subscribing to the "DataBindingComplete" event, but it's fired too many times (one or more time for each binding associated to the control); what I need is a more global "AllDataBindingsComplete" event, fired when the control is ready to be displayed to the user.
As a temporary workaround, I'm using the MouseDown event (I've assumed that when the user is able to click the control, it means that the control is displayed... :) and the events I'm playing with - SelectionChanged - are fired after the MouseDown):
protected override void OnMouseDown(MouseEventArgs e)
{
Binding selectedItemsBinding = this.DataBindings["SelectedItems"];
if (selectedItemsBinding != null)
{
selectedItemsBinding.DataSourceUpdateMode = DataSourceUpdateMode.OnPropertyChanged;
}
base.OnMouseDown(e);
}
It works, but it smells like an ugly hack A LOT (and it's called too many times, only one time is enough for my needs).
Is there a better way?
(yes, I'm trying to adopt MVVM in a Windows Forms project, and I've added a bindable "SelectedItems" property to the DataGridView...)
What I've done at the Windows Forms form level, and may be improvised down to just the control(s) you want, is to subclass the Windows Forms baseclass into my own. Then, in its constructor, attach an extra event call to the Load() event.
So when everything else is completely loaded, only THEN will it hit my custom method (of the subclass). Since it is the bottom of the call-stack chain being attached to the event queue, I know it's last and everything else is done... Here's a snippet of the concept.
public class MyForm : Form
{
public MyForm()
{
this.Load += AfterEverythingElseLoaded;
}
private void AfterEverythingElseLoaded(object sender, EventArgs e)
{
// Do my own things here...
}
}
This concept can be applied to the Init() function too if that's more appropriate for your control... Let everything else within it get initialized(), then do you the "AfterInitialized()" function.

C# WPF which method is called when I call a window's show()?

I have window A and window B. In window A I call B.show(). I want to know in window B which method is called and I want to load data when B is showing up. thanks,
You can always listen to the "Loaded" event:
BWindow.Loaded += new RoutedEventHandler(BWindow_Loaded);
void BWindow_Loaded(object sender, RoutedEventArgs e)
{
//Your Code here
}
Then in your AWindow call
BWindow.Show();
You may be surprized, but when you call B.Show(), the method which is called is Show().
About loading additional data after window B is shown, you may subscribe to its Loaded event (see answer of #masenkablast). The better idea would be perhaps to derive from Window class and bind to the needed data in XAML. (You are using WPF, not WinForms, I suppose.)
I think it is better to have a Property which is set before B.Show() is called. This way you can always get the method which invokes the show method based on the property.

How do I programmatically invoke an event?

I am creating a C# Windows Mobile application that I need to programmatically invoke the click event on a Button.
I have looked at the Button class and do not see a way to do this.
You might consider changing your design: at least move the logic from button1_Click handler somewhere else so that you'll be able to invoke it from wherever you want.
You can do something like this:
private void button1_Click(object sender, EventArgs e)
{
OnButtonClick();
}
private void OnButtonClick()
{
}
Then you can call your OnButtonClick() wherever you need to.
Not exactly the answer you were probably looking for:::
You might just call the code you want to run, move the meat of the code outside the OnClick handling method. The OnClick method could fire that method the same as your code.
The Control class, from which Button inherits, has the OnClick method, which invokes the Click event. Using reflection, you can call this method, even though it is declared protected. For instance, I created the following extension method:
public static void PerformClick(this Control value)
{
if (value == null)
throw new ArgumentNullException();
var methodInfo = value.GetType().GetMethod("OnClick", BindingFlags.NonPublic | BindingFlags.Instance);
methodInfo.Invoke(value, new object[] { EventArgs.Empty });
}
Although, this may be regarded as a dirty hack...
Anything that prevents you from simply invoking the method that handles the onClick event?
You can call the added event handler function as:
someControl_EventOccured(someControl, new EventArgs());
This works when the control's event argument e is not used inside the handler function, and mostly it's not used.

Categories