Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Content-driven Input Dialog

0.00/5 (No votes)
20 Nov 2015 2  
Self configuring input dialog box for quick data collection in a Windows Forms solution.

Introduction

Have you ever needed to collect simple information in an application that needs more than MessageBox? Developers can spend hours coding different forms for each data instance. This solution, InputDialog, will take a single, simple data type, or a more complex class, and display a form that can collect the information for the user and return an updated data object.

Each data type's input is restricted to valid values.

You can use both simple and more complex data types, as show by these samples:

    

Using the code

Simple Method Call

To just get a string (like in the small sample above) code:

string s = "";
if (InputDialog.Show("What is your name?", "", ref s) == DialogResult.OK)
{
   // Do something with the 's' variable
}

Collecting more items can be done by passing in a class or structure. For example to get the larger sample above:

public class A
{
   public enum AGender { Female, Male };
   
   public string Name { get; set; }
   public int Age { get; set; } = 25;
   public bool Married { get; set; }
   public AGender Gender { get; set; }
}

public void CollectA()
{
   A a = new A();
   InputDialog.Show("Please provide some basic information:", "Personal Info", ref a,
      SystemIcons.Information.ToBitmap());
}

Component

If you're more of a visual coder, you can add this InputDialog.cs file into your project and then you should see an InputDialog item in your toolbox.

Adding this component to your form will place an item in the component tray:

You can then look over at the Properties panel and make changes there:

Calling this from your form would then be as simple as:

int data = 100;
inputDialog1.Data = data;
if (inputDialog1.ShowDialog(this) == DialogResult.OK)
   data = (int)inputDialog1.Data;

And you get:

Control display using Attributes

If using a class or structure, you can even control the label and display order using the InputDialogItem attribute:

public class A
{
   public enum AGender { Female, Male };
   
   [InputDialogItem(Hidden = true)]
   public bool unshownSetting = true;

   [InputDialogItem("Full name", Order = 0)]
   public string Name { get; set; }
   [InputDialogItem(Order = 1)]
   public int Age { get; set; } = 25;
   public bool Married { get; set; }
   [InputDialogItem(Order = 2)]
   public AGender Gender { get; set; }
}

All public fields and properties will be shown until they have the InputDialogItem.Hidden property set to 'true'.

The order is somewhat arbitrary as reflection is used to gather those values. To specify the order, set the InputDialogItem.Order property. Any ordered items will proceed unordered items.

By default, the label for each item is the name of the field or property. To change it, use the first parameter of the InputDialogItem attribute and set it to the value you desire (like the Name property above).

The class above will produce this dialog:

Support for multiple types

All of the following types are supported as members of a class or structure or as stand-alone objects:

Boolean, Byte, SByte, Int16, UInt16, Int32, UInt32, Int64, UInt64, IntPtr, UIntPtr, Char, Double, Single, Enum, Decimal, DateTime, String, TimeSpan and Guid

Each will show an error if the user tries to add an invalid string and each prevents typing unsupported characters.

Lessons Learned

Using Reflection

To accomplish this input dialog, I'm of course using reflection. I determine the type of the object passed in and then use the various methods and properties of the Type class to decide how to build out the UI.

Since many of the types are actually structures or primitive types, I needed to pass in the value as a reference so I can change its value upon a successful return.

The nasty science of TableLayoutPanel

I wish I could say I spent most of my time coding. No. I spent most of my time debugging the strange machinations of the TableLayoutPanel. What did I learn?

  1. The Margin of the control inside the cell is very important. If the Margin is all zeros, then the control is treated differently than if there isn't a control. If the Margin has a value, the entire row or column is affected.
  2. Setting MinimumSize and MaximumSize are oftent the only ways to ensure the size of a cell.
  3. Getting a label to break rows is hard. Internally, it has the right answers for sizing, but fails to apply them.
    1. Set AutoSize = true and Dock = DockStyle.Top
    2. After label is added to the table, set its MinimumSize = Size if its Width < PreferredWidth

Cool event handling shortcuts

Ever need to handle an event but too lazy to build out the handler? Try this:

TextBox tb = new TextBox();
tb.Enter += (s, e) => tb.SelectAll()

This will cause the text in a TextBox to be selected whenever the control is entered.

History

11 Nov 2015 - Initial posting

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here