Monday, February 28, 2011

Highlight the column header and the first few cells in the DataGrid

In my application, I have a requirement, SelectionMode of the DataGrid has been set to Extend, and SelectionUnit is Cell, thus user can select each cell int the DataGrid, the first 4 or 5 columns in the data grid is used for display some information about the row,  so when user select a cell in the Grid, both the columnheader and the related information cell should be highlight , thus make it easier for user to understand what they are editing. like excel.
Originally I was thinking to hook up a function with the CurrentCellChanged event, and then when the cell is changed, I manually to find the columns that need to be highlighted, and apply a style to it. but it is ugly. so I am keep searching whether there is a better way to do that, finally I get it. 

In terms of select the column header,  First of all, we should create a style and bind it to the column header, put the following xaml expression to your style, trigger part.
<DataTrigger Value="True">
                                <DataTrigger.Binding>
                                    <MultiBinding Converter="{StaticResource IsHeaderCurrentConverter}">
                                        <Binding RelativeSource="{RelativeSource Self}" />
                                        <Binding Path="CurrentColumn" RelativeSource="{RelativeSource FindAncestor,AncestorType={x:Type DataGrid}}" />
                                    </MultiBinding>

                                </DataTrigger.Binding>
                                <Setter  TargetName="headerBorder" Property="Background"
                                Value="Red" />
                            </DataTrigger>

After that, create a convertor. 
public class IsHeaderCurrentConverter : IMultiValueConverter
    {

       
        #region IMultiValueConverter Members

        public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            bool bResult = false;
            if (values[1] != null)
            {
                DataGridColumnHeader dgch = values[0] as DataGridColumnHeader;
                System.Windows.Controls.DataGridTextColumn dgtc =
                    values[1] as System.Windows.Controls.DataGridTextColumn;
                if(dgtc.Header.ToString().CompareTo(dgch.Column.Header.ToString()) == 0)
                {
                    bResult = true;
                }
            }

            return bResult;
        }

        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }

        #endregion
    }

In the converter, if we return true, then the column header will be highlight with red.

Use the same theory , you can create a style to highlight the cells that you need to change when cell is selected.

Sunday, February 27, 2011

DataGrid, Create and load datatemplate on the fly.

Recently , I was investigating how to port a winform application to use WPF.  the winform application is intensively using DataGrid. But it is using a lot of code to handle the style and appearance. 

In WPF, we have data binding which is very flexible. Here is what I learned recently.

1.How to bind columns on the fly using code behind.

Assume you have a model class, which can return you a DataTable object, while the columns in the DataTable varies by the input parameter which you passed in when you invoke the function.  The data in the table cell is a custom data type(SiteData),base on the DataType property of MyCellData object, we should use different style to differentiate it,Base on the column name we should decide hide or show the column,How to bind the DataTable to a DataGrid?

To be clear, I post a function to generated the data here, so based on the code, you know What I mean.

   1:   public DataTable ToDataTable()
   2:          {
   3:              DataTable dt = new DataTable();
   4:              this.CreateDummyData();
   5:              dt.Columns.Add("Row1", typeof(RowHeadInfo));
   6:              dt.Columns.Add("Row2", typeof(RowHeadInfo));
   7:              for (var i = 2000; i <= 2020; i++)
   8:              {
   9:                  for (var j = 0; j <= 4; j++)
  10:                  {
  11:                      if(j == 0)
  12:                          dt.Columns.Add(string.Format("Y{0}", i, j), typeof(SiteData));
  13:                      else
  14:                          dt.Columns.Add(string.Format("Y{0}Q{1}", i, j), typeof(SiteData));
  15:                  }
  16:              }
  17:              foreach (var item in this._listRows)
  18:              {
  19:                  item.ToDataTable(dt);
  20:              }
  21:              return dt;
  22:          }



You might say just set the itemssource to the datatable, yeah, we should do that anyway, but it is not that easy, cause the data in the table is a custom data type, so you have to specify a binding to tell the grid which property to display, and we need trigger to change the style of display.


Eventually, we can’t write the DataGridColumns definition in xaml file. there are two solutions.


a)You can use a loop to go through the columns in the DataTable and then use code to add column to the DataGrid.  use this method, you have to set the AutoGeneratedColumns to false.


b)You can set the AutoGenerateColumn to true, while write a function to handle the AutoGeneratingColumn event. in this function , you can create and load data template use code.


   1:  private void dataGrid1_AutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
   2:          {
   3:              if (e.PropertyType == typeof(RowHeadInfo))
   4:              {
   5:                  DataGridTextColumn dgtc = new DataGridTextColumn();
   6:                  dgtc.IsReadOnly = true;
   7:                  dgtc.Binding = new Binding(e.PropertyName + ".RowName");
   8:                  dgtc.CellStyle = this.FindResource("RowHeaderSelectedStyle") as Style;
   9:                  dgtc.HeaderStyle = this.FindResource("NormalHeaderStyle") as Style;
  10:                  e.Column = dgtc;
  11:              }
  12:              else if (e.PropertyType == typeof(SiteData))
  13:              {
  14:                  DataGridTextColumn dgtc = new DataGridTextColumn();
  15:                  dgtc.Width = 50;
  16:                  dgtc.Binding = new Binding(e.PropertyName)
  17:                  {
  18:                      
  19:                      Converter = new DataCellConverter(),
  20:                      Mode = BindingMode.TwoWay
  21:                  };
  22:                  
  23:                  if (e.PropertyName.Contains("Q"))
  24:                  {
  25:                      dgtc.Visibility = Visibility.Hidden;
  26:                      dgtc.HeaderStyle = this.FindResource("NormalHeaderStyle") as Style;
  27:                  }
  28:                  else
  29:                  {
  30:                      dgtc.HeaderStyle = this.FindResource("NormalHeaderStyleWithCheckBox") as Style;
  31:                  }
  32:                  
  33:                  dgtc.CanUserSort = false;
  34:                  dgtc.Header = e.PropertyName;
  35:                  
  36:                  string strStyle = Properties.Resources.NormalDataCellStyle;
  37:                  string strValue = strStyle.Replace("{0}", e.PropertyName);
  38:                  XmlReader xr = XmlReader.Create(new StringReader(strValue));
  39:                  Style st = (Style)XamlReader.Load(xr);
  40:                  dgtc.CellStyle = st;
  41:                  e.Column = dgtc;
  42:              }
  43:          }





   1:  <Style  TargetType="{x:Type DataGridCell}"  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
   2:              <Setter Property="Background" Value="Green" />
   3:              <Setter Property="Foreground" Value="White" />
   4:              <Setter Property="HorizontalAlignment" Value="Stretch" />
   5:              <Setter Property="VerticalAlignment" Value="Center" />
   6:              <Style.Triggers>
   7:                  <DataTrigger Binding="{Binding Path={0}.SiteDataType}">
   8:                      <DataTrigger.Value>
   9:                          REPORT
  10:                      </DataTrigger.Value>
  11:                      <Setter Property="Background" Value="Red" />
  12:                  </DataTrigger>
  13:                  <DataTrigger Binding="{Binding Path={0}.SiteDataType}">
  14:                      <DataTrigger.Value>
  15:                          ESTIMATE
  16:                      </DataTrigger.Value>
  17:                      <Setter Property="Background" Value="Yellow" />
  18:                  </DataTrigger>
  19:                  <Trigger Property="IsSelected" Value="True">
  20:                      <Setter Property="Background" Value="Green" />
  21:                  </Trigger>
  22:              </Style.Triggers>
  23:          </Style>

Saturday, February 12, 2011

How to do DB load test

For a portal which with very high traffic, Database is the one the will directly affect the performance of your website, so every time, when you need to deploy some store procedure or database changes, you will always think that whether you stuff will greatly affect the sites. 

Recently In order to reproduce one db issue we came across, we are trying to reproduce it on our dev environment. but after quite a lot try, we don't have any luck. so we are thinking whether we can do some load test on our database.  fortunately , with VS2008 we can actually do that easily. You might ask ,a lot people are already on VS2010, but unfortunately , this feature had been turned off in VS2010, but it still there, if you want to use it , you have to buy it... so you know why Microsoft is rich...

I had done some search via internet, but didn't find too much articles introducing how to do it, so I write this post, hopefully it will help someone later on, knowledge should be shared. 

Step 1 , you should use your VS2008 to create a test project, it is easy
Step 2,In the solution explorer, right click your project name , on the coming out context menu, click add a unit test, then select database unit test, refer to the following snapshot.
Step 3, in the coming out dialog, it will ask you to select a database, if your database connection is already there, you can just select one, or create a new one.

step4, create the test, on the following snapshot reflect screen, you can just click the "click here to create" link to create a database unit test case. basically once you hit the link , it will go to code mode, and allow you to type in a SQL statement, which you used for test.
 
Code window
Step 5, add a load test, in your test project , go to solution explorer, and right click your project, on the coming out context menu


Follow the load test wizard, usually, for Database test, we select step load, which means we will increase user load steady until it reach the maximum.
In the test mix, you can select the database test , which you just created.
Then your database load test is ready. run it , and check the performance counters....





Thursday, February 10, 2011

How to play steam video in Silverlight 4.0

Today , I am investigating how to play video in Silverlight 4.0 ,  using MediaElement, it is quite easy to play a video in local disk , or hold in a server that can be accessed through http.  but unfortunately , our server is in a seperate server, and exposed as mms stream.  

it is quite headache , I was plan to use telerik's media play control, but it can't support mms stream as well. it takes me a few hours to look around, but no luck , finally I was thinking whether I can change the mms protocol to using http to see what will happen,  the interesting thing is , I change the mms to http at the video url, and paste to chrome, and I found I can access it and play it successfully in a browser.

so I use MediaElement, and change the video url protocol to http and set to the source property of MediaElement, it works smoothly....

Is that mean mms is based on http? need to figure this out.

Tuesday, February 8, 2011

Silverlight 4.0 drag and drop -- continue

In a previous post, I mentioned the drag and drop in Silverlight 4, cause we upgrade to SL 4 recently, we were using the Silverlight Toolkit, ListBoxDragDropTarget, but in Silverlight 4, the performance of drag and drop control is deteriorative , even the issue that sometimes it lost mouse key up can be fixed, but still can't meet user's expectation.

So these few days, I tried to use telerik's silverlight controls, basically the performance is much better, and user experience is much better.  drag and drop much more smooth than silverlight toolkit, of course it will be better cause you gonna to pay it.

To be honest the silverlight toolkit drag and drop is quite automatic, you don't need to write too much code to make the drag and drop to work.  in this way, you also don't have too much control over it. while the drag and drop control of telerik on the contract , it gives you more control and require you to implement more logic and code to make it work.

Secondly, toolkit drag and drop can show some very good indicator when you drag over your drop target. such as insert indicator, etc.. while telerik control doesn't have that.

BTW. before I move to third party controls, I also looked into the toolkit source code, and find there are intensively use LINQ , which complex the who logic, and finally make me give up fixing the issues.

Just for the reference of those who also come across the same issue and considering some third party controls.

Monday, February 7, 2011

avoid checking parameters at where clause.

Recently , we came across an issue, when massive traffic come in, one of our store procedure will trigger very very high CPU usage,  at some point, it trigger the CPU usage spike to 90% percent, which greatly increase the database response time, and our service is timing out, also it slow down the other websites which are also connecting this database.  In our dev environment , when we look at the store procedure, it looks totally fine, we check the execution plan, it is good as well, we are using index seek , nothing is expensive at all.
Today we create a load test using Visual Studio 2010, which can simulate 1000 or 2000 concurrent online user and be able to reproduce the issue, and we have an interesting finding.

We are doing parameter check at where clause.

assume In SQL Server, if you have store procedure, which can pass in an @UserID INT, when @UserID is 0, you would like to skip this parameter, only use it when @UserID is not zero.  so the SQL Statement you can write like this.

SELECT ID,REALNAME,USERNAME FROM USERS where (@UserID=0 OR ID=@UserID)

When you looked at this statement it is fine, and when you try it , it works as well but it is problematic.
a)When you have a lot of traffic on a store procedure that is implemented in this way, you will find this statement use far more CPU resource than others.  in our case, the store procedure cause the SQL Server CPU to spike , and it reach 90% , and keep high.  after we take this statement out, CPU usage goes down to around 50 percent.
b)if you write SQL Statement this way, SQL Server will not be able to pick up appropriate index.

So be careful, if you are writing some SQL statement which will be executed on a database with high traffic, please avoid it.

Saturday, February 5, 2011

Caculate how many one in a bit format of int value

Everyone knows that in computer, no matter what type you are using, finally it will be represent with bits , 0 and 1 .   For example
INT value    Bit
1                  0001
2                  0010
3                  0011
4                  0100
and so on....

A couple days ago, I was asked, given an int value, can you print out it in bit format, and caculate how many 1 in the bit level.

First of all, it is quite easy to get the bit string of the int value, just use convert function.
Secondly , caculate how many one in the bit string, you can use & operator and >> operator


   1:  class MainClass
   2:      {
   3:          static readonly int LENOFBIT = 8;
   4:          public static void Main (string[] args)
   5:          {
   6:              int iValueToTest = 12345;
   7:              string strBit = Convert.ToString(iValueToTest,2);
   8:              Console.WriteLine("int value {0} in bit format is {1}",iValueToTest,strBit);
   9:              Console.WriteLine("there are {0} one in bit format",CaculateOne(iValueToTest));
  10:                          
  11:          }
  12:          
  13:          static int CaculateOne(int iValue)
  14:          {
  15:              int iResult = 0;
  16:              int iLen = sizeof(int);
  17:              for(int i=0;i<iLen * LENOFBIT;i++)
  18:              {
  19:                  if((iValue & 1) == 1)
  20:                  {
  21:                      iResult ++;
  22:                  }
  23:                  iValue = iValue >> 1;
  24:              }
  25:              return iResult;
  26:          }
  27:          
  28:      }

You may ask , what the hell this is used for? assume you are implementing a user permission system,  you can use each bit to represent a permission, thus an int value can represent 32 permissions.