Rules to Better Interfaces (WinForms Controls)
Controls - Do you include '-All-' option in your ComboBoxes?
ComboBoxes are often used for filtering data. It is best to have an '-All-' option to give your user chances to select all data.
It is important to understand the idea of visual text . In a list you could see either:
- -None- or
- No activity assigned
They both have the same meaning, but the first one is immediately visible whereas the second one must be read.
If the ID column in your database is a string data type, it is useful to add a constraint to limit the types of characters that it can contain. Adding a constraint can make it simpler to build your front-end, as you won't need to worry about encoding or escaping to handle special characters.
In SQL Server, you can add a check constraint that limits your column to alphanumeric characters, a hyphen, or underscore using the following T-SQL:
ALTER TABLE [TableName] ADD CONSTRAINT CK_String_IdentifierCHECK ([StringIdColumn] NOT LIKE'%[^a-zA-Z0-9_\-]%')❌ Figure: Bad example - No '-All-' option so the user cannot select all data
✅ Figure: Good example - Having an '-All-' option gives a user a chance to select all data
Also, keep it simple!
❌ Figure: Bad example - '-All Stores-' isn't needed
✅ Figure: Good example - Keep it as a simple '-All-'
✅ Figure: Good example - Keeping it simple makes it easy to spot (that there is no filter) when you have multiple fields.
Read our rule on Always make sure the dimensions All Captions = All.
Controls - Do you include the number of results in ComboBoxes?
When designing your form, you should try to help your user whenever it's possible. So it's a good idea to include the number of results in ComboBoxes.
For Windows Forms
❌ Figure: Bad example - You can't tell the number of results and there is a scroll bar
✅ Figure: Good example - The number of results is clearly displayed. Long text boxes larger than 30 entries, another approach can be employed - putting the common ones at the top
❌ Figure: Bad example - Firstly because it is manual, plus what about the 4th, 5th, etc most common used countries
❌ Figure: Bad example – This was a highly unpopular method of the sorting and counting above
We believe all combos should be able to be sorted ascending/descending and by popularity asc/desc.
✅ Figure: Good example - A better way to sort this
Control Choice - Do you use GridView over the CheckedListBox?
In Web we have:
In Windows Forms we have a CheckedListBox. With a CheckedListBox you cannot:
- Sort data - always useful when there are more than about 20 rows
- Contain much information - can only show one field
- DataBind - always costs heaps of code
❌ Figure: Bad Example - The CheckedListBox is limited
✅ Figure: Good Example - The DataGrid can show much more information (and if you use a 3rd Party eg. Telerik, then it can be pretty too)
In Windows Forms, the code of DataGrid databinding is easier than that of CheckedListBox.
ProductsService.Instance.GetAll(Me.ProductsDataSet1) CheckedListBox1.DataSource = Me.ProductsDataSet1.Tables(0) CheckedListBox1.ValueMember = "ProductID" CheckedListBox1.DisplayMember = "ProductName" For i As Integer = 0 To CheckedListBox1.Items.Count - 1 Dim checked As Boolean = CType(ProductsDataSet1.Tables(0).Rows(i)("Discontinued"), Boolean) CheckedListBox1.SetItemChecked(i,checked) Next Figure: 8 lines of code to fill a CheckedListBox ProductsService.Instance.GetAll(Me.ProductsDataSet1) Figure: One line of code to fill a DataGrid But the CheckedListBox is useful if only one field needs displaying.
Control Choice - Do you use a GridView (over the ListBox)?
A GridView provides much richer features than ListBox, you can easily add a checkbox onto the header to allow "check all" functionality, which is impossible for ListBox.
❌ Figure: Bad Example - Use the ListBox.
✅ Figure: Good Example - Use GridView and add the enabled checkbox on the header
Control Choice - Do you use ListView over GridView (was DataGrid) for ReadOnly? (Windows Forms only)
<introEmbed body={<> Yes a ListView looks nicer than a DataGrid, but a Datagrid is better because it has more functionality (out of the box that is). With a ListView you cannot: - Copy and paste - although you can select a row of data in both controls, you can't copy and paste a whole row from the ListView - Sort data - always useful when there are more than about 20 rows - DataBind - always saves heaps of code </>} /> So our old rule was to always use the ugly DataGrid (although we were never happy about that). <imageEmbed alt="Image" size="large" showBorder={false} figureEmbed={{ preset: "badExample", figure: 'Bad Example - The DataGrid is ugly', shouldDisplay: true }} src="/uploads/rules/control-choice-do-you-use-listview-over-gridview-was-datagrid-for-readonly-windows-forms-only/../../assets/UsingDataGridWhenNotNeeded.gif" /> <imageEmbed alt="Image" size="large" showBorder={false} figureEmbed={{ preset: "goodExample", figure: 'Good Example - A beautiful ListView - a nicer look over the datagrid', shouldDisplay: true }} src="/uploads/rules/control-choice-do-you-use-listview-over-gridview-was-datagrid-for-readonly-windows-forms-only/../../assets/SortableListView.gif" /> So the listview looks nicer? If you are not convinced here is another one: <imageEmbed alt="Image" size="large" showBorder={false} figureEmbed={{ preset: "goodExample", figure: 'Good Example - The appearance of DataGrid and ListView', shouldDisplay: true }} src="/uploads/rules/control-choice-do-you-use-listview-over-gridview-was-datagrid-for-readonly-windows-forms-only/../../assets/DatagridVSListview.gif" /> But another issue is how much code to write... For ListView you will need to write a bit of code to fill the list view... this.listView1.Items.Clear(); // stops drawing to speed up the process, draw right at the end. this.listView1.BeginUpdate(); foreach(DataRow dr in this.dataSet11.Tables[0].Rows) { ListViewItem lvi = new ListViewItem(new string[] {dr[0].ToString(),dr[1].ToString(),dr[2].ToString()}); lvi.Tag = dr; this.listView1.Items.Add(lvi); } this.listView1.EndUpdate(); Figure: 8 lines of code to fill a ListView But the datagrid is nicer to code... this is because it comes with data binding ability. // bind it in the designer first. this.oleDbDataAdapter1.Fill(this.dataSet11); Figure: One line of code to fill a DataGrid But the SSW ListView (included in the [.NET Toolkit](http://www.ssw.com.au/ssw/NETToolkit/)) is nicer to code with as it comes with data binding ability. // bind it in the designer first. this.oleDbDataAdapter1.Fill(this.dataSet11); Figure: One line of code to fill the SSW ListView So what is this SSW ListView? It is an inherited control that how we implemented the ListView to give us what MS left out. - DataBinding - Sorting So now the rules are: Always use the SSW ListView. Exception: Use the DataGrid when: - When not read only - i.e. users will be editing data directly from the cells. - You need more than 1 column with checkboxes, or the column with checkboxes can't be the first column. E.g.: <imageEmbed alt="Image" size="large" showBorder={false} figureEmbed={{ preset: "default", figure: 'One place when you choose a DataGrid over a ListView is when you have 2 checkbox fields', shouldDisplay: true }} src="/uploads/rules/control-choice-do-you-use-listview-over-gridview-was-datagrid-for-readonly-windows-forms-only/../../assets/DataGrid2CheckBoxes.gif" /> So in summary, if you don't want users to edit the data directly from the cell, and only the first column need checkboxes, then the ListView is always the better choice. | We have an example of this in the [SSW .NET Toolkit](http://www.ssw.com.au/ssw/NETToolkit/). | | -------------------------------------------------------------------------------------------- | | We have a program called [SSW Code Auditor](http://www.ssw.com.au/ssw/CodeAuditor/) to check for this rule. | | ----------------------------------------------------------------------------------------------------------- | Note: We have a suggestion for Microsoft to improve the [copy and paste format from a gridview](http://www.ssw.com.au/ssw/Standards/BetterSoftwareSuggestions/MSForm.aspx#DataGridsFormattingonCopy)
Control Choice - Do you avoid using Group Box and use a line to organize your form?
Group box should only be used when you want to notify the user the controls within it are really related, such as radio buttons.
❌ Figure: Bad Example - Inappropriate use of 'Group Box', there is nothing to be grouped
✅ Figure: Good Example - Use a line to organize different sections
✅ Figure: Good Example - VS.NET 2003 Options form, appropriate use of 'Group Box', the radio buttons are related to each other
✅ Figure: Good Example - VS.NET 2012 Options form, also appropriate use of 'Group Box'
In other cases, you should avoid using group box and replace it with a simple line, this will save you some space on the form and help you organize your form more easily.
Control Choice - Do you know when to use options group Radio Buttons instead of ComboBox?
When the options are static items (not database driven) and they can fit on the screen (about 2-5 items), they should be radio buttons.
For a ComboBox, user needs 2 clicks to change the value:
- Click the ⌄ button to see the available options
- Then click the option to select
For an options group, user can see all the available options without clicking, and select the option with just a click.
❌ Figure: Bad example - ComboBox is used for "Job Type" where it contains only 2 options
✅ Figure: Good example - Radio Buttons are used and aligned vertically
Controls - Do you use a ToolTip to show the full text of hidden ListView data?
When you can't see all the text for an item in a ListView you need to expose the full text via a ToolTip.
❌ Figure: Bad example - Users can't see all the text and the ListView doesn't use a Tooltip
✅ Figure: Good example - Users can't see all the text, but the ListView shows all the text via a Tooltip
The code to do this is:
private ListViewItem hoveredItem;private void listView1_MouseMove(object sender, MouseEventArgs e) {ListView lv = (ListView) sender;ListViewItem item = lv.GetItemAt(e.X, e.Y);int columnIndex = 1;if (item != hoveredItem) {hoveredItem = item;if (item == null) {toolTip1.SetToolTip(lv, "");} else {// Make sure the mouse hovered row has the subitemif (item.SubItems.Count > columnIndex) {toolTip1.SetToolTip(lv, item.SubItems[columnIndex].Text);} else {toolTip1.SetToolTip(lv, "");}}}}Controls - Do you make the selected/enabled rows stand out in a datagrid?
Many times you allow a multiple selection in a grid by using a checkbox. When you do this make it easy to see the distinction of a row that is selected and one that is not. Make it subtle by dimming the unselected text.
❌ Figure: Bad example - Selected rows are not separate from others
✅ Figure: Good example - Selected rows are separate from others
To make this effect in datagrid, you may need to edit the cellcontentclick event handler code. Example:
private void DatagridviewRules_CellContentClick(object sender, DataGridViewCellEventArgs e) {if (DatagridviewRules.Columns[e.ColumnIndex] is DataGridViewCheckBoxColumn && e.ColumnIndex == 0 && e.RowIndex != -1) {bool boolCheckBox = (bool)(DatagridviewRules.Rows[e.RowIndex].Cells[e.ColumnIndex].Value);DatagridviewRules.Rows[e.RowIndex].DefaultCellStyle.ForeColor = boolCheckBox ? SystemColors.WindowText : SystemColors.ControlDark;DataRowView objDataRowView = (DataRowView) DatagridviewRules.Rows[e.RowIndex].DataBoundItem;JobRule.DataTableJobRulesRow objDataRow = (JobRule.DataTableJobRulesRow)(objDataRowView.Row);updateRuleIsEnabled(objDataRow.RuleId, boolCheckBox);updateSelectAllCheckBox();updateRulesCount();}}Setting the ForeColor to different ones, like black and gray, can separate the selected rows from others.
Controls - Do you extend the size of your ComboBoxes to show as many results as possible? (Windows Forms Only)
When designing your form, it's a good idea to help your user whenever it's possible. So it's a good idea to extend your ComboBoxes to show as many results as possible to save your user from scrolling. Also, you should extend the width of the dropdown in order to show the longest items.
However, you should not extend your ComboBox without limit, normally the maximum number of items should be under 10 and the maximum width of the drop-down should be smaller than your hosting form.
❌ Figure: Bad example - You have to scroll to see all the result, and the long results are cut off
✅ Figure: Good example - The size of the drop down has been extended to allow user to see as much as possible
Changing the maximum items is easy, just include the following code in your form:
cbxOUList.MaxDropDownItems = cbxOUList.Items.Count;// Changing the drop down size is a bit of trickyGraphics g = Graphics.FromHwnd(this.Handle);SizeF stringSize = new SizeF();stringSize = g.MeasureString(longString, cbx.Font, 600);int adjustedSize = cbx.DropDownWidth;if (adjustedSize < (int) stringSize.Width) {adjustedSize = (int) stringSize.Width;}cbx.DropDownWidth = adjustedSize;Controls - Do you use Text Boxes for displaying data?
Use Label controls to display static text of the application. Eg. "Customer ID:" Use Text Box controls to display data (results of calculations, information, records from a database, etc.).
The reasons are:
- users know it is data, not a label of the application
- users can copy and paste from the field
PS: One reason web UI's are nice, is that the information is always selectable/copyable.
❌ Figure: Bad Example - Not only is the data cut off when you are using label, but you can't copy and paste the value
✅ Figure: Good Example - Using Textbox controls makes the data obvious to users
As you can see you'll barely know the difference, so start using Textboxes for displaying data, that's good practice.
More Information
When using TextBox controls in Windows Forms, set them up like this:
Figure: Having the 'BorderStyle' Property set to Fixed3D is the best choice visually
Figure: Make the text box Read-Only (users copying data is OK, changing is silly)
Connection Stream - Do you use a UDL when getting database settings?
Why do people always invent ways of getting the same old server name and a database name? Look at this image from Speed Ferret - one of my favorite SQL Server utilities.
❌ Figure: Bad Example - Custom database connection screen in Speed Ferret
While a nice form, it would have taken quite some developer time to get it right. Not only that, it is a little bit different than what a user has seen before. Now look at this UDL from one of our utilities SSW SQL Auditor:
✅ Figure: Good Example - Standard Microsoft UDL dialog
Every developer has seen this before - so use it. Better still, it is only a few lines of code: B-Open UDL Dialog-DH.txt
Figure: Coming in Visual Studio .NET 2005 Microsoft are yet to release an API to do this
Exception
The above cannot be used when you want the user to create a new database. Microsoft does not supply an out of the box UI and there is no third party solution. Only in this case you have to create your own form.
Figure: SQL Deploy uses its own custom form for "selecting" a database name
Being Pedantic - Do your buttons have a mnemonic?
<introEmbed body={<> A mnemonic for a button is the letter which has an underscore, and the user can press the button using `Alt-<char>`. </>} /> <imageEmbed alt="Image" size="large" showBorder={false} figureEmbed={{ preset: "badExample", figure: 'Bad example - All buttons without Mnemonic', shouldDisplay: true }} src="/uploads/rules/being-pedantic-do-your-buttons-have-a-mnemonic/../../assets/BadMem.gif" /> <imageEmbed alt="Image" size="large" showBorder={false} figureEmbed={{ preset: "goodExample", figure: 'Good example - All buttons with Mnemonic - user can easily choose which button they want without a click', shouldDisplay: true }} src="/uploads/rules/being-pedantic-do-your-buttons-have-a-mnemonic/../../assets/GoodMem.gif" /> In Windows Applications, it is quite easy to assign a mnemonic to a button with the "&" character. So for the case above, the text would be: ```cs btnAbout.Text = "&About" ``` <asideEmbed variant="info" body={<> Learn more about the [Mnemonic property on Windows Desktop](https://learn.microsoft.com/en-us/dotnet/api/system.windows.forms.label.usemnemonic?view=windowsdesktop-7.0&WT.mc_id=WDIT-MVP-33518). </>} figureEmbed={{ preset: "default", figure: 'XXX', shouldDisplay: false }} />
Controls - Do you indicate when fields are "read only" or "calculated"?
When you are not able to edit a field the field should be greyed out. This visually indicates to the user that the field cannot be changed.
If you are using Word or Excel, actually locking cells or tables may not be what you require, but you still want to prevent people from directly editing calculations. So make the cells grey and the visual indication should prompt the users what to do.
✅ Figure: Good Example - Read only fields should be greyed out
✅ Figure: Good Example - Calculated Fields in Excel should be in Grey
Of course you should follow the converse, which requires making all editable fields white.
Controls - Do you set row select mode as "FullRowSelect" for DataGridView if it is read only? (Windows Forms Only)
If you use the DataGridView control which is read only, you had better set row select mode as "FullRowSelect". If the data cannot be modified we can let users select the whole row instead of one column.
❌ Figure: Bad Example - Row select mode is not "FullRowSelect".
✅ Figure: Good Example - Row select mode is "FullRowSelect".
Figure: Changed row select mode to FullRowSelect.
What's the next step? It's even better if you enable multiple row selection and copying, see Do your List Views support multiple selection and copying on Rules to Better Windows Forms Applications.
Being Pedantic - Do you use balloon tooltip?
The standard tooltip is a rectangle, so the tool tip for the control can be misleading. While, the balloon tooltip has an arrow pointing to the destination control, which is clearer for users.
❌ Figure: Standard tooltip.
✅ Figure: Balloon tooltip.
To implement you can:
- Set the standard Tooltip's property IsBalloon true or
- Use EdwardForgacs' balloon tooltip control.
Do your controls autopostback?
When visitors are navigating through your site and they need to make a selection from a control with fixed values, it is best to have the control automatically post back. This makes navigating your site quicker as the user does not have to click other buttons to see the changes which they have made. It is also important to remember that controls which do not have set values, such as text boxes, should have a "Show" button available to click once the visitor is finished entering their data.
❌ Figure: Bad Example - because the combos can be set to autopostback and should not have a "Show" button.
✅ Figure: Good Example - because the combo boxes have fixed values and can autopostback.
❌ Figure: Bad Example - because the text boxes do not have fixed data and thus should have a "Show" button.
✅ Figure: Good Example - because there is a "Show" button as the text boxes do not contained fixed data.
✅ Figure: Good Example - because the combos can be set to autopostback while the text boxes have the "Show" button available.