Posts Tagged Linq

C# Linq: Find Missing Values in a Sequence of Numbers and Other Sequence Related lists as IEnumerable Extensions

Water bubble and wavesI recently had a need to determine if a sequence of integers was solid, not broken, and whether it contained a gap of any missing numbers to report to the end user. I researched the issue and was dismayed that the examples found on the internet seemed to have unnecessary overheads of copied arrays or other artifacts and were too cumbersome for my needs. From that I wrote these C# extensions which work for any .Net above 3.5. Below I document the extension methods to get the missing numbers of a sequence, quickly determine if a sequence is broken and finally report where the existing numbers before the break of the sequence. See the end for the whole extension class for easier copying.

Problem Definition

If one has a set of numbers say

{ 2, 4, 7, 9 }

it has a broken sequence because there are missing numbers from the set 2-9. Those missing numbers are:

{ 3, 5, 6, 8 }

Find Missing Numbers In a Sequence

This method is the one I created first. It uses the Linq Aggregate extension to enumerate over the numbers in the set. If there is a gap which is greater than 1 between the numbers (the difference below is > 0 but same concept) then it reports the numbers missing between the two.

public static IEnumerable<int> SequenceFindMissings(this IList<int> sequence)
{

    var missing = new List<int>();

    if ((sequence != null) && (sequence.Any()))
    {
        sequence.Aggregate((seed, aggr) =>
                            {
                                var diff = (aggr - seed) - 1;

                                if (diff > 0)
                                    missing.AddRange(Enumerable.Range((aggr - diff), diff));

                                return aggr;
                            });
    }

    return missing;
}

Quickly Determine Broken Sequence

Is the sequence broken from the first number to the last in the set?

public static bool IsSequenceBroken(this IEnumerable<int> sequence)
{
    bool broken = false;

    if (sequence != null) 
    {
        var sequenceAsList = sequence.ToList();

        if (sequenceAsList.Any())
        {
            int lastValue = sequence.First();

            broken = sequence.Any(value =>
                                    {
                                        if ((value - lastValue) > 1)
                                            return true;

                                        lastValue = value;

                                        return false;
                                    }); 
        }
    }

    return broken;
}

Report Last Valid Number Before The Break

This is useful in situations where one needs to report where the break happens, say the user is editing in a grid and one highlights the existing number which precedes the missing number(s).

Example here returns a 2 and 5 which are the numbers which precede the break.

   (new List() { 1, 2, 4, 5, 7, 8}).SequenceReportMissingsBreakStarts()

Here is the method:

public static IEnumerable<int> SequenceReportMissingsBreakStarts(this IList<int> sequence)
{

    var breaks = new List<int>();

    if ((sequence != null) && (sequence.Any()))
    {

        sequence.Aggregate((seed, aggr) =>
                            {
                                var diff = (aggr - seed) - 1;

                                if (diff > 0)
                                    breaks.Add(seed);
                                return aggr;
                            });
    }

    return breaks;
}

Full Extension Source With Comments

Here is the code for an easier copy

public static class SequenceExtensions
{
    /// <summary>
    /// Take a sequence of numbers and if there are any gaps greater than 1 between the numbers,
    /// report true.
    /// </summary>
    /// <param name="sequence">A set of numbers to check.</param>
    /// <returns>True if the there is a break in the sequence of numbers.</returns>
    public static bool IsSequenceBroken(this IEnumerable<int> sequence)
    {
        bool broken = false;

        if (sequence != null)
        {
            var sequenceAsList = sequence.ToList();

            if (sequenceAsList.Any())
            {
                int lastValue = sequence.First();

                broken = sequence.Any(value =>
                                        {
                                            if ((value - lastValue) > 1)
                                                return true;

                                            lastValue = value;

                                            return false;
                                        });
            }
        }

        return broken;
    }

    /// <summary>
    /// Take a sequence of numbers and report the missing numbers. Stop at first break found.
    /// </summary>
    /// <param name="sequence">Set of Numbers</param>
    /// <returns>True of sequence has missing numbers</returns>
    public static IEnumerable<int> SequenceFindMissings(this IList<int> sequence)
    {

        var missing = new List<int>();

        if ((sequence != null) && (sequence.Any()))
        {
            sequence.Aggregate((seed, aggr) =>
                                {
                                    var diff = (aggr - seed) - 1;

                                    if (diff > 0)
                                        missing.AddRange(Enumerable.Range((aggr - diff), diff));

                                    return aggr;
                                });
        }

        return missing;

    }

    /// <summary>
    /// A missing break start in a sequence is where the drop off occurs in the sequence.
    /// For example 3, 5, has a missing break start of the #3 for #4 is the missing.
    /// </summary>
    /// <param name="sequence">Set of Numbers</param>
    /// <returns>The list of break numbers which exist before the missing numbers.</returns>
    public static IEnumerable<int> SequenceReportMissingsBreakStarts(this IList<int> sequence)
    {

        var breaks = new List<int>();

        if ((sequence != null) && (sequence.Any()))
        {

            sequence.Aggregate((seed, aggr) =>
                                {
                                    var diff = (aggr - seed) - 1;

                                    if (diff > 0)
                                        breaks.Add(seed);
                                    return aggr;
                                });
        }

        return breaks;

    }
}

Hope this helps!

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# 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# Linq How To Load a Winform Control Using Dynamic Linq entitites (Or any other Control)

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

Steps

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

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

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

Result

GridView

Share

Tags: , , ,

Tribal Knowledge: Linq Entities To Do Your Bidding via the Partial Keyword in C#

TribalKnowledge2Having premade entities created during the Linq process in .Net really comes in handy. But did you know that one can extend those entities further outside of of the generated dbml file? By using the concept introduced in C# 2.0 of a partial class, where one can have business logic methods and other properties which are not generated but are none the less relevant in an Object Oriented fashion it can be achieved.

As mentioned the entities are generated and nothing is worse than having the generator throw away user code placed in the generated file after a regeneration. To allow for generated and user code to coexist hand in hand was accomplished by partial classes. That is where the partial keyword is appended to a class which allows for the class to have a subset of functionality in a different code file. The generated code file resides in one file and the user code lives elsewhere in a different file allowing them co-exist.

I have used this process to put validation logic on an entity. That logic was used to verify that the differing properties which the user had entered values against matched business rules. Those rules could not be entirely expressed in a database schema. It was very Handy!

Example

A user posted a question on the MSDN Forums as to how one could achieve indexing into a Linq generated class entity where each property represented a numerated indexed field. The below code shows the use of a partial class in a separate file which the user could  have an index-able entity.

public partial class Request
{
    public int this[int index]
    {
        get
        {
            int retValue;

            switch ( index )
            {
                case 0: retValue = Val1; break;
                case 1: retValue = Val2; break;
                case 2: retValue = Val3; break;
            }

            return retValue;
        }
        set
        {
            switch (index)
            {
                case 0: Val1 = value; break;
                case 1: Val2 = value; break;
                case 2: Val3 = value; break;
            }
        }
    }
}
Share

Tags: , , ,

Linq vs. DataReader; Visual Examples Showing That Linq Does it in Fewer Lines of Code

Bridges I recently replied to a post in the MSDN C# General forum (one of the best places to get help if you have C# question) where the user was getting data from a DataReader and needed help with null values being returned. What I ended up discovering was differences from old way of getting data from a database in .Net and the new way. Such as the highways above both go to the same location and essentially do the same thing, but the contrast is so much different. Same holds true for .Net Linq and the DataReader.

In the post I recommend the use of the null-coalescing operator to handle the null returned from the database. Erroneously I forgot that the DataReader returns a DBNull which cannot be handled by the null-coalescing operator. GRRR

My mistake was based in the fact that I have become used to the Linq Data Context returning a INullable<T> when dealing with null fields in a database. The the null-coalescing operator can handle that to a tee.

I created my test code and realized that it demonstrated the following

  1. Linq does so much for the developer that what previously took around six plus lines of code boils down to roughly three. It manages so much in the background for the user that it allows for quicker coding to get at data.
  2. The design of Linq handles Nulls differently, or at lease presents them to the end user from the old way processing. Using the null-coalescing operator as shown is a great help.

Here is the example code, first up is Linq and the target operation is to display values from a nullable field in the database called Description. When enumerating over the data rows, if that field happens to be null it reports it or shows the actual data. Next up is the older way of doing it and notice how the user has to handle reader. Note one could check for DBNull in that situation, so the example may not be what you are looking to do in a real system.

GTCDataContext gtc = new GTCDataContext();

var items = gtc.Location_US;

foreach ( var it in items )
   Console.WriteLine( it.Description ?? "not Defined" );

string queryString = "SELECT Description FROM dbo.Location_US;";

using ( SqlConnection connection = new SqlConnection( gtc.Connection.ConnectionString  ))
{
   SqlCommand command = new SqlCommand( queryString, connection );    connection.Open();

   SqlDataReader reader = command.ExecuteReader();

   // Call Read before accessing data.
   while ( reader.Read() )
   {
      Console.WriteLine( (string.IsNullOrEmpty(reader[0].ToString()) == false) ?  reader[0] : "not defined again" );
   }

    // Call Close when done reading.
    reader.Close();
}

Here is the result of the run:

Florida

not Defined

Colorado

California

not Defined

not Defined

not Defined

not Defined

—————————————–

Florida

not defined again

Colorado

California

not defined again

not defined again

not defined again

not defined again

Share

Tags: , , , , ,

Asp.Net DropDownList bound with Linq Data Example

I recently answered a post where the user was using ASP .Net 3.5 but not binding data to a DropDownList but instead using hard coded data to load the drop down in the HTML. So I created this quick example to show Linq-To-Xml (Linq) loading of an Asp.Net DropDownList and handling the automatic postback selection changes.

As mentioned example shows how to bind data to a dropdown list using Linq, specifically Linq-To-Xml, but you could use any other of the Linq methodologies because we are using the anonymous types to work with the needs of the DropDownList.

First we will place the Asp.Net DropDownListon our page along with a label which will used to show state changes.

<asp:DropDownList ID="ddlMain"
      runat="server"
      AutoPostBack="true"
      OnSelectedIndexChanged="SelectionMade" />

<asp:Label ID="lblWhat" runat="server"/>

Nothing earth shattering here, we have AutoPostBack because we want the control to tell our code behind on the server when a selection has been made. Following that we have the method which will be called for that event of SelectionMade.

The next thing is to load the DropDownList with values to choose from. We will use an XElement loaded dynamically to show how to do do this in Linq. The other thing of note is that we only want load this once, so we check the postback status. If its a postback, we do not reload.

protected void Page_Load( object sender, EventArgs e )
{

if ( Page.IsPostBack == false ) // Only do this once
{
   // Simulate an Linq-To-SQL call with an Linq-To-SQL
   // So anyone can use this demo.
   XElement dataForList
       = new XElement(
           "DropDownData",
             new XElement( "Node",
                 new XElement( "Text", "Selection 1"  ),
                 new XElement( "Data", "1Selection" ) ),
             new XElement( "Node",
                 new XElement( "Text", "Selection 2" ),
                 new XElement( "Data", "2Selection"  ) ));


   var toTheScreen = from x in dataForList.Descendants( "Node" )
                 select new
                 {
                     Text = x.Descendants( "Text" ).First().Value,
                     Value = x.Descendants( "Data" ).First().Value
                 };

    ddlMain.DataTextField = "Text";
    ddlMain.DataValueField = "Value";
    ddlMain.DataSource = toTheScreen;
    ddlMain.DataBind();
}

}

As shown above we work through all the elements named Node. For each of those nodes we will create a new entity with two properties Text and Value. Text will be shown to the user and value is what is associated with the selection. In the binding operations we specify the Text and Value field for the DropDownList to use and simply bind it to our anonymous projection.

Now all we have to do is handle the selection change event

protected void SelectionMade( object sender, EventArgs e )
{
    DropDownList target = sender as DropDownList;

    if ( target != null )
        lblWhat.Text =
            string.Format(
                "Item {0} selected with Value of {1}",
                target.SelectedItem.Text,
                target.SelectedValue );
}

Nothing magical here, we get the DropDownList from the sender argument, divine the selection and update the label. Here is what it should look like after a change:

ddl

Share

Tags: , , ,

C# XML Parsing Extracting Values and using XML to Linq with XDocument

On my blog the most accessed articles are the basic ones on XML which has suprised me. So In this article I will focus on the new kid on the block the Linq derived XDocument. In the following example I will load the Xml then enumerate over the child nodes, to extract specific values and then display them.

I am loading the xml directly, but you can load it from other locations using the Load option of XDocument.

string xml = @"<?xml version='1.0' encoding='UTF-8'?>
<widgets>
    <widget>
        <url>~/Portal/Widgets/ServicesList.ascx</url>
        <castAs>ServicesWidget</castAs>
        <urlType>ascx</urlType>
        <parameters>
            <PortalCategoryId>3</PortalCategoryId>
        </parameters>
    </widget>
    <widget>
        <url>www.omegacoder.com</url>
        <castAs>ServicesWidget</castAs>
        <urlType>htm</urlType>
        <parameters>
            <PortalCategoryId>41</PortalCategoryId>
        </parameters>
    </widget>
</widgets>";

XDocument loaded = XDocument.Parse( xml );

var widgets = from x in loaded.Descendants( "widget" )
              select new
              {
                  URL = x.Descendants( "url" ).First().Value,
                  Category = x.Descendants( "PortalCategoryId" ).First().Value
              };

foreach ( var wd in widgets )
    Console.WriteLine( "Widget at ({0}) has a category of {1}", wd.URL, wd.Category );

/* Outputs:

Widget at (~/Portal/Widgets/ServicesList.ascx) has a category of 3
Widget at (www.omegacoder.com) has a category of 41

*/
Share

Tags: , ,