Archive for category .Net

.Net Regex: Can Regular Expression Parsing be Faster than XmlDocument or Linq to Xml?

iStock_000017256683XSmallMost of the time one needs the power of the xml parser whether it is the XmlDocument or Linq to Xml to manipulate and extract data. But what if I told you that in some circumstances regular expressions might be faster?

Most conventional development thinking has branded regex processing as slow and the thought of using regex on xml might seem counter intuitive. In a continuation of articles I again want to dispel those thoughts and provide a real world example where Regular Expression parsing is not only on par with other tools in the .Net world but sometimes faster. The results of my speed test may surprise you;  and hopefully show that regular expressions are not as slow as believed, if not faster!

See: Are C# .Net Regular Expressions Fast Enough for You?

Real World Scenario

There was a developer on the MSDN forums who needed the ability to count URLs in multiple xml files. (See the actual post count the urls in xml file on Msdn) The poster received three distinct replies, one to use XMLDocument, another provided a Linq to XML solution and I chimed in with the regular expression method. The poster took the XMLDocument method and marked as the answer, but could he have done better?

I thought so…

So I took the three replies and distilled them down into their core processing and wrapped them in a similar IO extraction layer and proceeded to time them. I created 48 xml files with over one hundred thousand urls to find for a total of 13 meg on disk. I then proceeded to run the test all in release mode to get the results.  (See below section Setup to get a gist repository of the code).

Real World Result

Five tests, each test name is the technology and the user as found on the original msdn post. In red is the slowest and fastest time. Remember XmlDoc is the one the user choose as the answer.

Test 1
Regex           found 116736 urls in 00:00:00.1843576
XmlLinq_Link_FR found 116736 urls in 00:00:00.2662190
XmlDoc_Hasim()  found 116736 urls in 00:00:00.3534628

Test 2
Regex           found 116736 urls in 00:00:00.2317883
XmlLinq_Link_FR found 116736 urls in 00:00:00.2792730
XmlDoc_Hasim()  found 116736 urls in 00:00:00.2694969

Test 3
Regex           found 116736 urls in 00:00:00.1646719
XmlLinq_Link_FR found 116736 urls in 00:00:00.2333891
XmlDoc_Hasim()  found 116736 urls in 00:00:00.2625176

Test 4
Regex           found 116736 urls in 00:00:00.1677931
XmlLinq_Link_FR found 116736 urls in 00:00:00.2258825
XmlDoc_Hasim()  found 116736 urls in 00:00:00.2590841

Test 5
Regex           found 116736 urls in 00:00:00.1668231
XmlLinq_Link_FR found 116736 urls in 00:00:00.2278445
XmlDoc_Hasim()  found 116736 urls in 00:00:00.2649262

 

Wow! Regex consistently performed better, even when there was no caching of the files as found for the first run! Note that the time is Hours : Minutes : Seconds and regex’s is the fastest at 164 millseconds to parse 48 files! Regex worst time of 184 milleseconds is still better than the other two’s best times.

How was this all done? Let me show you.

Setup

Ok what magic or trickery have I played? All tests are run in a C# .Net 4 Console application in release mode. I have created a public Gist (Regex vs Xml) repository of the code and data which is actually valid Git repository for anyone how may want to add their tests, but let me detail what I did here on the blog as well.

The top level operation found in the Main looks like this where I run the tests 5 times

Enumerable.Range( 1, 5 )
            .ToList()
            .ForEach( tstNumber =>
            {
                Console.WriteLine( "Test " + tstNumber );
                Time( "Regex", RegexFindXml );
                Time( "XmlLinq_Link_FR", XmlLinq_Link_FR );
                Time( "XmlDoc_Hasim()", XmlDoc_Hasim );
                Console.WriteLine( Environment.NewLine );
            }

while the Time generic method looks like this and dutifully runs the target work and reports the results in “Test X found Y Urls in X [time]”:

public static void Time<T>( string what, Func<T> work )
{
    var sw = Stopwatch.StartNew();
    var result = work();
    sw.Stop();
    Console.WriteLine( "\t{0,-15} found {1} urls in {2}", what, result, sw.Elapsed );
}

Now in the msdn post the different methods had differing ways of finding each xml file and opening it, I made them all adhere to the way I open and sum the ULR counts. Here is its snippet:

return Directory.EnumerateFiles( @"D:\temp", "*.xml" )
            .ToList()
            .Sum( fl =>
            {

            } );

Contender  –  XML Document

This is one which the poster marked as the chosen one he used and I dutifully copied it to the best of my ability.

public static int XmlDoc_Hasim()
{
    return Directory.EnumerateFiles( @"D:\temp", "*.xml" )
                .ToList()
                .Sum( fl =>
                {
                    XmlDocument doc = new XmlDocument();
                    doc.LoadXml( System.IO.File.ReadAllText( fl ) );

                    if (doc.ChildNodes.Count > 0)
                        if (doc.ChildNodes[1].HasChildNodes)
                            return doc.ChildNodes[1].ChildNodes.Count;

                    return 0;

                } );

}

I used the sum extension method which is a little different from the original sum operation used, but it brings the tests closer in line by using the Extension.

Contender – Linq to Xml

Of the other two attempts, this one I felt was the more robust of the two, because it actually handled the xml namespace. Sadly it appeared to be ignored by the original poster. Here is his code

public static int XmlLinq_Link_FR()
{
    XNamespace xn = "http://www.sitemaps.org/schemas/sitemap/0.9";

    return Directory.EnumerateFiles( @"D:\temp", "*.xml" )
                    .Sum( fl => XElement.Load( fl ).Descendants( xn + "loc" ).Count() );

}

Contender – Regular Expression

Finally here is the speed test winner. I came up with the pattern design Upon by looking at the xml and it appeared one didn’t need to match the actual url, but just the two preceding  tags and any possible space between. That is the key to regex, using good patterns can achieve fast results.

public static int RegexFindXml()
{
    string pattern = @"(<url>\s*<loc>)";

    return Directory.EnumerateFiles( @"D:\temp", "*.xml" )
                    .Sum( fl => Regex.Matches( File.ReadAllText( fl ), pattern ).OfType<Match>().Count() );

}

XML1 (Shortened)

<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url><loc>http://www.linkedin.com/directory/companies/internet-web2.0-startups-social-networking/barcelona.html</loc><changefreq>weekly</changefreq></url>
<url><loc>http://www.linkedin.com/directory/companies/internet-web2.0-startups-social-networking/basel.html</loc><changefreq>weekly</changefreq></url>
<url><loc>http://www.linkedin.com/directory/companies/internet-web2.0-startups-social-networking/bath.html</loc><changefreq>weekly</changefreq></url>
<url><loc>http://www.linkedin.com/directory/companies/computer-networking/sheffield.html</loc><changefreq>weekly</changefreq></url>
<url><loc>http://www.linkedin.com/directory/companies/computer-networking/singapore.html</loc><changefreq>weekly</changefreq></url>
<url><loc>http://www.linkedin.com/directory/companies/computer-networking/slough.html</loc><changefreq>weekly</changefreq></url>
<url><loc>http://www.linkedin.com/directory/companies/computer-networking/slovak-republic.html</loc><changefreq>weekly</changefreq></url>
</urlset>

Xml2 Shortened

<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url><loc>http://www.linkedin.com/groups/gid-2431604</loc><changefreq>monthly</changefreq></url>
<url><loc>http://www.linkedin.com/groups/gid-2430868</loc><changefreq>monthly</changefreq></url>
<url><loc>http://www.linkedin.com/groups/Wireless-Carrier-Reps-Past-Present-2430807</loc><changefreq>monthly</changefreq></url>
<url><loc>http://www.linkedin.com/groups/gid-2430694</loc><changefreq>monthly</changefreq></url>
<url><loc>http://www.linkedin.com/groups/gid-2430575</loc><changefreq>monthly</changefreq></url>
<url><loc>http://www.linkedin.com/groups/gid-2431452</loc><changefreq>monthly</changefreq></url>
<url><loc>http://www.linkedin.com/groups/gid-2432377</loc><changefreq>monthly</changefreq></url>
<url><loc>http://www.linkedin.com/groups/gid-2428508</loc><changefreq>monthly</changefreq></url>
<url><loc>http://www.linkedin.com/groups/gid-2432379</loc><changefreq>monthly</changefreq></url>
<url><loc>http://www.linkedin.com/groups/gid-2432380</loc><changefreq>monthly</changefreq></url>
<url><loc>http://www.linkedin.com/groups/gid-2432381</loc><changefreq>monthly</changefreq></url>
<url><loc>http://www.linkedin.com/groups/gid-2432383</loc><changefreq>monthly</changefreq></url>
<url><loc>http://www.linkedin.com/groups/gid-2432384</loc><changefreq>monthly</changefreq></url>
</urlset>

Summary

It really comes down to the right tool for the right situation and this one regex really did well. But Regex is not good at most xml parsing needs, but for certain scenarios it really shines. If the xml has malformed or the namespace was wrong, then the parser has its own unique problems which would lead to a bad count. All the technologies had to do some upfront loading and that is key to how they performed. Regex is optimized to handle large data efficiently and as long as the pattern is spot on, it can really be quick.

My thought is don’t dismiss regular expression parsing out of hand, while the learning of it can pay off in some unique text parsing situations.

Share

Tags: , ,

C# Silverlight WCF: Thread Safe Multiple Async Call Strategy With Final Operation To Join Data.

Seven Pointing Arrows ending at different points except one arror leaping of the page to show the final Async call.This article describes one way to handle asynchronous or async calls in .Net 3.5 or .Net 4.0 when using WCF in Silverlight in C#. The goal is to have a final operation wait for all the calls to finish so to combine all the data gathered, all in a thread safe way. A secondary goal is to minimize the consumer code required to perform this operation from what is currently available in straight WCF async calls.

This article has a short shelf life because after .Net 4 (see What’s Next in C#? Get Ready for Async!) one will use the built in Asynchrony methodology developed. Until that time if one is using any version of Silverlight and WCF then this article describes how to handle those multiple async calls and join the data in a final method call.

Final Result Example

Before delving into the solution, here is how the consumer will use the methodology. Below a user is getting account information of user requests, departments and accounts to join all the data on the view model in the final method for display on a Silverlight page. Thesee operations as shown are setup when the view model class (MyViewModel) is created and no blocking occurs keeping UI thread clear.

public MyViewModel()
{
    DataContext = new MyServiceClient();

    FinalAsync(CombineDataAndDisplay); // When all the data is retrieved, do this method to combine the data From the 3 async callls below

    // Provide the operation as a lambda (could be a method call) to assign data to our target backing store property
    // and if all has gone well (no errors in other async calls) and it is the final completing operation. Do the final
    // Processing call automatically.
    DataContext.GetUserRequestsCompleted   += (s, e) => { AssignResultCheckforAllAsyncsDone(e, e.Result, ref _UserRequests, "Acquisition failure for User Requests");};
    DataContext.GetAccountsCompleted       += (s, e) => { AssignResultCheckforAllAsyncsDone(e, e.Result, ref _Accounts, "Acquisition Failure for Accounts"); };
    DataContext.GetDepartments             += (s, e) => { AssignResultCheckforAllAsyncsDone(e, e.Result, ref _Departments, "Failed to get Department Info."); };   

    // Start the Async processes 
    MultipleAsyncRun(DataContext.GetUserRequestsAsync);
    MultipleAsyncRun(DataContext.GetAccountsAsync);
    MultipleAsyncRun(DataContext.GetDepartmentsAsync);

    // Exit out and return the UI thread to the user operations.
}

// Once all the data is done, combine and assign into our
// PagedCollectionView property for display on the screen.
public void CombineDataAndDisplay()
{
    // Combine missing data on the calls
   _UserRequests.ToList()
                .ForEach(ur =>
                {
                ur.BillingName     = _Accounts.First(ac => ur.AccountID == ac.AccountID).Name;
                ur.DepartmentName  = _Departments.First(dp => dp.DepartmentID == ur.DepartmentID).Name;
                });


    UserRequests = new PagedCollectionView( _UserRequests);
    UserRequests.GroupDescriptions.Add(new PropertyGroupDescription("DepartmentName"));

}
Explanation
Line  5: The final async call is where this process specifies a method to use after all async calls are completed. On line 24 of the example is our final operation method to do that which is reported to FinalAsync.
Line 11-13: Just like the normal async process we subscribe to the anync handler but we handle it in a anonymous lambda.
Line 11-13: AssignResultCheckForAllAsyncsDone method will check the result returned, code show later in the article. All one needs to know now is that the respective _UserRequests, _Accounts and _Departments, all backing store variables (not properties) will be loaded with the data if the result information ( e ) operation contains no errors. This method does all the heavy lifiting by checking error state, loading the data variable, decrementing the async count and firing off the final method if all asynchronous operations are completed.
Line 16-18: Just like the normal WCF async process we must launch the asnc calls and these statements do just that. We supply the method to be launched inside the MulipleAsync method.
Line 24: Here is our final method to be executed once the asynchrony process is complete. This method combines all the async data internally into the _UserRequest object at which it becomes complete and can be used.
Line 34: Finally a paged collection view is created from our data to be bound to Silverlight Xaml items which is our end result.
24-37: Note: The section below has a variable entitled AsyncErrors. The above example did not check that for null or an error situation. I have left out the check of AsyncErrors for brevity of the example. See the last section for an example of proper error handling.

Multiple Async Methodology Plumbing

Below is what will needed to be brought into your View Model, or placed on your page if not using MVVM. This is where the .Net thread safe Silverlight asynchronous operations will occur.

// Lock Objects 0 for false, 1 for true.
private int AsyncErrorResource = 0;
private int AsyncFinal = 0;

private List<Exception> AsyncErrors;  // If not null errors have been encountered.

private int PendingAsyncOperations; // Holds the counted total of ongoing async operations. Zero means do users final operation.

private Action FinalOperation;      // The user's final operation.

public void MultipleAsyncRun(Action Operation)
{
    Interlocked.Increment(ref PendingAsyncOperations);
    Operation();
}

public void FinalAsync(Action method)
{
    FinalOperation = method;
}

public void AssignResultCheckforAllAsyncsDone<T>(AsyncCompletedEventArgs ea, T receivedData, ref T assignTo, string ErrorMessage)
   where T : class
{
    bool valid = !((ea.Error != null) || (receivedData == null));

    if (valid == false)
    {
        if (0 == Interlocked.Exchange(ref AsyncErrorResource, 1))
        {
            if (AsyncErrors == null)
                AsyncErrors = new List<Exception>();

            AsyncErrors.Add(ea.Error);

            //Release the lock
            Interlocked.Exchange(ref AsyncErrorResource, 0);
        }
    }
    else
    {
        assignTo = receivedData;
    }

    Interlocked.Decrement(ref PendingAsyncOperations);
    if (PendingAsyncOperations == 0)
    {
        if (0 == Interlocked.Exchange(ref AsyncFinal, 1))
        {
            FinalOperation();
        }

        Interlocked.Exchange(ref AsyncFinal, 0);
        Interlocked.Decrement(ref PendingAsyncOperations); // Move to -1
    }
}
Explanation
Line  2/3: These variables are used as a lock targets for thread safety. Value zero means its open and a value of 1 means a lock is in place.
Line  5: Any errors encountered are placed into AsyncErrors. The final operation must check this variable. If it is not null errors have occurred and data is incomplete see the final section of this article on how to handle errors.
Line 7: This variable will hold the running total async operations. Once it gets to zero the final operation will be executed.
Line 11: This method counts and stores our async operations as they come in and launches the async method as well.
Line 13: This process uses the Interlocked class found in the System.Threading namespace. To quote Microsoft, “Provides atomic operations for variables that are shared by multiple threads. “. We simply count up the PendingAsyncOperations variable. Later when the operations complete this will be decremented.
Line 18: This method is called by the consumer so we know what method to launch when all async operations have completed. We assign the method to a holder variable as found on line 9.
Line 22: This method will take in the event arguments and check if there is a problem. It will store the error if there is one and also decrement our count. If our count hits zero it will launch the users final operation.
25-39: Checking errors reported by the async call. If there are any we log them and do not assign the variable. Note whether an error exists or not the operation continues below where the final operation is checked for and executed. Its up to the final operation to check if errors exists and handle them appropriately.
Line 42: If the event reports a success this is where we assign the value to the passed in reference to the template T assignTo. If one doesn’t use a variable for assignTo reference an exception will be generated on this line. See the following section as to why. 
Line 46: We safely decrement our operations count variable. Zero means we are done!
Line 47-57: Here is where we execute the final operation when the count is zero. Note there is an extra lock if operations unlikely hit a zero at the same time. The extra lock ensures only one will execute the final method.

That is it, simply use the above code and you can have all your operations work done asynchronously. Smile Now for the disclaimers…

Why Can’t Properties be Used by AssignResultCheckforAllAsyncsDone?

We must use direct variables like in our example

private ObservableCollection<UserRequestDTO> _UserRequests;
private ObservableCollection<Account> _Accounts;
private ObservableCollection<Department> _Deparments;

// Not Private ObservableCollection<Department> _Departments { get; set; }

If one used a property this exception is thrown.

A property, indexer or dynamic member access may not be passed as an out or ref parameter

That is because we are using the generic method AssignResultCheckforAllAsyncsDone to assign a value, and that assignment has to have an exact object instance for the template (T) object and not a Property to assign the value. If your end result is in a property, simply assign it from the variable to the property in the final async call.

Handling Errors

Simply check the error variable if it is not null it has encountered errors.

if (AsyncErrors != null)
{
    MessageBox.Show("Errors: " + string.Join(string.Format("{0}{0}", Environment.NewLine), AsyncErrors.Select(ex => ex.Message)));
}
else
{
    // Success Handle accordingly.
}
Share

Tags: , , , ,

C#: WPF and Silverlight DataGrid Linq Binding Example Using Predefined Column Header Names in Xaml

iStock_000015057287XSmallThis snippet is from my archives and reminds me how to setup column names for a WPF/Silverlight datagrid and bind them to the data by not using AutoGenerateColumn feature. (See below for the visual end result.)

Ω Check out the related post Xaml: Adding Visibility Behaviors Using Blend to A DataGrid for WPF or Silverlight

DataGrid Column Names Setup in Xaml

In this example we will have two columns where the data will be filename strings. We will specify the columns in the Xaml to use the DataGridTextColumn and not to dynamically generate columns on our Datagrid:

<DataGrid x:Name="dgOperation" AutoGenerateColumns="False">
    <DataGrid.Columns>
        <DataGridTextColumn Header="File Name Before" Binding="{Binding Path=Original}"/>
        <DataGridTextColumn Header="File Name After"  Binding="{Binding Path=New}"/>
    </DataGrid.Columns>
</DataGrid>

The result is that the header row will have two columns with the name “File Name Before” and “File Name After” will subsequently bind them to a data object with the property names of “Original” and “New”.

Actual Binding During the Loading of the Grid

We will read in a directory for the WPF example from the hard drive and fill the original file names to the first column and a generated name for the second column. Since we have specified in the Xaml that we are binding to “Original” and “New” properties the dynamic linq object created will have those properties.

dgOperation.ItemsSource = Directory.GetFiles( @"C:\" )
                                   .Select( ( nm, index ) => new
                                       {
                                          Original = System.IO.Path.GetFileName( nm ),
                                          New = string.Format( "{0}_{1}{2}", System.IO.Path.GetFileNameWithoutExtension( nm ),
                                                                             index,
                                                                             System.IO.Path.GetExtension( nm ) )
                                        } );

The result is as below:

DataGridBind

Note: Out of the box editing the rows will throw an exception. To fix that make each of the rows read only.

Share

Tags: , , ,

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#: String Extension SplitOn to Split Text into Specific Sizes

This code string extension will take a specific number of words and create a list of strings up to that word boundary. For example if one split on this sentence: “The Fall River” would make three strings of “The “, “Fall “ and “River”.

I have placed this into a string extension which could be called such as

List<string> items = "The Fall River".SplitOn( 5 );

Here is the extension method

// using System.Text.RegularExpressions;
public static class StringExtensions
{

    /// <summary>Use this function like string.Split but instead of a character to split on, 
    /// use a maximum line width size. This is similar to a Word Wrap where no words will be split.</summary>
    /// Note if the a word is longer than the maxcharactes it will be trimmed from the start.
    /// <param name="initial">The string to parse.</param>
    /// <param name="MaxCharacters">The maximum size.</param>
    /// <remarks>This function will remove some white space at the end of a line, but allow for a blank line.</remarks>
    /// 
    /// <returns>An array of strings.</returns>
    public static List<string> SplitOn( this string initial, int MaxCharacters )
    {

        List<string> lines = new List<string>();

        if ( string.IsNullOrEmpty( initial ) == false )
        {
            string targetGroup = "Line";
            string theRegex = string.Format( @"(?<{0}>.{{1,{1}}})(?:\W|$)", targetGroup, MaxCharacters );

            MatchCollection matches = Regex.Matches( initial, theRegex, RegexOptions.IgnoreCase
                                                                      | RegexOptions.Multiline
                                                                      | RegexOptions.ExplicitCapture
                                                                      | RegexOptions.CultureInvariant
                                                                      | RegexOptions.Compiled );
            if ( matches != null )
                if ( matches.Count > 0 )
                    foreach ( Match m in matches )
                        lines.Add( m.Groups[targetGroup].Value );
        }

        return lines;
    }


}

Here is an example with output of its usage:

string text = "The rain in spain falls mainly on the plain of Jabberwocky falls.";

List<string> lines = text.SplitOn( 20 );

foreach ( string line in lines )
    Console.WriteLine( line );

/*
The rain in spain
falls mainly on the
plain of Jabberwocky
falls.
 */

foreach ( string line in text.SplitOn( 11 ) )
    Console.WriteLine( line );

/*
The rain in
spain falls
mainly on
the plain
of
Jabberwocky
falls.
 */ 
Share

Tags:

C#: Multiple Dynamic Properties on a Class Either Defined or with Generics

Using the class indexer of C# (abc[ xxx ] = yyy) we can create a class which has multiple dynamic properties associated by a string or whatever we want as the key for access. In the example below we use a string as our access key and holds a string as a value. The storage is accomplished by using a dictionary. See the Usage method below on how to access it.

public class MultipleDynamicProperties
{

    private Dictionary<string, string> _dynamicProperties = new Dictionary<string, string>();    
    
    // Index the data here  
    public string this[string key]
    {
        get
        {
            if ( _dynamicProperties.ContainsKey( key ) == false )
                _dynamicProperties.Add( key, string.Empty );

            return _dynamicProperties[key];
        }
        set
        {
            if ( _dynamicProperties.ContainsKey( key ) == false )
                _dynamicProperties.Add( key, value );
            else
            {
                _dynamicProperties[key] = value;
            }
        }
    }

    /// <summary>
    /// Example don't use in your code.
    /// </summary>
    public static void Usage()
    {
        MultipleDynamicProperties mdc = new MultipleDynamicProperties();

        mdc["Jabber"] = "1st Attempt";
        mdc["Jabber"] = "Wocky";
        mdc["Omega"] = "Man";

        Console.WriteLine("Jabber: " + mdc["Jabber"]); // Printers Jabber: wocky

    }

}

Using other index types say integer or enum, we can accomplish the same goal by changing or adding to our index’able properties of the class. We could have multiple accessors as long as the key is not the same. Below is an example using an enum as the key and a List<string> as the value returned:

public class MultipleDynamicPropertiesWithEnum
{
    public enum Operation
    {
        TargetA,
        TargetB,
    }

    private Dictionary<Operation, List<string>> _dynamicProperties = new Dictionary<Operation, List<string>>();


         // Index the data here  
    public List<string> this[Operation key]
    {
        get
        {
            if ( _dynamicProperties.ContainsKey( key ) == false )
                _dynamicProperties.Add( key, new List<string>() );

            return _dynamicProperties[key];
        }
        set
        {
            if ( _dynamicProperties.ContainsKey( key ) == false )
                _dynamicProperties.Add( key, value );
            else
            {
                _dynamicProperties[key] = value;
            }
        }
    }

    public static void Usage()
    {
        MultipleDynamicPropertiesWithEnum show = new MultipleDynamicPropertiesWithEnum();

        show[Operation.TargetA] = new List<string>() { "Jabber" };
        show[Operation.TargetB] = new List<string>() { "Wocky" };

        // Prints Jabberwocky 
        Console.WriteLine( show[Operation.TargetA][0] + show[Operation.TargetB][0] );
    }
}

 

Generic Option

But why limit ourselves, why not make the accessor generic, so the user/consumer can dictate what the keys and what data is returned. Here is the generic version where we mimic the hard coded version of string and string.

/// <summary>
/// This class has a generic indexor defined by the generic parameters specified
/// by the consumer.
/// </summary>
/// <typeparam name="KY">Key type to use to acces the value type to store.</typeparam>
/// <typeparam name="T">The value type to store.</typeparam>
/// <remarks>See Usage on how to use.</remarks>
public class MultipleDynamicPropertiesAsGeneric<KY, T>
{

    private Dictionary<KY, T> _dynamicProperties = new Dictionary<KY, T>();

    // Index the data here  
    public T this[KY key]
    {
        get
        {
            if ( _dynamicProperties.ContainsKey( key ) == false )
            {
                _dynamicProperties.Add( key, Activator.CreateInstance<T>() );
            }

            return _dynamicProperties[key];
        }
        set
        {
            if ( _dynamicProperties.ContainsKey( key ) == false )
                _dynamicProperties.Add( key, value );
            else
            {
                _dynamicProperties[key] = value;
            }
        }
    }

    public static void Usage()
    {
        MultipleDynamicPropertiesAsGeneric<string, string> show = new MultipleDynamicPropertiesAsGeneric<string, string>();

        show["Jabber"] = "Wocky";

        // Prints wocky 
        Console.WriteLine( show["Jabber"] );

    }

}
Share

Tags: ,

C# WPF: Threading, Control Updating, Status Bar and Cancel Operations Example All In One

You're All Mine Bringing them together; this article shows how to do GUI processing and background work in WPF using C# with an eye on progress and the ability to cancel. This article demonstrates all these topics :

  • Create a background thread to do work away from GUI as to not slow down the user experience.
  • Pass data from the GUI thread to the background worker and subsequently to GUI to update appropriate controls.
  • Safely update screen data after work is done.
  • Invoke/Dispatch back to control GUI thread from worker as needed.
  • Associate threaded work with progress bar in WPF to provide status.
  • Allow the users to stop or cancel the process and handle it appropriately.
  • Enable and disable buttons so user is not kicking off superfluous actions while the work process is executing.
  • I write these articles to enlighten the development community as well as notes for myself as I work in the differing technologies going forward. For this article I saw many websites which would individually piece these topics together, but none of them showed the the whole process. This article covers the whole process.

    BackgroundWorker Not Just For Winforms Anymore

    The goal of the operation is to do the work, and that work is not done on the GUI thread where a user will notice the slow down, but on a background thread. To accomplish that, one of the best fixtures of .Net is the Background thread which was introduced for Winforms. Even though the BackgroundWorker is a nice drag and droppable component in the Winform arena it does not mean that it can’t moonlight in our WPF sandbox. We simply have to instantiate and initialize it ourselves. Here is the code to do that in our Window class:

    public partial class Window1 : Window
    {
        BackgroundWorker bcLoad = new BackgroundWorker();
    
        public Window1()
        {
            InitializeComponent();
    
            bcLoad.DoWork += new DoWorkEventHandler(bcLoad_DoWork);
            bcLoad.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bcLoad_RunWorkerCompleted);
    
            bcLoad.WorkerReportsProgress = true;
            bcLoad.ProgressChanged += new ProgressChangedEventHandler(bcLoad_ProgressChanged);
    
            bcLoad.WorkerSupportsCancellation = true;
        }

    Explanation

    • Line 3: We must declare and subsequently instantiate a background worker which will be used. This object and operations can be reused so this only needs to be done once and to keep temporality we declare it on the window class itself.
    • Line 9/10: We are subscribing to the events which will handle our work on the separate thread. The DoWork event is where the heavy lifting of the offloaded operations will occur. The RunWorkerCompleted event is the safe haven where we can pipe the results of DoWork to the GUI controls without having to invoke or dispatch back to the controls because the event code will be done on the GUI’s thread. Note intellisense is our friend one these lines. Type in += and intellisense offers to create the subscribing to the event handler with a Tab. A subsequent Tab key will create the method stub. Give it a try.
    • Line 12/13: Here is where we tell the background worker that we are going to do a progress operation back to the GUI for the user experience. Note if we don’t specify WorkReportsProgress we will get this exception:This BackgroundWorker states that it doesn’t report progress. Modify WorkerReportsProgress to state that it does report progress.
    • Line 15: Here is where we also inform the BackgroundWorker object that we will be handling cancellation.

    Xaml Mammal

    With the goal of providing a cancel and progress status bar as such:

    StatusBar

    Here is the code to add to our Xaml where it lives at the bottom of our screen. Below the code is the status bar and its child elements of a TextBlock, ProgessBar and button for the cancel.

    <StatusBar Name="stBarPrimary" Grid.Row="5" Grid.ColumnSpan="4" Background="AntiqueWhite" Margin="0,9.056,0,0">
    
        <StatusBarItem>
            <TextBlock Name="tbStatus">Status:</TextBlock>
        </StatusBarItem>
    
        <StatusBarItem>
            <ProgressBar Height="12" Width="400" Margin="20,0,5,1" Name="pBar1" Visibility="Hidden" VerticalAlignment="Bottom" />
        </StatusBarItem>
    
        <StatusBarItem>
            <Button Height="24" Width="80" Content="Cancel" Name="btnCancel" Visibility="Hidden" Click="btnCancel_Click" />
        </StatusBarItem>
    
    </StatusBar>

    The only thing to note that initially the Cancel button and progress bar visibility is set to hidden.

    Launching the Operation from a Button Click

    Here is the code where we launch the DoWork event operation, but more importantly we pass in data which the DoWork can use to perform its operations. The data here is special because it all resides on gui controls. We don’t want to access that data directly from our worker thread otherwise we will get this exception as reported in my previous article (C# WPF: Linq Fails in BackgroundWorker DoWork Event ) :

    The calling thread cannot access this object because a different thread owns it.

    private void btnAcquire_Click(object sender, RoutedEventArgs e)
    {
        btnAcquire.IsEnabled = false;
    
        tbStatus.Text = "Status :"; // Reset status if changed.
    
        btnCancel.Visibility =
        pBar1.Visibility = Visibility.Visible;
    
        bcLoad.RunWorkerAsync(new Dictionary<string, string>()
                    {
                        { "AccountID", tbAccount.Text },
                        { "CategoryID", tbCategory.Text },
                        { "SequenceNumber", tbSequenceNumber.Text }
                    });
    }

    The first thing we do is darken the button which launched the process so the user doesn’t click it twice. Then we make the cancel button and the progress bar visible to the user as the process is about to begin. Finally we extract data held in Gui controls exposed to the user. We cannot access that data once the thread is running and must get the data to to the DoWork process.

    Is It Done Yet? Move the Progress Bar.

    Here is our event which handles the moving of the progress bar. This is done on the GUI thread so no need to do checking of the dispatch. We get a numeric percentage which moves the bar along and incremental movements.

    void bcLoad_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        pBar1.Value = e.ProgressPercentage;
    }

    Cancelling the Operation from a Button Click

    The cancel is similar because we do the opposite of the initiation code above by hiding the controls and informing the user of the stop action. This cancel is initiated by the cancel button on click event shown in the Xaml above. We do all this on the cancel because a cancel event does not fire the RunWorkerCompleted event.;

    private void btnCancel_Click(object sender, RoutedEventArgs e)
    {
        bcLoad.CancelAsync();
    
        // Turn off from here the progress bar and cancel button and report that.
        tbStatus.Text = "Status : Canceled";
    
        btnCancel.Visibility =
        pBar1.Visibility = Visibility.Hidden;
    
        btnAcquire.IsEnabled = true;
    
    }

    Time to DoWork

    Ok, here is what we have been waiting to do, the actual work which will occur in the background on the separate thread. We add to the code for the DoWork Event.

    void bcLoad_DoWork(object sender, DoWorkEventArgs e)
    {
        try
        {
            List<string> Results = new List<string>();
    
            Dictionary<string, string> UserInputs = e.Argument as Dictionary<string, string>;
    
            if (UserInputs != null)
            {
                bcLoad.ReportProgress(33);
    
                DatabaseContext dbc = new DatabaseContext();
    
                var data = dbc.SystemData
                              .Where(ac => ac.Account_ID == UserInputs["AccountID"])
                              .Where(ac => ac.TimeStamp == 0)
                              .Where(ac => ac.Category_id == UserInputs["CategoryID"])
                              .Where(ac => (int)ac.Category_seq_nbr == int.Parse(UserInputs["SequenceNumber"]))
                              .Select(ac => acc.UnitCode);
    
                Results.Add("Unit Code: " + data.First());
    
                if (bcLoad.CancellationPending)
                {
                    e.Cancel = true;
                    return;
                }
    
                bcLoad.ReportProgress(60);
                Results.Add("Income Processing Types: " + string.Join(" ", Financial.GetIncomeProcessingTypes().ToArray()));
    
                if (bcLoad.CancellationPending)
                {
                    e.Cancel = true;
                    return;
                }
    
                bcLoad.ReportProgress(80);
    
                Results.Add("Stock Movement: " + string.Join(" ", Financial.GetStockMovementTypes().ToArray()));
    
                bcLoad.ReportProgress(100);
    
                e.Result = Results; // Pass the results to the completed events to process them accordingly.
            }
        }
        catch (Exception ex)
        {
            lbxData.Dispatcher.BeginInvoke(new Action(() => lbxData.Items.Add("Exception Caught: " + ex.Message)));
        }
    
    }

    Explanation

    • Line 5: We will return Results to the RunWorkerCompleted event and this line initializes it.
    • Line 7: This method was passed data. Here is where we unbox our present which is a Dictionary which contains our user input we are interested in processing.
    • Line 11: Here is where we pass our percentage. It will move the bar up 33 percent. You can dictate what percentage of the process is done. I have chosen 33 in this case, because the code does three separate work items and it will allow for a smother transitions.
    • Line 16 : Here is where we access the passed in dictionary which holds our user inputs.
    • Line 22: The first work unit will be executed on this line and the database call will be made. After this line we can bump up the progress bar.
    • Line 24: Our first important check to see if the user wants to cancel. If a cancel event has been fired, we simply exit this method. Cancellation means that the follow up function RunWorkerCompleted will not be fired.
    • Line 27: If we are here, bump up the progress bar.
    • Line 28-37: Repeat of the work, check cancel and move progress bar as shown above. Though once done, we bump the result to 100%! We are done with the work.
    • Line 39: Now we place the results on the DoWorkEvents Result property to be used in the RunWorkerCompleted.
    • Line 44: The exception actually reports the error to in this case a List box named lbxData. This is accomplished by using the controls Dispatcher invoke code. That invoke ensures that the action against the control is done safely on the GUI thread. We could have used this in our code instead of putting things onto a result. But I have chosen not to because if the user cancels, we don’t have half loaded data to unload from controls. By passing the result to the RunWorkerCompleted event we ensure that all data is properly populated and no complex back out of data during error situations is needed. But since this is a exceptional and unplanned situation, I have chosen to write to the control directly. You have the tools to do either, its your design. :-)

    Time to Display the Result to the User

    Finally our work is done and all is complete. The below code safely writes the result to the GUI thread’s controls.

    void bcLoad_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        if ((e.Result != null) && (e.Cancel == false))
        {
            List<string> results = e.Result as List<string>;
    
            if (results != null)
                foreach (string item in results)
                    lbxData.Items.Add(item);
        }
        else // User has canceled or there is no data.
        {
           lbxData.Items.Clear();
        }
    
        btnAcquire.IsEnabled = true;
    
        btnCancel.Visibility =
        pBar1.Visibility = Visibility.Hidden;
    
    }

    Explanation

    • Line 3: We are expecting results, do a check for good measure.
    • Line 5: Unbox our present from the DoWork event.
    • Line 7: Load our ListBox with our found data!
    • Line 10: Turn on the button which started it all.
    • Line 12-13: Hide the progress bar and Cancel button.

    This is now done and I hope it helped.

    Miscellaneous

    I am including the Xaml which I used which shows the user input and input button for those who may be curious about the code.

    <Window x:Class="CSS_Research.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Window1" Height="360" Width="582">
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="34*" />
                <RowDefinition Height="34*" />
                <RowDefinition Height="34*" />
                <RowDefinition Height="34*" />
                <RowDefinition Height="134*" />
                <RowDefinition Height="37*" />
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="170*" />
                <ColumnDefinition Width="216*" />
                <ColumnDefinition Width="16*" />
                <ColumnDefinition Width="155*" />
            </Grid.ColumnDefinitions>
            <Label Name="lbAccount" Content="Account" HorizontalAlignment="Center" VerticalAlignment="Center" />
            <TextBox Name="tbAccount" Grid.Column="1" VerticalContentAlignment="Center" VerticalAlignment="Center" Height="Auto" Margin="0">392702150</TextBox>
            <Label Margin="0" Name="label1" Grid.Row="1" HorizontalAlignment="Center" VerticalAlignment="Center">Category</Label>
            <TextBox Margin="0" Name="tbCategory" VerticalContentAlignment="Center" Grid.Row="1" Grid.Column="1" HorizontalAlignment="Stretch" VerticalAlignment="Center">ret</TextBox>
            <TextBox Grid.ColumnSpan="1" Margin="0" Name="tbSequenceNumber" VerticalContentAlignment="Center" Grid.Column="1" Grid.Row="2" HorizontalAlignment="Stretch" VerticalAlignment="Center" Grid.RowSpan="1">1</TextBox>
            <Label Grid.RowSpan="1" Margin="0" Name="label2" Grid.Row="2" HorizontalAlignment="Center" VerticalAlignment="Center">Category Sequence Number</Label>
            <Button Grid.Column="3" Margin="54.252,6.696,37,6.696" Name="btnAcquire" Click="btnAcquire_Click">Acquire</Button>
    
            <TabControl  Name="tabControl1" Grid.ColumnSpan="4" Grid.Row="4" Margin="12,0.367,0,32.597" Grid.RowSpan="2">
                <TabItem Header="General" Name="tabItem1">
                    <Grid>
                        <ListBox Name="lbxData" Grid.IsSharedSizeScope="True" />
                    </Grid>
                </TabItem>
                <TabItem Header="Data" Name="tbData">
                    <Grid>
    
                    </Grid>
    
                </TabItem>
            </TabControl>
    
            <StatusBar Name="stBarPrimary" Grid.Row="5" Grid.ColumnSpan="4" Background="AntiqueWhite" Margin="0,9.056,0,0">
    
                <StatusBarItem>
                    <TextBlock Name="tbStatus">Status:</TextBlock>
                </StatusBarItem>
    
                <StatusBarItem>
                    <ProgressBar Height="12" Width="400" Margin="20,0,5,1" Name="pBar1" Visibility="Hidden" VerticalAlignment="Bottom" />
                </StatusBarItem>
    
                <StatusBarItem>
                    <Button Height="24" Width="80" Content="Cancel" Name="btnCancel" Visibility="Hidden" Click="btnCancel_Click" />
                </StatusBarItem>
    
            </StatusBar>
    
        </Grid>
    </Window>
    Share

    Tags: , ,