Jump to content

  • Log In with Google      Sign In   
  • Create Account

We're offering banner ads on our site from just $5!

1. Details HERE. 2. GDNet+ Subscriptions HERE. 3. Ad upload HERE.


having a couple of problems with Windown Forms


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
14 replies to this topic

#1 Manhattanisgr8   Members   -  Reputation: 487

Like
0Likes
Like

Posted 14 January 2014 - 08:53 PM

I have been having two problems that have been nagging with Windows Forms. One being the visibility modifier and updating a list box. To start off, I had trouble getting the menu strip highlight colors to change to what I wanted them to be. Fixed that by creating a new class that inherits from MenuStrip and then adding it to the main form. The program (more like game) is using several different panels to display different information and navigation controls. So instead of creating a bunch of different panels in the main form and setting the visibility to false until a button is pressed (putting a bunch of code in one place), I decided to make each panel a user control class (which automatically inherits UserControl). My problem with the visibility modifier is that I had to add each user control to the main form as public static in order for the other controls to set the visibility modifiers. Is there another way to implement something so I don't have to add all the user controls to the main form as public static?

 

The other problem I have is updating a listbox from one user control when I press a button on a different user control. Basically I have a user control which displays info from a list on a listbox with add, modify, delete buttons. When the user clicks add, they are taken to another user control to input the info they want. However, when they click save, I want to update the listbox with the added info. I tried to make the listbox static and have tried both class.listbox.DataSource = null then class.listbox.DataSource = list. That didn't work. Then I tried class.listbox.Refresh(). That didn't work as well.

 

I was thinking about maybe trying to use and Interface, but I am not exactly sure how they work or how to use them. To me, they seem like just a way of organizing like classes in order to save time typing a bunch of methods, but don't interact with each other.

 

Any help would greatly be appreciated.


Cpl Alt, Travis A

USMC


Sponsor:

#2 Nypyren   Crossbones+   -  Reputation: 4510

Like
2Likes
Like

Posted 14 January 2014 - 11:28 PM

It sounds like your main problem is getting different objects "connected" to each other. For now, avoid making anything static. You usually don't need it for WinForms.

I usually do the following:

Whenever I need to "connect" two controls to each other, and they're both in the same form, I write code in the form which connects them:
 
using System.Windows.Forms;

public class UserControl1 : UserControl
{
    public Button Button;

    public UserControl1 Link;

    public UserControl1()
    {
        Button = new Button();
        Controls.Add(Button);

        Size = Button.Size;

        Button.Click += delegate
        {
            if (Link != null)
                Link.Visible = !Link.Visible;
        };
    }
}

public class Form1 : Form
{
    UserControl1 control1;
    UserControl1 control2;

    public Form1()
    {
        control1 = new UserControl1();
        control1.Button.Text = "Button 1";
        Controls.Add(control1);

        control2 = new UserControl1();
        control2.Top = control2.Bottom;
        control2.Button.Text = "Button 2";
        Controls.Add(control2);

        control1.Link = control2;
        control2.Link = control1;
    }
}
Notice the following:

- Form1 owns the controls.
- Form1 is responsible for telling the controls about each other.
- UserControl1 has ZERO code which refers to Form1 in any way.


Generally, I would NOT make the Button public like I did, but for this example it was simpler. Normally, I would do something like this:

public class UserControl1 : UserControl
{
    Button Button;

    public string ButtonText
    {
        get { return Button.Text; }
        set { Button.Text = value; }
    }

    ...    
}

public class Form1 : Form
{
    ...
    
    public Form1()
    {
        ...
        control1.ButtonText = "Button 1";
        ...
        control2.ButtonText = "Button 2";
        ...
    }
}

Edited by Nypyren, 14 January 2014 - 11:40 PM.


#3 Nypyren   Crossbones+   -  Reputation: 4510

Like
1Likes
Like

Posted 14 January 2014 - 11:49 PM

For your listbox issue, consider the following code:
 
using System;
using System.Collections.Generic;
using System.Windows.Forms;

public class UserControl1 : UserControl
{
    Button button;

    public string ButtonText
    {
        get { return button.Text; }
        set { button.Text = value; }
    }

    public event EventHandler ButtonClicked;

    public UserControl1()
    {
        button = new Button();
        Controls.Add(button);

        Size = button.Size;

        button.Click += delegate
        {
            if (ButtonClicked != null)
                ButtonClicked(this, null);
        };
    }
}

public class UserControl2 : UserControl
{
    ListBox listbox;

    public UserControl2()
    {
        listbox = new ListBox();
        Controls.Add(listbox);

        Size = listbox.Size;
    }

    public void SetList(object list)
    {
        listbox.DataSource = list;
    }
}

public class Form1 : Form
{
    UserControl1 control1;
    UserControl1 control2;
    UserControl2 control3;

    public Form1()
    {
        control1 = new UserControl1();
        control1.ButtonText = "Button 1";
        Controls.Add(control1);
        
        control2 = new UserControl1();
        control2.ButtonText = "Button 2";
        control2.Top = control1.Bottom;
        Controls.Add(control2);

        control3 = new UserControl2();
        control3.Top = control2.Bottom;
        Controls.Add(control3);

        string[] list1 = {"A", "B", "C"};
        string[] list2 = {"D", "E", "F"};

        control1.ButtonClicked += delegate { control3.SetList(list1); };
        control2.ButtonClicked += delegate { control3.SetList(list2); };
    }
}
- In this example, the form is mediating the interactions between the different controls.
- None of the controls need to know about each other.
- Things are 'connected' via public events and properties which encapsulate the underlying structure of each user control.

Edited by Nypyren, 14 January 2014 - 11:59 PM.


#4 Nypyren   Crossbones+   -  Reputation: 4510

Like
1Likes
Like

Posted 15 January 2014 - 12:05 AM

Now let's consider another textbox case more similar to what you described.

I've got a control with a textbox and a button, and another with the listbox.

When the button is pressed, it raises an event which includes the text.

The form handles the event and tells the other control to add it.
 
using System;
using System.Windows.Forms;

public class UserControl1 : UserControl
{
    TextBox textbox;
    Button button;

    public delegate void TextHandler(object sender, string text);
    public event TextHandler AddClicked;

    public UserControl1()
    {
        textbox = new TextBox();
        Controls.Add(textbox);

        button = new Button();
        button.Text = "Add";
        button.Left = textbox.Right;
        Controls.Add(button);

        Width = button.Right;
        Height = Math.Max(textbox.Height, button.Height);

        button.Click += delegate
        {
            if (AddClicked != null)
                AddClicked(this, textbox.Text);
        };
    }
}

public class UserControl2 : UserControl
{
    ListBox listbox;

    public UserControl2()
    {
        listbox = new ListBox();
        Controls.Add(listbox);

        Size = listbox.Size;
    }

    public void AddText(string text)
    {
        listbox.Items.Add(text);
    }
}

public class Form1 : Form
{
    UserControl1 control1;
    UserControl2 control2;

    public Form1()
    {
        control1 = new UserControl1();
        Controls.Add(control1);
        
        control2 = new UserControl2();
        control2.Top = control1.Bottom;
        Controls.Add(control2);

        control1.AddClicked += (sender, text) => control2.AddText(text);
    }
}
- Notice how the only things that are public are those that need to be public.
- Notice how there's actually less code now even though it's still very flexible.

Edited by Nypyren, 15 January 2014 - 12:09 AM.


#5 Manhattanisgr8   Members   -  Reputation: 487

Like
0Likes
Like

Posted 15 January 2014 - 08:39 AM

control1.Link = control2; control2.Link = control1;

 

 

tried to implement using this example, however, it is telling me this:

Error    1    Inconsistent accessibility: field type 'ProjectSlam.EditGameWorldPanel' is less accessible than field 'ProjectSlam.EditWorld.EditWorldEditPanel.Link'    C:\Users\Travis\Google Drive\visual studio 2013\Projects\ProjectSlam\ProjectSlam\EditWorld\EditWorldEditPanel.cs    15

in Control1, I used the example you provided with the button delegate, and in Control2 I added public Control2 Link;

 

Control1

Spoiler

 

Control2

Spoiler

 

Form1

Spoiler

Cpl Alt, Travis A

USMC


#6 Nypyren   Crossbones+   -  Reputation: 4510

Like
1Likes
Like

Posted 15 January 2014 - 09:03 PM

That error usually occurs whenever the member is public but the class is not public.


It looks like you're having namespace issues:

The error says 'ProjectSlam.EditGameWorldPanel'

But your file says:
 
namespace ProjectSlam.MenuStripItems
{
    public partial class EditGameWorldPanel
This leads me to believe that your project contains at least one other file with a class EditGameWorldPanel, but which is in the ProjectSlam namespace instead.

Also be really careful with the "partial" classes. "partial" means there can be multiple files that define the class. If you change the namespace in one of those files but not the others, bad things can start happening.



ALSO, notice that the namespaces in your two files are different:
 
namespace ProjectSlam.MenuStripItems
{
    public partial class EditGameWorldPanel
namespace ProjectSlam.EditWorld
{
    public partial class EditWorldEditPanel : UserControl
BUT, nowhere in the EditWorldEditPanel are you using the MenuStripItems namespace.

This leads me to believe that you used Visual Studio's "Create Class" autocompletion which generated a private ProjectSlam.EditWorld.EditGameWorldPanel which is causing the compile error.



Visual Studio has a maddeningly annoying behavior where it names a new file's namespace based on the subfolder you create the file in. I hate this because it leads to issues like what you're seeing here.

Edited by Nypyren, 15 January 2014 - 09:11 PM.


#7 Manhattanisgr8   Members   -  Reputation: 487

Like
0Likes
Like

Posted 15 January 2014 - 10:48 PM

Ok, created a new project and tried to implement the link controls where they all use the same namespace. However, now I am getting this:

 

Error    1    Cannot implicitly convert type 'InterfacesTest.ListboxPanel' to 'InterfacesTest.Panel1'    c:\users\travis\google drive\visual studio 2013\projects\interfacestest\interfacestest\form1.cs    26
 

in Form1.


Cpl Alt, Travis A

USMC


#8 Nypyren   Crossbones+   -  Reputation: 4510

Like
1Likes
Like

Posted 15 January 2014 - 10:52 PM

That error is simple: You are trying to assign a value to the wrong type of variable. To fix it, you either use a different value, convert the value, or change the type of the variable. In this case it's probably just a typo.

But I'm not sure what you're trying to do without seeing your actual code.

Edited by Nypyren, 15 January 2014 - 10:54 PM.


#9 Manhattanisgr8   Members   -  Reputation: 487

Like
0Likes
Like

Posted 15 January 2014 - 10:58 PM

Form 1:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace InterfacesTest
{
    public partial class Form1 : Form
    {
        public Panel1 panel1 = new Panel1();
        public ListboxPanel listboxPanel = new ListboxPanel();
        public AddItems addItems = new AddItems();

        public Form1()
        {
            InitializeComponent();
            this.Controls.Add(panel1);
            this.Controls.Add(listboxPanel);
            this.Controls.Add(addItems);

            panel1.Link = listboxPanel.Link;
            listboxPanel.Link = panel1;
        }
    }
}

panel1 - first panel the user sees

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace InterfacesTest
{
    public partial class Panel1 : UserControl
    {
        public Panel1 Link;

        public Panel1()
        {
            InitializeComponent();
            this.Visible = false;

            button1.Click += delegate
            {
                if (Link != null)
                    Link.Visible = !Link.Visible;
            };
        }
    }
}

ListboxPanel

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace InterfacesTest
{
    public partial class ListboxPanel : UserControl
    {
        public ListboxPanel Link;

        public ListboxPanel()
        {
            InitializeComponent();
            this.Visible = false;

            button1.Click += delegate
            {
                if (Link != null)
                    Link.Visible = !Link.Visible;
            };
        }
    }
}

AddPanel - will be used to add items to listbox in ListboxPanel

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace InterfacesTest
{
    public partial class AddItems : UserControl
    {
        public AddItems Link;

        public AddItems()
        {
            InitializeComponent();
            this.Visible = false;

            button1.Click += delegate
            {
                if (Link != null)
                    Link.Visible = !Link.Visible;
            };
        }
    }
}

Hope this helps, didn't add the other .designer.cs of the classes that VS uses for the design


Cpl Alt, Travis A

USMC


#10 Nypyren   Crossbones+   -  Reputation: 4510

Like
1Likes
Like

Posted 15 January 2014 - 11:07 PM

OK, now I can see what you're doing.

In my original example with the Links, both of my panels are the same type. This is where your code is different.

The type of your Link members need to be changed. Right now, you have it set up so that they can only refer to another instance of the *same type*. But your panels are actually different types. The Link members need to use the types that you want them referring TO, which is not necessarily the same type as the class they're in.

#11 Manhattanisgr8   Members   -  Reputation: 487

Like
0Likes
Like

Posted 15 January 2014 - 11:22 PM

How would I go around this? I tried to implement your second example, however, instead of setting the list, I tried to set the visibility of another panel, and that didn't work.

 


control1.ButtonClicked += delegate { control3.SetList(list1); }; control2.ButtonClicked += delegate { control3.SetList(list2); };

Cpl Alt, Travis A

USMC


#12 Nypyren   Crossbones+   -  Reputation: 4510

Like
1Likes
Like

Posted 16 January 2014 - 12:57 AM

Did you fix the things that I suggested? Or do you need to know exactly which lines to change?

If you've fixed them yourself, then I see another problem that will prevent the program from working nicely:
 
this.Controls.Add(panel1);
this.Controls.Add(listboxPanel);
this.Controls.Add(addItems);
That adds the controls, but you haven't set their position!

By default, the position of a control is 0,0 - the upper left corner of the control or form that contains it. Also, UserControls have a default size of 100x100 when you make them in the form designer.

So, my guess is that all of your panels are overlapping on top of each other right now, which will make it hard to tell if any of them are actually changing visibility or not.

In my examples, you can see that in a few places I set the Left, Top and sometimes the Width and Height of certain things. I've done this to make sure that they aren't placed on top of each other.

Left is the X position of the left edge of a control, relative to its parent. You can set this.
Top is the Y position of the top edge of a control, relative to its parent. You can set this.

"Parent" in this case means the control or form that you've added it to. In fact, 'Parent' is an actual property of controls that you can use in your code.

Right and Bottom are read-only. You can get their values but you can't set them.

Width and Height can be set. When you change them, Right and Bottom will reflect the changes.

Edited by Nypyren, 16 January 2014 - 01:09 AM.


#13 Manhattanisgr8   Members   -  Reputation: 487

Like
0Likes
Like

Posted 16 January 2014 - 01:49 PM

Which lines do I change? All the initializing of the buttons are in the classxx.deigner.cs portion of the panel.

Cpl Alt, Travis A

USMC


#14 Nypyren   Crossbones+   -  Reputation: 4510

Like
1Likes
Like

Posted 16 January 2014 - 03:06 PM

You're going to need to learn how to figure this stuff out on your own.  Perhaps find a good WinForms-in-C# book. But here are the lines you need to change:

In Form1:
//panel1.Link = listboxPanel.Link;
panel1.Link = listboxPanel;
In Panel1:
//public Panel1 Link;
public ListboxPanel Link;
In ListboxPanel:
//public ListboxPanel Link;
public Panel1 Link;
In AddItemsPanel:
 
//public AddItems Link;
// I have no idea what you're planning to do with this.
Your compiler has been giving you helpful error messages so far, which you need to learn how to understand. If you don't understand an error, type in its "error CS####" code into google for a more detailed explanation. This should help you to figure out what the error means, and sometimes the results will contain examples showing what's wrong and how to fix it. You can find the "error CS####" in the "Output" window of Visual Studio (They are not shown in the Error List window.)

Both the compiler and I have already explained several times why these need to be changed. I may hang around for a little while longer but I think you need to find someone with more patience than I have to help you out.

Edited by Nypyren, 16 January 2014 - 03:12 PM.


#15 Manhattanisgr8   Members   -  Reputation: 487

Like
1Likes
Like

Posted 16 January 2014 - 10:16 PM

I figured it out, thank you for your help and patience.


Cpl Alt, Travis A

USMC





Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS