I’ve just realized there is no working solution in C# on how to programatically select cells across a dataGridView.

What I needed was a quick, simple and easy solution on the next behaviour: a user clicks a cell (any kind of cell: may it be a textBox cell, a checkBox cell, a comboBox cell etc.), the cell gets selected, the user clicks another cell, both the new cell and the previous cell are selected, the user click the first cell again, only the second cell is selected.

How I’ve done this? Well, first, it’s important to keep in mind that the events occur like this: CellMouseDown, CellClick, CellContentChanged, CellMouseUp, SelectionChanged. Sure, there are so many other events as well, but it’s important that you use only the CellContentChanged and the SelectionChanged events. Moreover, be aware, that if you try using the CellClick event, you won’t get this desired behaviour :).

What’s more to add, please keep in mind that you will have the MultiSelect property set to True. It would be also nice to have the SelectionMode set to CellSelect, so you don’t need to take care of several exceptions that could occur if you select the entire row/column by clicking on the column header or row header.

So:

– first, declare a System.Collections.ArrayList arrayList = new System.Collections.ArrayList(); This is where you will save a list of all of your selected cells. Sure, it would be nice to save the SelectedCells collection of the DataGridView, but that collection is obviously read-only. Otherwise, I probably wouldn’t even have this post :P.

– second, in the SelectionChanged event, do this:

foreach (DataGridViewCell arrayElement in arrayList)
{
arrayElement.Selected = true;
}

And in the CurrentCellChanged, do the following:

if (dataGridView1.CurrentCell != null)
{
label1.Text = (dataGridView1.CurrentCell.RowIndex + 1).ToString() + ” ” + (dataGridView1.CurrentCell.ColumnIndex + 1).ToString();
if (arrayList.Contains(dataGridView1.CurrentCell))
{
arrayList.Remove(dataGridView1.CurrentCell);
dataGridView1.CurrentCell.Selected = false;
}
else
{
arrayList.Add(dataGridView1.CurrentCell);
dataGridView1.CurrentCell.Selected = true;
}
}

This is basically it. Now, there is a thing about this code. The thing is that is you click on a column header, in order to re-sort the column, you’ll have a rather strange “error”: your last selected cell will get de-selected. If you re-sort the column again, the cell will be selected again. The fault of this occurrence is due to the way the events are called. Basically, when you click the header, the CurrentCellChanged is called for a first time, since you clicked the header (so, dataGridView.CurrentCell will be null). Afterwards, the CurrentCellChanged is automatically called again, because current cell’s position is moved (so the event is called for some reason…).

There are several ways to get along with this thing; I’ll let you find your own solution, since:

  1. I for one, needed NonSortable columns
  2. I needed the column headers hidden

Alex M.

It’s not that I didn’t know this for such a long time, but today I’ve just realized that there are so many questions regarding automatic application launching.

So, leaving the startup process aside, once WinCE has loaded, the system loads all the applications specified in the HKLMInit registry key, with the values of LaunchXX. The XX stand for a integer value between 00 and 99 (this means that 1 should be coded as 01). The XX values actually represent the sequence that applications are launched (so 00 will be launched first, 01 second etc.). It is good to keep in mind that the system will not wait for an application to ‘fully’ start. This means that it will generate an interruption for each and every application in the Init key, in a specified sequence, without creating a delay or a timeout between any two consecutive applications in the sequence. This is good since it means that application launching cannot create any kind of system hangs (at least in theory).

However, it is sometimes necessary to create a dependency between applications (application MyShell.exe cannot start – in the developer’s point of view – without running Shell.exe, since, for example, it is using some variables generated by Shell.exe). Therefore, a DependXX value can be used, where XX should match the value in the LaunchXX key where the dependecy is specified.

LaunchXX contains a value of the REG_SZ type which must be the name of the program that needs to be launched, such as MyShell.exe, without the parameters. Again, the XX value determines the load order.

DependXX contains a value of the REG_BINARY type, which enables you to determine the dependency of applications on other applications during the load by specifying which applications must be loaded prior to the application specified in the corresponding LaunchXX key. The indexes of XX applications that a given application is dependent on are specified as a lists of words with a reverse byte order. It is important to keep in mind that a word is (as usual) 2 bytes long.

The application specified in the Init registry key must inform the system that it has loaded successfully and the dependent applications can be loaded by calling the SignalStarted() function with a parameter that it is passed to by the system as a command line parameter
during the load.

An example of the Init registry key is shown below:

[HKEY_LOCAL_MACHINEInit]
“Launch10”=“shell.exe”
“Launch20”=“device.dll”
“Depend20”=“hex:0a,00”
“Launch30”=“gwes.dll”
“Depend30”=“hex:14,00”
“Launch50”=“MyShell.exe”
“Depend50”=“hex:14,00, 1e,00”

In this case, the shell.exe application launches first, then it loads the Device Manager (device.dll), which depends (in the example) on shell.exe, then it loads gwes.dll, which is dependent on the Device Manager, and finally, MyShell.exe, which depends on both the Device Manager (device.dll) and gwes.dll.

Normally, setting up the startup options is something you would do on OS image building. However, in case you can’t do this before building the image, and considering you are using a Hive-based registry, it is ok if you use a Registry Editor or a Remote Regustry Editor (like the one over KITL) and update the registry ‘manually’.

Word of advice: always be sure to double-check the launch sequence! It is possible that certain BSP features or drivers are already in the sequence and required by the your OEM. Using the same XX value twice in a sequence may cause system crash or system ‘hang’. In case you want to auto-launch only one application (your main application for the system), it is probably best to assign it the 99 value (in case it’s free :-)).

That should be it for now! Comments are very welcome!

Alex

I have had some trouble changing the ScrollBar’s width in an application I’ve been asked to modify. Obviously, the first thing to do was to search for a Size property for the panel’s scroll bar. Just as expected, there wasn’t any. What could I do more? Surely Google (or Bing…) would have the answer!

But surprise! No good answer on the first 6 pages that Google showed up. So I started checking the Components toolbox again, and there it was: VScrollBar.

It is probably the best way to have a larger scroll bar in your application, since this component has a Size property. Linking the component to the form or panel you want to scroll is as easy as enabling the component’s Scroll event and writing down

panelName.VerticalScroll.Value = vScrollBar.Value;

Now, if you want to be 100% sure about how the scroll bar looks like, simply set the component’s Maximum property to the difference of the panel’s length (should I call it height), and the portion of the panel that is not showed (the one that should be scrolled for…).

In the end, I suggest you use a panel, for easier and safer usage of the vScrollBar.

Hope the post is clear enough. If not, don’t hesitate to ask your question in a comment.

Alex.