Question

I seem to be have a great deal of trouble with a simple issue. Yes I'm new to c# but I try to learn what I can without jumping to post a question. In this case I just think I'm not asking the right question.

No code samples will help here because I'm talking about the basics ( implementation ). I have not really coded anything yet, just use the visual builder to create my windows forms and menus.

The issue I'm having is when I select a menu item (call it: set paths ) I want that list view on my main form to load from the path selected when I hit ok on form2. So I did a simple find folder dialog and I have my new path stored on form2 in a text box. When I hit ok on that form2 I want my listview form1 to populate. I know how to do all of this but I can not for the life of me access form1 from form2 or vice versa.

I tried making a call back function but I get that non-static variable cannot be referenced... error because my form1 is static, so I can't create any non static methods. I looked in to EventArgs but that just seems like an over kill for such a common request.

So what is the general way to do this?

Was it helpful?

Solution

Robert's answer is correct as far as accessing members on another form. However, in general you should be storing the state of your application (call it the "model") separately from the state of your user interface (call it the "view"). This becomes very important as your application grows beyond one or two interactions. There are several philosophies or patterns about how to tie the two together (Google "model-view-controller" (MVC) and "model-view-viewmodel" (MVVM) for example), and if you really want to do this correctly I would recommend learning about those. My preference is for the MVVM approach, and you can do it fairly easily with Windows Forms even though it was designed with WPF applications in mind.

In .NET, the basic piece of code you should use to implement the connection between your viewmodel and your view is an interface called INotifyPropertyChanged. You create a class that implements this interface and sends notifications whenever a property changes, so for example for your path property you would create this class:

class ViewModel : INotifyPropertyChanged
{
    private string path;
    public string Path
    {
        get { return path; }
        set {
            if (value != path)
            {
                path = value;
                NotifyPropertyChanged();
            }
        }
    }

    // This event gets triggered whenever a property changes.
    public event PropertyChangedEventHandler PropertyChanged;

    // This will cause the event to actually be triggered. It automatically determines the name of the property that triggered it using the [CallerMemberName] attribute - just a bit of .NET 4.5 sweetness. :)
    private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

It may seem like a lot of work, but now in your form1 you can create a new "ViewModel" instance, subscribe to the event, and then pass the instance to form2. form2 then simply updates the Path property on the viewmodel instance whenever the user selects a different path.

So, Form1 needs this code near the top:

private ViewModel viewmodel = new ViewModel();

And this goes in the Form1 constructor:

viewmodel.PropertyChanged += new EventHandler(OnPathChanged);

And when you create/show form2:

var form2 = new Form2(viewmodel); // Note, the viewmodel instance is being passed to the form2 constructor
form2.Show();

The form2 constructor then stores its own reference to the "viewmodel" instance, and sets the Path property whenever the path is changed by the user.

private ViewModel viewmodel;

public Form2(ViewModel viewmodel)
{
    this.viewmodel = viewmodel;
    ... // Other stuff to set up your controls etc. goes here
}

private void PathChanged(object sender, EventArgs e) // This may be named differently in your code; it's the event handler that gets called when the path changes
{
    // This will automatically notify the event handler in Form1! It's super-elegant and flexible.
    this.viewmodel.Path = txtPath.Text; // Assuming you have a textbox called txtPath
}

And finally the event handler in Form1:

private void OnPathChanged(object sender, EventArgs e)
{
    var newPath = viewmodel.Path; // Get the updated path back from the viewmodel
    //TODO: Whatever you want to do when the path changes.
}

Here's a link to a really good MVVM intro using Windows Forms, it uses two forms like you have in your example. MVVM (Model-View-ViewModel) Pattern For Windows Form Applications, using C#

OTHER TIPS

If you need to access something on another form, just hold a reference to it from your first form, like this:

form2 = new Form2();
form2.Show();
form2.WhateverYouWantToAccess

That said, if you just want to get a file path from the user, you want to use the OpenFileDialog class.

private void button1_Click(object sender, System.EventArgs e)
{
    Stream myStream = null;
    OpenFileDialog openFileDialog1 = new OpenFileDialog();

    openFileDialog1.InitialDirectory = "c:\\" ;
    openFileDialog1.Filter = "txt files (*.txt)|*.txt|All files (*.*)|*.*" ;
    openFileDialog1.FilterIndex = 2 ;
    openFileDialog1.RestoreDirectory = true ;

    if(openFileDialog1.ShowDialog() == DialogResult.OK)
    {
        try
        {
            if ((myStream = openFileDialog1.OpenFile()) != null)
            {
                using (myStream)
                {
                    // Insert code to read the stream here.
                }
            }
        }
        catch (Exception ex)
        {
            MessageBox.Show("Error: Could not read file from disk. Original error: " + ex.Message);
        }
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top