Sunday, March 14, 2010

LINQ To Entities in WinForm and Better Practice

There is a homework for week 2 UTS Short Course about LINQ To Entities. As a tutor, I find it is interesting and I never use LINQ before, so I spent sometime to do the homework in advance. Here is the homework mock-up and criteria,

















Figure: Mock-Up


Criteria:
On Search Button click, try to use some LINQ  magic to return employees that match that filter
  • Firstname match OR Lastname match
  • Filter on phone number as well
  • Try to filter on birth date if the text in the textbox is a date or the user writes "1979"
  • Try to implement filters like:  “Gfader 1979” returns all people with name Gfader and birthdate year 1979 

I use VS 2010 RC in this solution:














"Form1.cs" is my original version which is messy coding. After I took the advice from Peter about using Regex and reusable Iqueryable object, I create the "BetterPracticeForm.cs". So you can download the solution file if you interested to make a comparison.

In "BetterPracticeForm.cs", when search button fires, It will call the Text Parsing method (using Regex) :

//Format: BirthDate e.g. 22/12/1948
Regex birthDateRegex = new Regex(@"([1-9]|[12][0-9]|3[01])[- /.](0[1-9]|1[012])[- /.](19|20)\d\d$");

//Format: Phone Number e.g. (206) 555-9857 PS: Space is optional
Regex phoneNumRegex = new Regex(@"\(\d+\)\s?\d+[-]\d+$");

//Format: BirthYear e.g. 1959
Regex birthYearRegex = new Regex(@"(19|20)\d\d$");


Here is the checking if the SearchValue match Regex:

            bool noNameAndBirthYearflag = true;
            bool phoneNumFound = false;
            string phoneNumString = string.Empty;
            if (phoneNumRegex.IsMatch(searchValue))
            {
                phoneNumFound = true;
                phoneNumString = searchValue;
                noNameAndBirthYearflag  = false;
            }

            bool birthDateFound = false;
            string birthDateString = string.Empty;
            if(birthDateRegex.IsMatch(searchValue))
            {
                birthDateFound = true;
                birthDateString = searchValue;
                noNameAndBirthYearflag = false;
            }

            int tmepYear;
            int year = 0;
            bool yearFound = false;
            string[] inputKeywords = searchValue.Split();
            string nameString = string.Empty;

            if(noNameAndBirthYearflag)
            {
                foreach (var inputKeyword in inputKeywords)
                {

                    if (int.TryParse(inputKeyword, out tmepYear))
                    {
                        // number found!
                        if (birthYearRegex.IsMatch(tmepYear.ToString()))
                        {
                            // is a valid year
                            yearFound = true;
                            year = tmepYear;
                        }
                    }
                    else
                    {
                            nameString = inputKeyword;
                    }
                }
            }

 Here is the code of LINQ:

            using (NorthwindEntities data = new NorthwindEntities())
            {
                       var dq = data.Employees.Select(employee => new
                       {
                           employee.FirstName,
                           employee.LastName,
                           employee.Title,
                           employee.BirthDate,
                           employee.HomePhone
                       });

                if(noNameAndBirthYearflag )
                {
                    // Filter on year
                    if (yearFound)
                    {
                        dq = from employee in dq
                             where employee.BirthDate.Value.Year == year
                             select (new
                             {
                                 employee.FirstName,
                                 employee.LastName,
                                 employee.Title,
                                 employee.BirthDate,
                                 employee.HomePhone
                             });
                    }

                    // Filter on firstname lastname
                    if (string.IsNullOrEmpty(nameString) == false)
                    {
                        dq = dq.Where(employee=>(employee.FirstName.Contains(nameString) || employee.LastName.Contains(nameString))).Select(employee => (new
                        {
                            employee.FirstName,
                            employee.LastName,
                            employee.Title,
                            employee.BirthDate,
                            employee.HomePhone
                        }));
                    }
                }
                else
                {
                    // Filter phone number
                    if (phoneNumFound)
                    {
                        dq = from employee in dq
                             where employee.HomePhone == phoneNumString
                             select (new
                             {
                                 employee.FirstName,
                                 employee.LastName,
                                 employee.Title,
                                 employee.BirthDate,
                                 employee.HomePhone
                             });
                    }

                    // Filter birth date
                    if (birthDateFound)
                    {
                        DateTime dt = DateTime.Parse(birthDateString);
                        dq = from employee in dq
                             where
                                 employee.BirthDate.Value.Year == dt.Year && employee.BirthDate.Value.Month == dt.Month &&
                                 employee.BirthDate.Value.Day == dt.Day
                             select (new
                             {
                                 employee.FirstName,
                                 employee.LastName,
                                 employee.Title,
                                 employee.BirthDate,
                                 employee.HomePhone
                             });
                    }
                }
                dataGridViewResult.DataSource = dq;











Figure - Search Phone Number











Figure - Search Birth Date












Figure - Search FirstName Or LastName












Figure - Search Name and Birth Year











Figure - Search Birth Year


Here is the link for code downloading and link for Regex reference.
Also, here is the link from SSW about why we choose LINQ To Entities over LINQ To SQL.

Thanks for Peter giving me advice.

If you think here is any problems in my entry, please leave comments. I really appreciate it.

    Monday, March 1, 2010

    Using ListBox instead of ScrollViewer in Silverlight

    If you are thinking about scrolling image or text in silverlight, ScrollViewer might be the first thing to pop up in head. However, it is not always works.

    In my scenario, there is an auction-related project. It basically use silverlight to create UI similarly as below,


    The left Viewer is the connection and biding information. The right one is the DataGrid displaying the latest price for each items.


    In .xaml file, I was using ScrollViewer,
     <ScrollViewer Margin="25,0,-7,8" x:Name="connectViewer">
                    <TextBlock x:Name="lblMessages" Margin="1" TextWrapping="Wrap" Height="860" FontSize="8"></TextBlock>
                </ScrollViewer>

               
    In code behind,
    lblMessages.Text += message + Environment.NewLine;

    The problem is there is a limitation in the length of TextBlock. Because there are so many biding information which reach the limit of TextBlock, the new coming biding info won't be displayed in ScrollViewer.


    Solution:
    Use ListBox DataTemplate intead.

    Code in .xaml
     <ListBox x:Name="listBoxConnectInfo" Margin="25,0,-7,8">
                    <ListBox.ItemTemplate>
                        <DataTemplate>
                            <TextBlock Text="{Binding}" TextAlignment="Left" />
                        </DataTemplate>
                    </ListBox.ItemTemplate>
     </ListBox>

    In code behind,
    listBoxConnectInfo.Items.Add(message);

    So for every each time, it adds a TextBlock into ListBox and bind the message to the Text property.The more important thing is, it is scrollable as well.


    Hope that helps -:).
    Please don't hesitate to leave comments if you have better idea.