Archive for category .Net

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: , ,

    C# WPF: Linq Fails in BackgroundWorker DoWork Event

    iStock_000010874966XSmall I write this because if I ran into this, someone else will. Now first off it wasn’t Linq that failed, but it looked like it and here is my story of failure I found in a WPF background worker threading code which can happen in other areas as well.

    The perennial advice to all people in the MSDN forums as well as others is never, never, never  write to a GUI control in a thread or the BackgroundWorker’s do work event. All GUI work must be done on a the GUI. I very well knew that…but the reverse (don’t read from a GUI in a different thread)  is also true and that bit me. Let me explain.

    Anecdotal Evidence

    Imagine my surprise when I created a WPF project at a new job and started getting this exception in the DoWork code of my BackgroundWorker when the first use of a Linq query’s delayed execution point was accessed :

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

    The code threw an exception, on line 16 below, where I was loading data from after the Linq call.  I began to think, does this have something to do with the Linq DataContext?

    void bcLoad_DoWork(object sender, DoWorkEventArgs e)
    {
        try
        {
            List<string> Results = new List<string>();
    
            DatabaseDataContext dbc = new DatabaseDataContext();
    
            var data = dbc.SystemData
                          .Where(ac => ac.Account_id == tbAccount.Text)
                          .Where(ac => ac.TimeStamp == 0)
                          .Where(ac => ac.Category_id == tbCategory.Text)
                          .Where(ac => (int)ac.Category_seq_nbr == int.Parse(tbSequenceNumber.Text))
                          .Select(ac => ac.Unit_Code);
    
            Results.Add("Unit Code: " + data.First());
    
            e.Result = Results;
        }
        catch (Exception ex)
        {
            lbxData.Dispatcher.BeginInvoke( new Action(() => lbxData.Items.Add( "Exception Caught: " + ex.Message )));
        } 
    }

    No the problem was within the setup of the Lambdas for the Linq query. All the highlighted lines above is where the actual problem originates and not on the final highlighted line.

    The problem was that I was accessing Gui controls data, and not changing; that was the nuance. For in my mind that was ok, it was a passive read action and not a direct writing one. Obviously not.

    Note: If you have come to this blog experiencing this problem but for the writing of items to a control, one method to solve it is to use the Dispatcher off the control on any thread not just BackgroundWorker. That code is shown in my exception catch blog above. That line is perfectly fine to do and is not another issue. The lbxData is a Listbox on the main Xaml and because of the immediacy of the exception, I write

    Resolution

    Since I was already using the plumbing of the DoWorkEventArgs, it seemed a natural choice to pass in the data using that object. I changed the call to pass in a Dictionary of values to extract the data as such:

    bcLoad.RunWorkerAsync(new Dictionary<string, string>() 
                            { 
                                { "AccountID",      tbAccount.Text }, 
                                { "CategoryID",     tbCategory.Text },
                                { "SequenceNumber", tbSequenceNumber.Text }
                            });

    Then to consume the Dictionary as such:

    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)
            {
    
            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());
    
            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 )));
        }
    
    }

    I simply convert the object property of Argument to a Dictionary, as highlighted, and go do the work. One doesn’t have to use a Dictionary. One can pass in any object off of the Argument property. Hope This Helps

    Share

    Tags: , , , ,

    C#: Reflect and Load Entities From a DataSet using a Generic Method and Attributed Entities

    iStock_000011856107XSmall If one is not using Linq-To-Sql and the entities are not being generated and loaded, one has to create their own entities and manually load the data into the it. Sure the process for doing one or two entities is ok when done by hand; but it becomes very repetitive grunt work for two or more. This article shows how to decorate an entity with attributes and then using reflection in a generic method load the data from a dataset in C#. This can be done with any version of .Net from 3.5 or greater.

    Entity

    To make this magic happen we need to decorate our entity with a C# attribute which describes the target column name in the database. Thanks to the System.Xml.Serialization namespace we can use the XmlElement attribute. It has an attribute within itself the ElementName attribute which is an excellent vehicle for what we need to do.

    In the class below we have two strings, a DateTime and a decimal. Using the XmlElement we define what all of the target database column names are for each individual mapping of the property to hold the data.

    public class Site
    {
    
        [XmlElement(ElementName = "ID")]
        public decimal ID { get; set; }
    
        [XmlElement(ElementName = "Site_Code")]
        public string Code { get; set; }
    
        [XmlElement(ElementName="Site_Description")]
        public string Description { get; set; }
    
        [XmlElement(ElementName = "REQ_PROP_ORIG")]
        public DateTime? Origination { get; set; }
    
    }
    Using

    Here are the usings if you don’t want to do <CTRL><.> on each error in the file to resolve the namespace for the next sections code.

    using System.Reflection;
    using System.Xml.Serialization;
    using System.ComponentModel;
    using System.Globalization;
    Generic Method and Reflection

    Here is the generic method in a static class. In the next section I describe what is going on when this class is called with a data row and the target entity instance is returned. (See the section Example Usage below to see it in action.)

    public static class EntityHelper
    {
    
        public static TEntity CreateEntityFromDataRow<TEntity>(DataRow drData)
            where TEntity : class, new()
        {
    
            Attribute aTargetAttribute;
            Type tColumnDataType;
    
            TEntity targetClass = new TEntity();
    
            Type targetType = targetClass.GetType(); // The target object's type
    
            PropertyInfo[] properties = targetType.GetProperties(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
    
            // Enumerate the properties and each property which has the XmlElementAttribute defined match the column name
            // and set the new objects value..
            foreach (PropertyInfo piTargetProperty in properties)
            {
                aTargetAttribute = Attribute.GetCustomAttribute(piTargetProperty, typeof(XmlElementAttribute));
    
                if (aTargetAttribute != null)
                {
                    try
                    {
                        foreach (DataColumn column in drData.Table.Columns)
                        {
    
                            if (((XmlElementAttribute)aTargetAttribute).ElementName.ToUpper() == column.ColumnName.ToUpper())
                            {
    
                                if (drData[column.ToString()] != DBNull.Value) // Only pull over actual values
                                {
                                    tColumnDataType = drData[column.ToString()].GetType();
    
                                    // Is the data in the database  a string format and do we
                                    // want a DateTime? Do the below checks and if so covert to datetime.
                                    if ((tColumnDataType != null) &&
                                        (tColumnDataType == typeof(System.String)) &&
                                        (piTargetProperty.PropertyType.IsGenericType) &&
                                        (piTargetProperty.PropertyType.GetGenericTypeDefinition().Equals(typeof(Nullable<>))) &&
                                        ((new NullableConverter(piTargetProperty.PropertyType)).UnderlyingType == typeof(System.DateTime)))
                                    {
                                        // The below pattern dd-MMM-YY is for an Oracle date target. You may need to change this depending
                                        // on the database being used.
                                        DateTime dt = DateTime.ParseExact(drData[column.ToString()].ToString(), "dd-MMM-YY", CultureInfo.CurrentCulture);
                                        piTargetProperty.SetValue(targetClass, dt, null);
                                    }
                                    else // Set the value which matches the property type.
                                        piTargetProperty.SetValue(targetClass, drData[column.ToString()], null);
                                }
                                break; // Column name and data associated, no need to look at the rest of the columns.
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        throw new ApplicationException(string.Format("Load Failure of the Attribute ({0}) for {1}. Exception:{2}",
                            ((XmlElementAttribute)aTargetAttribute).ElementName, targetType.Name, ex.Message));
                    }
                }
            }
    
            return targetClass;
        }
    }
    Explanation
    • Line 4: The generic method is defined to accept a generic type definition (the entity we are working with) but accept a DataRow as the actual data and return the generic type as a valid instance.
    • Line 5: This line requires that the generic type is a class and can be new’ed up. New because we will creating new entity instance at run time. See line 10.
    • Line 11: Simply new up a new entity to return.
    • Line 13/15: We begin to examine the generic type which will lead to the discovery of the properties we are looking at. Note we want all properties regardless of their access level. You can specify just public or private by removing the flags setup on line 14. (For more on this see my blog article .Net Reflection 101: Accessing The String Properties of an Active Object).
    • Line 19: We will enumerate upon the reflected properties of the type and match by reflected Element Name to Column Name.
    • Line 21: Here we reflect and get the custom attributes of the type for usage later.
    • Line 27: Now we begin to find the associated column by enumerating over each column found in the row.
    • Line 30: Does the reflected name match the current column name?
    • Line 35: What is the reported data type from the current row column? This is usede in the if of 39-43.
    • Line 39-43: Some databases return a string value for specific dates/times. If that is the case and we are looking at a string held date value do specialized processing to extract the date/time. If your database returns a DateTime object you can remove this if check.
    • Line 51: Assign the data in the column to the instances property via reflection in SetValue.
    Example Usage
    List<Site> SiteList = new List<Site>();
    
    DataSet ds = new DataSet();
    
    {Data Adaptor}.Fill( ds ); // Fill the dataset from a data adapter. 
    
    // Convert the data in the dataset into a list of the target types.
    foreach (DataRow dr in ds.Tables[0].Rows)
        SiteList.Add(EntityHelper.CreateEntityFromDataRow<Site>(dr));
    Share

    Tags: ,

    C#: Handling Title Case in Strings with Articles and Prepositions

    iStock_000002240961XSmall

    This was an issue I answered in the forums which a user presented and felt that the response was intricate enough to share with the world as a whole. The user wanted to have a string converted to title case but also wanted to have the first letter of any article or preposition to not be be upper case along with the rest of the sentence. This article discusses how to do that in C#.

    For example the user was interested in changing

    “ALL QUIET ON THE WESTERN FRONT”

       to

    “All Quiet on the Western Front.”

    .Net Framework Almost Does It

    Thanks to the TextInfo class and a helping hint from a current CultureInfo object we can use the method ToTitleCase to work with our current language. The problem is that when ToTitleCase is called with the original sentence we get this:

    “All Quiet On The Western Front”

    Give it some Help

    The .Net code is not robust enough to ignore the articles and prepositions so we will augment it. The following code using Linq-to-Object and Regex and processes majority of the target articles and prepositions . I have placed it into an extension method below:

    /*
    using System.Globalization;
    using System.Threading;
    using System.Text.RegularExpressions;
    */
    
    /// <summary>
    /// An Extension Method to allow us t odo "The Title Of It".asTitleCase()
    /// which would return a TitleCased string.
    /// </summary>
    /// <param name="title">Title to work with.</param>
    /// <returns>Output title as TitleCase</returns>
    public static string asTitleCase ( this string title)
    {
        string WorkingTitle = title;
    
        if ( string.IsNullOrEmpty( WorkingTitle ) == false )
        {
            char[] space = new char[] { ' ' };
    
            List<string> artsAndPreps = new List<string>()
                { "a", "an", "and", "any", "at", "from", "into", "of", "on", "or", "some", "the", "to", };
    
            //Get the culture property of the thread.
            CultureInfo cultureInfo = Thread.CurrentThread.CurrentCulture;
            //Create TextInfo object.
            TextInfo textInfo = cultureInfo.TextInfo;
    
            //Convert to title case.
            WorkingTitle = textInfo.ToTitleCase( title.ToLower() );
    
            List<string> tokens = WorkingTitle.Split( space, StringSplitOptions.RemoveEmptyEntries ).ToList();
    
            WorkingTitle = tokens[0];
    
            tokens.RemoveAt(0);
    
            WorkingTitle += tokens.Aggregate<String, String>( String.Empty, ( String prev, String input )
                                    => prev +
                                        ( artsAndPreps.Contains( input.ToLower() ) // If True
                                            ? " " + input.ToLower()              // Return the prep/art lowercase
                                            : " " + input ) );                   // Otherwise return the valid word.
    
            // Handle an "Out Of" but not in the start of the sentance
            WorkingTitle = Regex.Replace( WorkingTitle, @"(?!^Out)(Out\s+Of)", "out of" );
        }
    
        return WorkingTitle;
    
    }
    Explanation
    • Line 21: Here is our English list of words not to capitalize. We would have to change this for other languages.
    • Line 25: We get the current culture from the running thread so that ToTitleCase can do its job.
    • Line 30: ToTitleCase does the first run and upper cases all the first letters and drops any following upper case letters if they exist.
    • Line 32: We split the line on space between the words into word tokens and put them in a list.
    • Line 34: We save off the first word because regardless of what it is, it is correct.
    • Line 36: We remove the first word so not to process it.
    • Line 40: Using the Aggregate extension to accumulate each word token we will add a space. We are using the aggregate method in-lieu of string.Join to add spaces to our words (the accumulation), but also to check each word as it goes by which string.Join can’t help us with.
    • Line 42: As the tokens (words) are handed to us, check to see if they are in the list we setup in line 21. If it exists, add a space in front and make the whole word lower case (Line 43) other wise ad a space and just return the word.
    • Line 46: Handle any two word Out Of issues, but ignore if it is the first word as found in “Out of Africa”.
    Tests and Results

     

    Console.WriteLine( "ALL QUIET ON THE WESTERN FRONT".asTitleCase() );
    Console.WriteLine( "Bonfire OF THE Vanities".asTitleCase() );
    Console.WriteLine( "The Out-of-Sync Child: Recognizing and Coping with Sensory Processing Disorder".asTitleCase() );
    Console.WriteLine( "Out OF AFRICA".asTitleCase() );
    
    /* Results
    All Quiet on the Western Front
    Bonfire of the Vanities
    The Out-Of-Sync Child: Recognizing and Coping With Sensory Processing Disorder
    Out of Africa
    */
    Share

    Tags: , , ,

    C# Extracting CSV data into Linq and a Dictionary using Regular Expressions

    One is uniqueI had written a post a while back which detailed a regular expression pattern used by the .Net regex parser which parsed a Comma Separated Value file, or a CSV file for short. Upon looking at the pattern I came to realize that the pattern didn’t work for all situations. So I have created a new pattern which will extract all items from the CSV data into into a dynamic anonymous Linq entity.  Following that example I will show one how to use the same Linq entity to put that CSV data into a dictionary, a hash table, where the key of entry is the first column’s data.

    CSV Considerations

    1. Data separated by a comma.
    2. Quotes, single or double are an optional encapsulation of data.
    3. Any data which has a comma must be encased in quotes.
    4. Quoted data can be single or double quote.
    5. Data rows can be ragged.
    6. Null data handled except for last column
    7. Last data column cannot be null.
    'Alpha',,'01000000043','2','4',Regex Space
    'Beta',333,444,"Other, Space",No Quote Space,'555'

    Regular Expression Pattern

    The things of note about the below pattern are

    • Pattern needs Regex Options. Those options for this article are defined both in the pattern and the call to the regular expression parser; normalcy only its done only once.
      1. Pattern commented so IgnorePatternWhitespace option is needed. Note that option does not affect the regex parsing of the data.
      2. Multiline option needed so ^ matches the beginning of each line and $ matches the end, after the \r\n.
    • Regular Expression if condition is used to test if the indivudal column data is enclosed in quotes. If it finds a quote it consumes the quotes but does not pass them on to the final data processing.
    • Each line will correspond to one match
    • All data  put into named match capture called Column; hence the match will have all line values in the capture collection named Column.
    (?xm)                        # Tell the compiler we are commenting (x = IgnorePatternWhitespace)
                                 # and tell the compiler this is multiline (m),
                                 # In Multiline the ^ matches each start line and $ is each EOL
                                 # -Pattern Start-
    ^(                           # Start at the beginning of the line always
     (?![\r\n]|$)                # Stop the match if EOL or EOF found.
     (?([\x27\x22])              # Regex If to check for single/double quotes
          (?:[\x27\x22])         # \\x27\\x22 are single/double quotes
          (?<Column>[^\x27\x22]*)# Match this in the quotes and place in Named match Column
          (?:[\x27\x22])
    
      |                          # or (else) part of If when Not within quotes
    
         (?<Column>[^,\r\n]*)    # Not within quotes, but put it in the column
      )                          # End of Pattern OR
    
    (?:,?)                       # Either a comma or EOL/EOF
    )+                           # 1 or more columns of data.

    Regex to Linq

    Here is the code which will enumerate over each match and add the contents of the match capture collection into a dynamic linq entity. Notes:

    1. tThe code below uses the regex pattern mentioned above but does not show it for brevity.
    2. The regex options are set twice for example. One only needs to set them once.
    string pattern = @" ... ";
    
    
    string text = /* Note the ,, as a null situation */
    @"'Alpha',,'01000000043','2','4',Regex Space
    'Beta',333,444,""Other, Space"",No Quote Space,'555'";
    
    // We specified the Regex options in teh pattern, but we can also specify them here.
    // Both are redundant, decide which you prefer and use one.
    var CSVData = from Match m in Regex.Matches( text, pattern, RegexOptions.IgnorePatternWhitespace | RegexOptions.Multiline )
                  select new
                  {
                      Data = from Capture cp in m.Groups["Column"].Captures
                             select cp.Value,
                  };
    
    int lineNo = 0;
    
    foreach ( var line in CSVData )
        Console.WriteLine( string.Format("Line #{0}:  {1}", ++lineNo, string.Join( "|", line.Data.ToArray() ) ));
    
    /* Output
    
    Line #1:  1||01000000043|2|4|Regex Space
    Line #2:  2|333|444|Other, Space|No Quote Space|555
    
    */

    Linq To Dictionary

    Taking the same code above, specifically the dynamic Linq entity holder CSVData, we will transform it into a dictionary where the key into the hashtable is the first CSV column data item.

    // Put into Dictionary where the key is the first csv column data.
    // Note the below creates a KeyValuePair using an integer for the
    // key whichextracted as the parsing goes on. It is not used. It
    // is simply shown for example of getting the index from Linq and
    // could be change to use the first column instead.
    
    Dictionary<string, List<string>> items2 =
        CSVData.Select( ( a, index ) => new KeyValuePair<int, List<string>>( index, a.Data.ToList() ) )
               .ToDictionary( kvp => kvp.Value[0], kvp => kvp.Value );
    
    
    foreach ( KeyValuePair<string, List<string>> kvp in items2 )
          Console.WriteLine( "Key {0} : {1}", kvp.Key, string.Join( "|", kvp.Value.ToArray() ) );
    
    /*
    Key Alpha : Alpha||01000000043|2|4|Regex Space
    Key Beta : Beta|333|444|Other, Space|No Quote Space|555
    */

    Full Code

    string pattern = @"
    (?xm)                        # Tell the compiler we are commenting (x = IgnorePatternWhitespace)
                                 # and tell the compiler this is multiline (m),
                                 # In Multiline the ^ matches each start line and $ is each EOL
                                 # Pattern Start
    ^(                           # Start at the beginning of the line always
     (?![\r\n]|$)                # Stop the match if EOL or EOF found.
     (?([\x27\x22])              # Regex If to check for single/double quotes
          (?:[\x27\x22])         # \\x27\\x22 are single/double quotes
          (?<Column>[^\x27\x22]*)# Match this in the quotes and place in Named match Column
          (?:[\x27\x22])
    
      |                          # or (else) part of If when Not within quotes
    
         (?<Column>[^,\r\n]*)    # Not within quotes, but put it in the column
      )                          # End of Pattern OR
    
    (?:,?)                       # Either a comma or EOL/EOF
    )+                           # 1 or more columns of data.";
    
    
    string text = /* Note the ,, as a null situation */
    @"'Alpha',,'01000000043','2','4',Regex Space
    'Beta',333,444,""Other, Space"",No Quote Space,'555'";
    
    // We specified the Regex options in teh pattern, but we can also specify them here.
    // Both are redundant, decide which you prefer and use one.
    var CSVData = from Match m in Regex.Matches( text, pattern, RegexOptions.IgnorePatternWhitespace | RegexOptions.Multiline )
                  select new
                  {
                      Data = from Capture cp in m.Groups["Column"].Captures
                             select cp.Value,
                  };
    
    int lineNo = 0;
    
    foreach ( var line in CSVData )
        Console.WriteLine( string.Format("Line #{0}:  {1}", ++lineNo, string.Join( "|", line.Data.ToArray() ) ));
    
    /* Output
    
    Line #1:  1||01000000043|2|4|Regex Space
    Line #2:  2|333|444|Other, Space|No Quote Space|555
    
    */
    
    // Put into Dictionary where the key is the first csv column data.
    // Note the below creates a KeyValuePair using an integer for the
    // key whichextracted as the parsing goes on. It is not used. It
    // is simply shown for example of getting the index from Linq and
    // could be change to use the first column instead.
    
    Dictionary<string, List<string>> items2 =
        CSVData.Select( ( a, index ) => new KeyValuePair<int, List<string>>( index, a.Data.ToList() ) )
               .ToDictionary( kvp => kvp.Value[0], kvp => kvp.Value );
    
    
    foreach ( KeyValuePair<string, List<string>> kvp in items2 )
          Console.WriteLine( "Key {0} : {1}", kvp.Key, string.Join( "|", kvp.Value.ToArray() ) );
    
    /*
    Key Alpha : Alpha||01000000043|2|4|Regex Space
    Key Beta : Beta|333|444|Other, Space|No Quote Space|555
    */
    Share

    Tags: , , ,

    C# Regex Linq: Extract an Html Node with Attributes of Varying Types

    iStock_000008717494XSmall

    The premise of this article and subsequent code sample is that one has an html node to parse and needs the parsed node’s attributes accessible in a handy fashion. Using Regular Expressions with Linq  we can achieve our goal and examine all attributes of the html node. I will show the steps to take and pitfalls on using other methodology.

    Data

    <INPUT onblur=google&&google.fade&&google.fade() class=lst title='Google Search' value=TESTING maxLength=2048 size=55 name=q autocomplete='off' init='true'/>

    Why Not Use XElement’s Attributes?

    Because of the free-form text found in the html the following code throws an exception on the first attribute encountered:

    string test = @"<INPUT onblur=google&&google.fade&&google.fade() class=lst title='Google Search' value=TESTING maxLength=2048 size=55 name=q autocomplete='off' init='true'>";
    
    // Fails saying google is unexpected token!
    var input = XElement.Parse( test )
                        .Attributes()
                        .Select( vl => new KeyValuePair<string, string>( vl.Name.ToString(), vl.Value.ToString() ) );
    
    foreach ( KeyValuePair<string, string> item in input )
        Console.WriteLine( "Key: {0,15} Value: {1}", item.Key, item.Value );

    Step 1: Regex

    Our first step is to create a regular expression which can handle the node and its attributes. What is interesting about the below regex pattern is that it uses an if clause to discriminate if the attribute contains the value in quotes, single or double, and will put them into the captures collection.

    (?:<)(?<Tag>[^\s/>]+)       # Extract the tag name.
    (?![/>])                    # Stop if /> is found
    # -- Extract Attributes Key Value Pairs  --
    
    ((?:\s+)             # One to many spaces start the attribute
     (?<Key>[^=]+)       # Name/key of the attribute
     (?:=)               # Equals sign needs to be matched, but not captured.
    
    (?([\x22\x27])              # If quotes are found
      (?:[\x22\x27])
      (?<Value>[^\x22\x27]+)    # Place the value into named Capture
      (?:[\x22\x27])
     |                          # Else no quotes
       (?<Value>[^\s/>]*)       # Place the value into named Capture
     )
    )+                  # -- One to many attributes found!
    

    The above will find a match on a node, place the tag into the named capture of Tag. Then each attribute will be in two named capture collections of Key Value

    Regex Returns A Match…Now What?

    We need to extract the items into a Dictionary of key value pairs. The following code works with the name match captures and its indexed captures and extracts all attributes (Note copy code to clipboard or view to get alignment):

    var attributes = ( from Match mt in Regex.Matches( node, pattern, RegexOptions.IgnorePatternWhitespace )
                       select new
                       {
                           Name = mt.Groups["Tag"],
                           Attrs = ( from cpKey in mt.Groups["Key"].Captures.Cast<Capture>().Select( ( a, i ) => new { a.Value, i } )
                                     join cpValue in mt.Groups["Value"].Captures.Cast<Capture>().Select( ( b, i ) => new { b.Value, i } ) on cpKey.i equals cpValue.i
                                     select new KeyValuePair<string, string>( cpKey.Value, cpValue.Value ) ).ToDictionary( kvp => kvp.Key, kvp => kvp.Value )
                       } ).First().Attrs;

    What the above is doing is enumerating over all the matches, in this case there is only one. Then we work through all the keys in the “Key” captures array and marry them to the “Value” value in that array on a one-to-one basis. Notice how we can index into a joined array via its index thanks to the specialized select which returns the index value. Finally we express those combined items  into a key value pair.

    Full Code and Result

    string node = @"<INPUT onblur=google&amp;&amp;google.fade&amp;&amp;google.fade() class=lst title='Google Search' value=TESTING maxLength=2048 size=55 name=q autocomplete='off' init='true'/>";
    string pattern =@"
    (?:<)(?<Tag>[^\s/>]+)       # Extract the tag name.
    (?![/>])                    # Stop if /> is found
                         # -- Extract Attributes Key Value Pairs  --
    
    ((?:\s+)             # One to many spaces start the attribute
     (?<Key>[^=]+)       # Name/key of the attribute
     (?:=)               # Equals sign needs to be matched, but not captured.
    
    (?([\x22\x27])              # If quotes are found
      (?:[\x22\x27])
      (?<Value>[^\x22\x27]+)    # Place the value into named Capture
      (?:[\x22\x27])
     |                          # Else no quotes
       (?<Value>[^\s/>]*)       # Place the value into named Capture
     )
    )+                  # -- One to many attributes found!";
    
    var attributes = ( from Match mt in Regex.Matches( node, pattern, RegexOptions.IgnorePatternWhitespace )
                       select new
                       {
                           Name = mt.Groups["Tag"],
                           Attrs = ( from cpKey in mt.Groups["Key"].Captures.Cast<Capture>().Select( ( a, i ) => new { a.Value, i } )
                                     join cpValue in mt.Groups["Value"].Captures.Cast<Capture>().Select( ( b, i ) => new { b.Value, i } ) on cpKey.i equals cpValue.i
                                     select new KeyValuePair<string, string>( cpKey.Value, cpValue.Value ) ).ToDictionary( kvp => kvp.Key, kvp => kvp.Value )
                       } ).First().Attrs;
    
    
    foreach ( KeyValuePair<string, string> kvp in attributes )
        Console.WriteLine( "Key {0,15}    Value: {1}", kvp.Key, kvp.Value );
    
    /* Output:
    Key          onblur    Value: google&amp;&amp;google.fade&amp;&amp;google.fade()
    Key           class    Value: lst
    Key           title    Value: Google Search
    Key           value    Value: TESTING
    Key       maxLength    Value: 2048
    Key            size    Value: 55
    Key            name    Value: q
    Key    autocomplete    Value: off
    Key            init    Value: true
    */
    
    Share

    Tags: , ,

    C# Tribal Knowledge: Use of the Conditional Attribute for Conditional Compilation For Object and and Argument Validation during Development

    stockxpertcom_id14589271_jpg_013ced4118ce4854e1935aeaa12684ecThis is another one of of my topics which I deem to be Tribal Knowledge type information. For me it seems that such information seems be known by only the privileged few. In this article I present for your reading perusal details on how to handle different state errors found in classes and arguments during debug/development activities. The premise is that such checks for object or argument correctness is only needed for development and not for production level code. By using the Conditional attribute in ones C# code such checks can be utilized for object and state correctness but not be a burden in a production program or web site.

    Development State Errors Checking

    For example, and yes its a basic example,  say one is writing a database layer and the requirement is that the connection string be be properly filled with with a database name a user name and a password. You happen to know that this code will be reused by others on the development staff and they will most likely fail to provide such values the first time they hook up the code. So you don’t have to go to their desks to hand hold and debug the error, wouldn’t it be nice if the object checked its own state of correctness?

    Once working the checks will really become superfluous and will be removed. This scenario speaks to the fact that the user has two options, or two roads to failure, of loading the values. Say it can be done either during construction or after via the exposed properties. Just ripe for someone to forget to do one or the other.

    Code Speaks Conditionally

    For the code we will create a connection object which checks for the validity, to the best of its ability, of those values before their use, and if a problem exists throw an application exception during development time only.

    Here is our code and the highlight lines are related to the state checking:

    using System.Diagnostics;
    
    public class ConnectionManager
    {
        public string DatabaseName { get; set; }
        public string UserName     { get; set; }
        public string Password     { get; set; }
    
        public ConnectionManager() { }
    
        public ConnectionManager( string databaseName, string userName, string password )
        {
            DatabaseName = databaseName; UserName = userName; Password = password;
        }
    
        public string GenerateConnectionString()
        {
            // This is only called during debug builds and *not compiled*
            ValidateState(); // during Release builds.
    
            return string.Format( "{0};User={1};Password={2}", DatabaseName, UserName, Password );
        }
    
        [Conditional( "Debug" )]
        private void ValidateState()
        {
            if ( string.IsNullOrEmpty( DatabaseName ) )
                throw new ApplicationException( "Development Error: DatabaseName Empty" );
    
            if ( string.IsNullOrEmpty( UserName ) )
                throw new ApplicationException( "Development Error: UserName Empty" );
    
            if ( string.IsNullOrEmpty( Password ) )
                throw new ApplicationException( "Development Error: Password Empty" );
    
        }
    
    }

    So if this class is instantiated and the proper variables are not setup an application exception is thrown during debug mode only when a call to generate a connection string occurs. The magic is done by the highlighted lines but the second one with Conditional attribute tells the compiler to only use this in debug builds

    Summary

    Now this example is a bit contrived, but the idea is that if one has unique business state requirements which may need to be met before an object’s operation can be used, this methodology can be used to catch all actions, but not hamper runtime operations. It obviously shouldn’t be used to catch unique runtime scenarios such as user validation, those should be handled directly and possibly not by generating an exception.

    Share

    Tags: , ,

    Tribal Knowledge: EWS C# Extract Alternate Email Address’ Mailbox

    stockxpertcom_id260320_jpg_7150e45f4e023f0d664c8903434549ef This is what I call a Tribal Knowledge (TK) type of  information. TK is something that is obvious to those who work with it, or have been using it for a long time yet to the new person coming along its a mystery. Accessing a different mailbox using Exchange Web Services (EWS) was such an event for me. I had actually tapped Microsoft Premier Support to get this answer but was able to divine it at the last moment.

    Why Is This Confusing?

    The reason behind this confusion is how one registers a service with Exchange Web Services. Here is a snippet below:

    ExchangeService service = new ExchangeService( ExchangeVersion.Exchange2007_SP1 );
    
    service.AutodiscoverUrl( "Omega.Man@MyCompany.com" );

    When we pass the email address to Autodiscover we believe that it is registering the account we want to access. Usually when one is developing against EWS they use their mailbox as the target first and will have no problems. (See my article entitled C#: Getting All Emails From Exchange using Exchange Web Services for how process emails from the inbox.)

    Once the developer access the inbox and retrieves emails, the next step is to attempt access to a shared mailbox. That inbox is shown in Outlook and the user’s account has access rights to it. So the developer does this and erroneously uses Autodiscover again:

    service.AutodiscoverUrl( "SharedMailboxNotPrimaryAccount@MyCompany.com" );

    Well it actually works, sort of… the service doesn’t throw an exception, but when on tries to get email, its the primary email inbox that is gotten and not the specified email! The problem is that autodiscover could frankly care less about the who, its only concerned with the @xxxx.com to facilitate its processing. Very disingenuous eh…

    Solution

    Get the service with the email address as shown above (either one will work actually), but before EWS mail box processing add these lines:

    Mailbox mb = new Mailbox( "SharedMailboxNotPrimaryAddress@MyCompany.com" );
    
    FolderId fid1 = new FolderId( WellKnownFolderName.Inbox, mb );
    
    FindFoldersResults findResults = service.FindFolders(
                    fid1, // was WellKnownFolderName.Inbox,
                    new FolderView( int.MaxValue ) );

    That lets EWS know about which mailbox we want to use. It handles the getting of the folder ID (different from the ID you might use in Outlook Interop programming if you got it that way; btw) and all is well.

    HTH

    Share

    Tags: