2

I have two Forms. One with where all the main code is being executed. And the other form is displayed when clicking a menu item by using this method:

Form2 videoSettings = new Form2();       

private void videoToolStripMenuItem_Click(object sender, EventArgs e)
{
    videoSettings.Show();
}

The form which is then opened containsfields where the user gets to set some settings for the application. enter image description here Then when clicking the "save" button I want this variable: public int deviceIndex; to be fetched from the original Form.

So I'm wondering if I can add any event or something in Form1 which detects when the save button is clicked in videoSettings (Form2)?

5 Answers 5

6

I would do it a different way. I'd separate the code between the UI handling and the business logic layers. So your scenario would run in such a way:

  1. The first form issues an event notifying that the button with certain semantics has been activated. The data needed for the processing is included into the event's data.
  2. The business logic listens to this event, and decides to issue a command on the second form. It calls an appropriate method on the form's class, passing the needed information as a parameter (and maybe preprocessing the parameter if needed).
  3. The second form receives the command from the business logic and updates the view.

This way the problem doesn't arise at all.


Example: (I'm not the winforms expert, beware it can be totally wrong from the POV of best winforms practices.)

Part 1 (first form):

class ProcessingActivatedEventArgs : EventArgs
{
    public ProcessingActivatedEventArgs(int data) { MoreData = data; }
    public int MoreData { get; protected set; }
}

class Form1 : Form
{
    private int currentData;
    public event EventHandler<ProcessingActivatedEventArgs> ProcessingActivated;
    void OnButtonClick(object sender, EventArgs args)
    {
        // ...
        if (ProcessingActivated != null)
            ProcessingActivated(new ProcessingActivatedEventArgs(currentData));
    }
}

Part 2: (business logic)

class Controller
{
    Form1 f1;
    Form2 f2;

    void StartFirstForm()
    {
        f1 = new Form1();
        f1.ProcessingActivated += OnProcessingActivated;
        f1.Show();
    }

    void OnProcessingActivated(object sender, ProcessingActivatedEventArgs args)
    {
        int data = args.MoreData;
        f1.DisableProcessingRequests();
        model.ProcessingFinished += OnProcessingFinished;
        model.StartProcessing(data);
        if (data > 0)
            f2.DisplayDataProcessing(0, data);
        else if (data < 0)
            f2.DisplayDataProcessing(data, 0);
        else
            throw new SomeCoolException("impossible data");
    }
}

Part 3: (second form)

class Form2 : Form
{
    public void DisplayDataProcessing(int lower, int upper)
    {
        // ... update the UI
    }
}

Note that this implementation ties the Controller and forms tighter than it could be done. In WPF, the decoupling is achieved by using the appropriate DataContext (but I don't know how to do it properly in WinForms).

Sign up to request clarification or add additional context in comments.

8 Comments

This indeed sounds like a much better idea! Do you have any example available using this version? Or can you link to something familiar so I just get the hang of it.
@Robert: I am not a winforms expert, so I don't know what is the idiomatic way to express the relations between the view and business logic there. But I'll try.
@Vlad: This seems overly complicated to achieve a very simple task.
@caesay: separation of responsibilities makes the overall structure of the application simpler, and the logic clean. It's worth an extra pair of classes, really. Your maintainers will be grateful to you. Alternately, the application may and up in doing everything in OnClicks.
@caesay: This may initially seem complicated if you're used to the usual way of putting events and code into the forms directly, but it will scale better as the application gets larger, and has a much lower chance of turning into a Big Ball of Mud.
|
1

Let me suggest another way, something between the simplest ShowDialog() and the elaborated way of separation between business logic and interface.

I wish to create a new event in Form2. I call this event SettingsSaved

In Form2 add as global declaration

public delegate void SettingsSavedEventHandler(object sender, SettingsSavedEventArgs e);
public event SettingsSavedEventHandler SettingsSaved;

and in the cmdSave_Click event

if(SettingsSaved != null)
{
    SettingsSavedEventArgs ss = new SettingsSavedEventArgs() { DeviceIndex = deviceIndex};
    SettingsSaved(this, ss); 
}

the skeleton for the class SettingsSavedEventArgs

public class SettingsSavedEventArgs: EventArgs
{
    public int DeviceIndex {get; set;}  
    // Other settings could be added here
}

now in the code calling the Form2 we can subscribe to the event and get notified when the user clicks on the Form2 Save button

Form2 videoSettings = new Form2();
videoSettings.SettingsSaved += new SettingsSavedEventHandler(SavedHandler);
videoSettings.Show();     
....

private void SavedHandler(object sender, SettingsSavedEventArgs ss)
{
    int deviceIndex = ss.DeviceIndex;
}

Observer Pattern

1 Comment

This is just like my second example, except with alot more code :)
1

There are many suggestions, but I'd like to add my two cents.

You could use form2.ShowDialog(); which will stop the execution of your form1 thread until the form2 is closed. Which means you can just do this from form1:

Form2 videoSettings = new Form2();  

//show options
videoSettings.ShowDialog();

//at this point, the user has either clicked save, cancel, or closed the form 
//(because the form is closed, obviously :) )
int device = videoSettings.deviceIndex;

If you cant have it locking up your form like that, here is another way using an event in Form2:

Form2 : Form
{
    public event EventHandler Saved;

    OnSaveButtonClicked(...)
    {
        if(Saved != null) Saved(this, new EventArgs());
    }
}

and then from Form1:

Form2 frm = new Form2();
frm.Saved += (s, e) =>
{
    //saved button clicked, retrieve value.
    //also could be handled as a method, or really any way.
};
frm.Show();

Comments

0

Maybe you could try to have your second form to implement INotifyPropertyChanged interface. Then when you click on Save, you Raise the PropertyChanged event, and you capture it in the first form.

1 Comment

for the non-french version: msdn.microsoft.com/en-us/library/…
0

You can pass information something like this

private Form1 mainForm = null;
public Form2(Form callingForm)
{
    mainForm = callingForm as Form1; 
    InitializeComponent();
}

Then, you can access the Form1 property from Form2 like this:

//Call this in Save button click event 
this.mainForm.deviceIndex;

2 Comments

He needs only that property, so why carrying on all the form. If I were you I would use an interface.
There can be alternatives, Interface can provide a better solution. I just gave what I can.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.