Archive for category Winforms

C#: How to Load a Winform ComboBox or ListBox and have a Unique Value Associated with the Selected Item

ComboListBox When loading a list box or a combo box drop down in a Winform most developers can use the Items property of the Add method to get the individual textual items to be chosen. The problem comes in later when the developer needs to get certain information beyond the text of the item itself. They need to tag a value to the item, so that future processing can commence. (See my post C# Winforms and the Hidden Association Tag for more information on how to load those types of controls.)

That item to be associated could be an integer, a string or even an actual object. This article demonstrates how do that by loading a KeyValuePair object (or a Tuple for .Net 4) into the box where the display text will be shown but it will also carry a payload to allow us to process things in the future.

Loading ComboBox and ListBox

The following code shows how to load the boxes. The goal is to have Alpha, Beta and Gamma as the selectable text and the payload values they will carry to be 5, 6 and 7 respectfully. Here is the code to load.

List<string> displayValues = new List<string>() { "Alpha", "Beta", "Gamma" };

var dict = displayValues.Select( ( item, index ) => new KeyValuePair<string, string>( item, ( index + 5 ).ToString() ) );

cbOne.DisplayMember =
lbOne.DisplayMember = "Key";

// Convert the objects to array and the controls
// will extract the appropriate values to display
// and use for a value.
cbOne.Items.AddRange( dict.OfType<object>().ToArray());
lbOne.Items.AddRange( dict.OfType<object>().ToArray());

Explanation

Line 1: Contains our list items to show to the user.

Line 3: Thanks to Linq we enumerate the displayValues list and on each indexed item we add 5 to the that index value. That creates key value pairs of (“Alpha”, (0+5)), (“Beta”, (1 + 5)), (“Gamma”, (2+5)). Note one doesn’t have to use a string as a value it could be a whole new instance of a class.

Line 5-6: We inform the combobox and the listbox that when it processes and creates the items, use “Key” for the display text for the user.

Line 11-12 : We load our combo box an list box accordingly. Note how we have to change the type of the item return to be an array of objects thanks to the OfType<object>() extension. This is done because the boxes take objects and not a specific object. It allows us a greater flexibility.

That loads our controls. Build and run to see the controls with the selected values.

Value Extraction

Now we have a button on the screen which when clicked gets the current item and extracts our value data to use. It takes those values and displays them to labels next to the target controls so we can see it working. Here is the code

private void btShowSelectedValues_Click( object sender, EventArgs e )
{
    label1.Text = string.Format( "Value: {0}", ((KeyValuePair<string,string>)lbOne.SelectedItem).Value );
    label2.Text = string.Format( "Value: {0}", ((KeyValuePair<string, string>)cbOne.SelectedItem ).Value );

}

What is happening is that we get the target selected items and cast them to the key value pair object. Once that is done we can extract the actual value, string in this case and write it to the display. Its that simple.

A Larger Trojan Horse

Ok you say, the example is great and you understand that instead of a string for the Value, you could use a class. But what if you need to have more than one value? If you are using .Net 4 use a Tuple. Here is the same code but with a Tuple<>  and three separate objects used instead. Two of the objects will be another class and an enum.

public class OtherClass
{
    public string Action { get; set; }
}

public enum OpValue
{
    Condor,
    Eagle,
    Hawk
}

Here is how we load our boxes and setup the Tuple:

List<Tuple<string, OtherClass, OpValue>> myList = new List<Tuple<string, OtherClass, OpValue>>()
{
    { new Tuple<string, OtherClass, OpValue>( "Alpha", new OtherClass() { Action="Max" }, OpValue.Condor )},
    { new Tuple<string, OtherClass, OpValue>( "Beta", new OtherClass()  { Action="Move" }, OpValue.Hawk )},
    { new Tuple<string, OtherClass, OpValue>( "Gamma", new OtherClass() { Action="Reset" }, OpValue.Eagle)}
};

cbOne.DisplayMember =
lbOne.DisplayMember = "Item1";

// Convert the objects to array and the controls
// will extract the appropriate values to display
// and use for a value.
cbOne.Items.AddRange( myList.OfType<object>().ToArray() );
lbOne.Items.AddRange( myList.OfType<object>().ToArray() );

Here is the button click which will extract our tuple and use the the Action property of our class. Once we have the tuple casted we could use anything…but you know that.

private void btShowSelectedValues_Click( object sender, EventArgs e )
{
    label1.Text = string.Format( "Value: {0}", ( (Tuple<string, OtherClass, OpValue>)lbOne.SelectedItem ).Item2.Action );
    label2.Text = string.Format( "Value: {0}", ( (Tuple<string, OtherClass, OpValue>)cbOne.SelectedItem ).Item2.Action );
}

Here is the final output when run:

Tuple

Share

Tags: , , , , ,

C#: Access a Resource .resx File and a Corresponding Enum To Create a Dictionary

iStock_000013436514XSmall(Update 5/16/2011: Fixed mispelling)
I ran across a situation where the code I was working on had an enum with values and I needed to display a user friendly text which was related to the enum but not the enum’s actual text value.

The standard way of mapping values across cultures is to create a localized resource file(s) (.resx) and to put in string key and a string value, where the value will be shown. The code can then do an if check to map between the two; but that gets laborious real quick. It would be better to have a dictionary where the enum is the key and the value is the value of the resources file.

The following snippet of code takes in an enum and its corresponding resource resx data and creates that dictionary. See the section Steps to Test for an example of its usage.

/// <summary>
/// Take an enum and a created corresponding resx resource file and join the two together 
/// into a dictionary. The dictionaries key is the actual enum and the value is the user readable text
/// found in the value of the resource file.
/// </summary>
/// <typeparam name="T">The Enum type which contains the target enums</typeparam>
/// <param name="rm">The .resx resource's manager which contains the mapped text</param>
/// <returns>A dictionary whose key is the enum and the result is the mapped text in the resource file.</returns>
public static Dictionary<T, string> LoadResourceEnumMappings<T>( ResourceManager rm )  
{
    T[] eValues = (T[])System.Enum.GetValues( typeof( T ) ); // Gets the actual values of the enum (T) type

    // Puts those into a local dictionary/hash for use in later.
    var dictEnum = eValues.ToDictionary( it => it.ToString(), it => it ); 

    // Work through the key value pairs (KVP) of the resource set and marry them
    // to a new dictionary where the key is the enum and the value output is the user string
    // as found in the resource's value of its kvp.
    return rm.GetResourceSet( Thread.CurrentThread.CurrentCulture, true, false )
             .OfType<DictionaryEntry>()
             .ToDictionary( kvp => dictEnum[kvp.Key.ToString()], kvp => kvp.Value.ToString() );

}
NOTES
  • One can have more resource keys than enums and the above will work. But if there are more enums than resource keys, the above code will throw a KeyNotFound exception.
Enumerate the Embedded Resource

The above code uses the ability to enumerate or iterate the resource file by calling GetResourceSet. That calls returns a Dictionary entry which has the key value pair of the resource file and could be used with a foreach.

Steps To Test
  1. Create console application
  2. Create enum named MappedValues with these enums : Alpha, Beta, Gamma.
    public enum MappedValues
    {
        Alpha,
        Beta,
        Gamma
    }
  3. Create Resource File named UserText.Resx with these values:Resx 

Test as such with this code by calling EnumMapper.Usage():

public static class EnumMapper
{
    /// <summary>
    /// This is just for show and not meant for production.
    /// </summary>
    public static void Usage()
    {
        try
        {
            Console.WriteLine( "Load resource and show: " + UserText.Alpha );

            Dictionary<MappedValues, string> mapped = LoadResourceEnumMappings<MappedValues>( UserText.ResourceManager );

            Console.WriteLine( mapped[MappedValues.Alpha] );

            Console.WriteLine( mapped[MappedValues.Beta] );

            Console.WriteLine( mapped[MappedValues.Gamma] );
        }
        catch ( KeyNotFoundException )
        {
            Console.WriteLine("The Resource File has a key which is not found in the enum.");
        }

/* outputs (Note "first value" was shown to initialize the ResourceManager otherwise it would be null from GetResourceSet)
Load resource and show: First Value
First Value
Second Item
Third Wave
*/
    }

    /// <summary>
    /// Take an enum and a created corresponding resx resource file and join the two together 
    /// into a dictionary. The dictionaries key is the actual enum and the value is the user readable text
    /// found in the value of the resource file.
    /// </summary>
    /// <typeparam name="T">The Enum type which contains the target enums</typeparam>
    /// <param name="rm">The .resx resource's manager which contains the mapped text</param>
    /// <returns>A dictionary whose key is the enum and the result is the mapped text in the resource file.</returns>
    public static Dictionary<T, string> LoadResourceEnumMappings<T>( ResourceManager rm )  
    {
        T[] eValues = (T[])System.Enum.GetValues( typeof( T ) ); // Gets the actual values of the enum (T) type

        // Puts those into a local dictionary/hash for use in later.
        var dictEnum = eValues.ToDictionary( it => it.ToString(), it => it ); 

        // Work through the key value pairs (KVP) of the resource set and marry them
        // to a new dictionary where the key is the enum and the value output is the user string
        // as found in the resource's value of its kvp.
        return rm.GetResourceSet( Thread.CurrentThread.CurrentCulture, true, false )
                    .OfType<DictionaryEntry>()
                    .ToDictionary( kvp => dictEnum[kvp.Key.ToString()], kvp => kvp.Value.ToString() );

    }

}
Share

Tags: , , , ,

C#: Connect To Oracle Database With No Oracle Client Install Needed (Winform DataGridView Loading Example)

Oracle_smallUpdate 1/14/2014 : Updated Oracle Instant Client Link

This article demonstrates in a step by step fashion the easiest, and frankly fastest way to connect to an Oracle database using C#. The goal is to not have to install the huge Oracle Client either on the development machine nor the target machine the code will run on. This example creates a winform and inserts the content into a DataGridView for quick viewing. The code below is base on .Net 3.5.

Steps

  1. Oracle has an Oracle Database Instant Client (download link)which is a set of Dlls which can be XCopy installed onto the development and target PC to allow Oracle database access without installing the full Oracle client. In future steps we will include those target Dlls to be copied to the target output folder with the executable. Download the appropriate package and add Dlls to a folder of your choice on the PC.
  2. In Visual Studio create a Winform Project. From the Solution Explorer and within the project create a subfolder named Oracle Dlls. Update: This step should not be done, for the dlls will end up being copied into a subfolder of the same name and when running the client an error may come up stating “System.Data.OracleClient requires Oracle client software
    version 8.1.7 or greater”.
  3. Add the reference to the project of System.Data.OracleClient to the project..
  4. In Studio again select the folder created in step 2 (highlight the project root) and from the right click menu select Add->Existing Item, and insert all the top level Oracle Dlls from step one into the directory into the folder project. Note the below picture shows into a folder, they do not go into a folder but at the root of the project.
    OracleFolder2
  5. Highlight all the inserted DLLs and select Properties to bring up the properties window. Change the Build Action to be Content and the Copy To Output Directory to be Copy If Newer. This allows the dlls to reside with the created executable program. By doing this it allows the program to run on another computer, as well as this one, that does not have the Oracle Client installed because all the Oracle specific dlls reside with the output executable.
  6. On the design view of the form add a button, label, binding source and a DataGridView. The names used for each in the example (Label as lbState, Binding Source as bsOracle and DataGridView as gvOracle).
  7. Create in the forms code a method to handle the connection string and add the target Oracle db/instance items (Note: Replace { xxx } including the curly braces the specifics to your db) :
    private string GenerateConnectionString()
    {
       return "Data Source=( DESCRIPTION = ( ADDRESS_LIST = ( ADDRESS = ( PROTOCOL = TCP )( HOST = {Insert Host Here} )( PORT = {Insert Port Here} ) ) )( CONNECT_DATA = ( SERVER = DEDICATED )( SERVICE_NAME = {Service Name Here } ) ) ); User Id= {DB ID Here}; Password = {Password Here};";
    }
  8. In the button’s onclick event wire up the controls and access the Oracle database as such:
    try
    {
        using ( OracleConnection connection = new OracleConnection( GenerateConnectionString() ) )
        {
            connection.Open();
            lblState.Text = connection.State.ToString();
    
            OracleCommand oc = connection.CreateCommand();
            oc.CommandText = "SELECT * FROM {Your Table Here}";
    
            OracleDataReader reader = oc.ExecuteReader();
    
            bsOracle.DataSource = reader;
            gvOracle.DataSource = bsOracle;
    
            gvOracle.BorderStyle = BorderStyle.Fixed3D;
            gvOracle.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.AllCells;
    
        }
    }
    catch ( Exception ex )
    {
    //  MessageBox.Show( "Exception: " + ex.Message );
        lblState.Text = ex.Message;
    }
  9. Run and compile the program and if all goes well it should attach…but there are other possible failure points see the next section as to a couple of them.

Note for a more involved explanation of this process check out the article Instant Oracle Using C# which has a console example and does not provide the advice of using the build options in Studio for the Oracle Dlls. That will be our little secret. HTH

Possible Errors Encountered

System.Data.OracleClient requires Oracle client software version 8.1.7 or greater

If this is encountered it could be a permission problem accessing the location where the oracle dlls are…but most likely the dlls are not in the same directory as the executable or found within the environment path of the system.

ORA-12541: TNS:no listener

 

This one could mean that one of the connection settings is incorrect and the database could not be connected to and this generic error comes back. Try tweaking the settings, port, instance

Share

Tags: , ,

C# Linq How To Load a Winform Control Using Dynamic Linq entitites (Or any other Control)

This has been requested in the forums, for most examples in the Linq world are of console applications. One can use Linq to dynamically load winform (or asp.net) controls very easily with the dynamic entities which are created on the fly thanks to Linq. This article shows how to load a gridview control, or any other, with dynamic items of linq.

Steps

  1. Create a winform project/solution.
  2. Drag two controls to the surface of the form datagridview and bindingsource. We will accept the default names of dataGridView1 and bindingSource1.
  3. For demonstration purposes of this article we will create a struct for the simulated data which the Linq-to-Object operation will query off of:
    struct Data
    {
        public string Name { get; set; }
        public string Operation { get; set; }
        public string Description { get; set; }
        public DateTime DateStart { get; set; }
        public DateTime DateEnd { get; set; }
    
    }

    Note if you don’t create a new file for the above struct, place it below the Form1 partial class. Placing it above will screw up the design view when you try to edit.

  4. Here is the code to load the GridView using Linq which can be called from the constructor of the form after the InitializeCoponent call.
    BindingSource bindingSource1= new BindingSource();
    private void LoadGrid()
    {
        List<Data> dataListing = new List<Data>()
        {
            new Data() { Name = "Jabberwocky", Operation="Read", DateStart= DateTime.Now.AddDays(-2), DateEnd = DateTime.Now.AddDays(-2), Description="Process Started No errors"},
            new Data() { Name = "Space", Operation="Write", DateStart= DateTime.Now.AddDays(-2), DateEnd = DateTime.Now.AddDays(-1), Description="Final process remote allocation of 3000 items to main buffer."},
            new Data() { Name = "Stock Purchase", Operation="DataWarehousing", DateStart= DateTime.Now, DateEnd = DateTime.Now, Description="Shared data transport."}
        };
    
        var items = from dta in dataListing
            select new
            {
               OperationName = dta.Name,
               Start         = dta.DateStart.ToShortDateString(),
               End           = dta.DateEnd.ToShortDateString(),
               Operation     = dta.Operation,
               Description   = dta.Description
             };
    
        bindingSource1.DataSource = items;
        dataGridView1.DataSource  = bindingSource1;
    
        // Grid attributes
        dataGridView1.BorderStyle         = BorderStyle.Fixed3D;
        dataGridView1.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.AllCells;
    
    }

Result

GridView

Share

Tags: , , ,

Safely Update .Net Winform from Threads or Timer Ticks

Update The following article is one way to to achieve threading…But an easier way to try first is the BackGround Worker component (How to: Run an Operation in the Background). The below article shows how to invoke back to the form which is a step one does not have to do directly with the background worker due to its design.
Whenever one has threads or timers doing work on a winform application there is a need to update the screen from those operations. Most first time winform programmers fall into the trap where they try to update a screen control from those background processes and discover that their app locks up. The reason is that any data screen updating needs to be done by the GUI thread solely and not from any background task.
What the code should do is invoke a delegate back to the GUI thread to do the screen updating. This article shows one such way.
Step 1 define a delegate on the winform form class, and have an event derived from it which can be subscribed to such as:
// This is the format the delegate method
// will use when invoking back to the main gui
// thread.
public delegate void DataAcquired( object sender );
// The main thread will check for events
// invoked by subscribed threads here.
// This is the subscription point for the 
// threads.
public event DataAcquired OnDataAcquiredEvent;

In the above example we are just using an object to pass between the threads, but you can specify anything you want which is dictated by your circumstances.

Step 2 then have the form subscribe to the event (as in the constructor) which will be eventually be consumed by the worker threads or timers.

OnDataAcquiredEvent +=
    new DataAcquired(ThreadReportsDataAquiredEvent);

Note intellisense will do the above steps for you after the +=, accept them and it will do the next step

Step 3 Create the method that will handle the GUI update event

private void ThreadReportsDataAquiredEvent( object sender )
{
   tsslStatus.Text = sender.ToString();
}
  • Line 01: The thread/timer passes in an object which we will use to update the screen.
  • Line 03: We will take the object’s information from its ToString() and place it on a label on the form for the end user to see.

Step 4: In the timer tic method or the worker thread method we will call this method which will invoke back to the main thread:

private void PushStatus(string status)
{
    this.Invoke(this.OnDataAcquiredEvent,
                new object[] { status });
}

Note: One doesn’t have to create a separate method; the invoke line is all one has to do. We create the event and fire it to the GUI thread.

That is a safe way to update the screen for worker threads or timer tick events.

Share

Tags: , , , , ,

Extracting the Assembly Version in .Net

I like to place the version number of the current application either on the console output or the title bar of the Winform. Using the below method I am able to extract the current assemblies information and return the version info to be displayed.

using System.Reflection;
using System.Diagnostics;

~
// Place in local code
Assembly ass = Assembly.GetExecutingAssembly();
string version;

if (ass != null)
{
    FileVersionInfo FVI = FileVersionInfo.GetVersionInfo(ass.Location);

    version = String.Format("{0} Version ({1:0}.{2:0})",
                  FVI.ProductName,
                  FVI.FileMajorPart.ToString(),
                  FVI.FileMinorPart.ToString());
}
else
{
   version = "Unknown";
}
Share

C# WinForms: Monitor Threads, Handles and Bytes on the Status Strip

This article demonstrates how to monitor performance of an application to report items as handles, memory or threads. It demonstrates how to create a status bar with the display of those performance items in real time using C# in .Net 2/3. One can see if the application is leaking any resources in those areas.

Why not have your application provide information to its running state such as handles, threads and the bytes being used. This article will show you how to create a Winform Application with a status bar where each label reports handles, threads and the bytes used.

Steps:

  1. Create a winform application.
  2. Add the Timer component to the form and set these properties:
    1. Timer: Change the Interval from 100 to 1000 so it ticks off every second.
    2. Timer: Set Enabled to True
    3. Create a event for the Tick event.
  3. Add three PerfomanceCounter Components to the form and name them pcPrivateBytes, pcHandles and pcThreadsBuild the application and run it. Then set the properties below:
    1. All: CategoryName = Process
    2. All: InstanceLifetime = Global
    3. All: MachineName = . (Yes a period)
    4. All: InstanceName = (Find the running application name in the drop down list, hence why we are running it.)
    5. pcHandles: CounterName = Handle Count
    6. pcThreads: CounterName = Thread Count
    7. pcPrivateBytes: CounterName = Private Bytes (Private bytes is only the bytes that the application allocates and not any extraneous bytes allocated by the system)
  4. Close the running application.
  5. Add a Status Strip to the application and create three status label areas named tsslHandles and tsslThreads, tsslPrivateBytes. Note the Private bytes is pretty dynamic, so placing it at the end is a good idea.
  6. In the timer tick event add this code which will get the current values of the performance moniter:
    tsslThread.Text  = string.Format("Threads: {0}", pcThreads.NextValue().ToString());
    tsslHandles.Text = string.Format("Handles: {0}", pcHandles.NextValue().ToString()); 
    
    // Divide the return of Private Bytes to something we will recognize.
    tsslPrivateBytes.Text = string.Format("Private Bytes: {0}", (pcPrivateBytes.NextValue() / 1000).ToString());
  7. Run the application and you should see this which gives you a running total of what your application is doing.

image

Share

Tags: , , ,

C# Winforms and the Hidden Association Tag

There is a little known property off of the Control class called Tag. Since most winform controls derive from this base Control class the Tag property is on most everything that one does with winforms. The tag’s purpose is to associate user data with the control. When building a list or a tree, each node can have a reference to the object that it is associated to. That is very handy when one receives an event and the event gives the node of the tree in question and instead of fishing for the original object in some other list, just one retrieves it off of the Tag property!

For example I created a DataGridView where individual rows had unique columns that needed to reference data that was more than just a boolean or a string. When working with each row’s cell I attached specialized data target objects which needed to be processed when the user sets or edits the value. When I created the row and columns, I would new up a specialized object for each cell and attach then to the row[cell index].Tag. Below we look at two cells. On one cell, I had create a specialized sql object and the other had an XmlDocument to hold the user’s work.

// We have a new row of blank data, create the
// specialized objets for the specific columns
e.Row.Cells[SQLColumn].Tag   = new SQL();
e.Row.Cells[RulesColumn].Tag = new XmlDocument();
// Populating other columns with appropriate data

Then when a user clicks on the SQL cell to edit, I receive this message and allow extract of the specialized object to work on in a winform popup:

private void dataGridViewMain_CellContentClick( object sender, DataGridViewCellEventArgs e )
{

try
{
  DataGridView grid = (DataGridView)sender;

  // Filter out clicks not in the DirectReports column
  if (e.RowIndex >= 0)
      switch (e.ColumnIndex)
      {
      case SQLColumn: // SQL
          SQL editObject = grid.Rows[e.RowIndex].Cells[e.ColumnIndex].Tag as SQL;
          MySQLEditForm edit = new MySQLEditForm(editObject);
          edit.Show();

See how handy the tag can be…use it next time. Also get in the habit of creating Tags on objects you create. One never knows what the consumer may use it for, but your consumer will be happy!

Share