• Announcements

    • khawk

      Download the Game Design and Indie Game Marketing Freebook   07/19/17

      GameDev.net and CRC Press have teamed up to bring a free ebook of content curated from top titles published by CRC Press. The freebook, Practices of Game Design & Indie Game Marketing, includes chapters from The Art of Game Design: A Book of Lenses, A Practical Guide to Indie Game Marketing, and An Architectural Approach to Level Design. The GameDev.net FreeBook is relevant to game designers, developers, and those interested in learning more about the challenges in game development. We know game development can be a tough discipline and business, so we picked several chapters from CRC Press titles that we thought would be of interest to you, the GameDev.net audience, in your journey to design, develop, and market your next game. The free ebook is available through CRC Press by clicking here. The Curated Books The Art of Game Design: A Book of Lenses, Second Edition, by Jesse Schell Presents 100+ sets of questions, or different lenses, for viewing a game’s design, encompassing diverse fields such as psychology, architecture, music, film, software engineering, theme park design, mathematics, anthropology, and more. Written by one of the world's top game designers, this book describes the deepest and most fundamental principles of game design, demonstrating how tactics used in board, card, and athletic games also work in video games. It provides practical instruction on creating world-class games that will be played again and again. View it here. A Practical Guide to Indie Game Marketing, by Joel Dreskin Marketing is an essential but too frequently overlooked or minimized component of the release plan for indie games. A Practical Guide to Indie Game Marketing provides you with the tools needed to build visibility and sell your indie games. With special focus on those developers with small budgets and limited staff and resources, this book is packed with tangible recommendations and techniques that you can put to use immediately. As a seasoned professional of the indie game arena, author Joel Dreskin gives you insight into practical, real-world experiences of marketing numerous successful games and also provides stories of the failures. View it here. An Architectural Approach to Level Design This is one of the first books to integrate architectural and spatial design theory with the field of level design. The book presents architectural techniques and theories for level designers to use in their own work. It connects architecture and level design in different ways that address the practical elements of how designers construct space and the experiential elements of how and why humans interact with this space. Throughout the text, readers learn skills for spatial layout, evoking emotion through gamespaces, and creating better levels through architectural theory. View it here. Learn more and download the ebook by clicking here. Did you know? GameDev.net and CRC Press also recently teamed up to bring GDNet+ Members up to a 20% discount on all CRC Press books. Learn more about this and other benefits here.
Sign in to follow this  
Followers 0
Manhattanisgr8

having a couple of problems with Windown Forms

14 posts in this topic

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.

0

Share this post


Link to post
Share on other sites
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
2

Share this post


Link to post
Share on other sites
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
1

Share this post


Link to post
Share on other sites
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
1

Share this post


Link to post
Share on other sites

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]

namespace ProjectSlam.MenuStripItems
{
    public partial class EditGameWorldPanel : UserControl
    {
        public EditGameWorldPanel Link;

        public EditGameWorldPanel()
        {
            InitializeComponent();
            this.Visible = false;
            this.Dock = DockStyle.Fill;
            createWorldInfoLabel.Visible = false;
            editInfoLabel.Visible = false;
            clearInfoLabel.Visible = false;
            createPictureInfoLabel.Visible = false;
            editGameWorldButton.Click += delegate
            {
                if (Link != null)
                    Link.Visible = !Link.Visible;

            };
        }

[/spoiler]
 

Control2

[spoiler]

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 ProjectSlam.EditWorld
{
    public partial class EditWorldEditPanel : UserControl
    {
        public EditGameWorldPanel Link;

        public EditWorldEditPanel()
        {
            InitializeComponent();
            this.Dock = DockStyle.Fill;
            this.Visible = false;
        }

[/spoiler]

 

Form1

[spoiler]

namespace ProjectSlam
{
    public partial class MainForm : Form
    {
        private MyMenuStrip menuStrip;
        private MenuStripItems.EditGameWorldPanel editGameWorldPanel;
        private DataLink.DataLinks dataLink;
        public static EditWorld.EditWorldPPVPanel editWorldPPV = new EditWorld.EditWorldPPVPanel();
        public EditWorld.EditWorldEditPanel editWorldEditPanel = new EditWorld.EditWorldEditPanel();
        public static EditWorld.EditWorldPPVSelectionPanel editWorldPPVSelectionPanel;
        public static List<UserControl> userControls = new List<UserControl>();
        private EditWorld.EditWorldPPV editPPV = new EditWorld.EditWorldPPV();

        public MainForm()
        {
            LoadDatabases();
            System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainForm));
            InitializeComponent();
            editGameWorldPanel = new MenuStripItems.EditGameWorldPanel();
            editWorldPPVSelectionPanel = new EditWorld.EditWorldPPVSelectionPanel();
            menuStrip = new MyMenuStrip();
            this.Controls.Add(menuStrip);
            this.Controls.Add(editGameWorldPanel);
            this.Controls.Add(editWorldPPV);
            this.Controls.Add(editWorldEditPanel);
            this.Controls.Add(editWorldPPVSelectionPanel);
            menuStrip.Renderer = new MyRenderer();
            BackgroundImage = Globals.background;

            editGameWorldPanel.Link = editWorldEditPanel;
            editWorldEditPanel.Link = editGameWorldPanel;


            // Set menu clicks
            menuStrip.exit.Click +=exit_Click;
            menuStrip.editGameWorld.Click += editWorld_Click;
            menuStrip.deleteGameWorld.Click += deleteGameWorld_Click;
        }

[/spoiler]

0

Share this post


Link to post
Share on other sites
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
1

Share this post


Link to post
Share on other sites

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.

0

Share this post


Link to post
Share on other sites
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
1

Share this post


Link to post
Share on other sites

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

0

Share this post


Link to post
Share on other sites
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.
1

Share this post


Link to post
Share on other sites

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); };
0

Share this post


Link to post
Share on other sites
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
1

Share this post


Link to post
Share on other sites
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
1

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0