Saturday, June 30, 2012

Drag and Drop between list boxes in C#

Preamble

Yeah, you are not alone when you dream of dragging and dropping. I did dream too. It's such an infinite ecstasy when you feel the power of the mouse. Just clicking on an item, dragging it to some other window or control and to simply drop it there gives you a feeling of supremacy. Alright, I guess I better stop with this juvenile gobbledygook and start talking serious stuff. Just today morning I was thinking that it should be quite easy to drag and drop in .NET because that's what I have basically encountered whenever I tried to do something with .NET. Everything is always so much more easier than when you are doing normal SDK/MFC stuff or the Non-dot-Net stuff.
I created a simple C# Windows Forms application. Then I added two list boxes using the form designer. Now my intention was to fill up the list box on the left with some text. By the time I complete the small sample program, I should be able to drag an item from the list box on the left and to drop it on the list box on the right. It should have taken me only about an hour or so, but I was really stuck at one point and luckily for me, James T Johnson offered a word of advice and solved all my problems. He really is an amazing character, that JTJ, you would need to get really close to feel it though.

Screenshot

Well, before we proceed you can ogle at the screen shot made on *ahem* Windows XP Professional. I know most of you are thinking now that this guy seems to be crazy if he thinks using XP is a big deal. But alas, little do they know the tribulations faced by a 3rd worlder such as myself. In fact it's a bit of a good fortune that I am not still using DOS 5.0. Yeah, things are that bad.

Let's go ahead

The control from which we drag the item is called as a drag-drop source. In our case this would be the list box on the left. And similarly the control where we'll finally drop the dragged item is called the drag-drop target, which for us would be the list box on the right. For those of you who haven't dragged and dropped before [specially people coming from a Linux background], it's quite easy to accomplish. Click on an item, now without raising your finger off the mouse button drag the mouse cursor to some other point, and release the mouse button, whereby you drop the item on that precise point. Make sure you drop it on a drag-drop target control or window, otherwise the whole exercise would be meaningless.
The first thing we need to do is to make sure that the right list box is a drop target. Controls have a property called AllowDrop which we need to set to true. You can do this using the form designer or manually via code.
this.listBox2.AllowDrop = true;
Now we need to add a handler for the MouseDown event for the left list box. A MouseDown event occurs when you click the mouse anywhere within the list box control.
this.listBox1.MouseDown += new MouseEventHandler(
    this.listBox1_MouseDown);
Well, the MouseDown handler is simplicity itself. First we figure out which item is directly under the mouse, when it is clicked. For this purpose we use the IndexFromPoint function which turned out to be just what I wanted. This was where James was of immense help to me. He pointed out this nice little function to me just when I was groping like a drunken cat in deep black darkness. Well I simply cannot stop singing JTJ's praises today. Pardon me folks.
Once we have the text that is to be dragged, we call the DoDragDrop function. This function takes two parameters.
public DragDropEffects DoDragDrop(object data,
 DragDropEffects allowedEffects);
The first argument is the object that will be dragged out of the drag-drop source. In our case this will be the text of the item in the list box that is directly under the mouse. The second argument is a DragDropEffects enumeration. I am showing you the various values possible in the table below. Of course you can also look it up in MSDN. I am using DragDropEffects.All cause that's what we are doing. We copy the data to the target and remove it from the source. We need to check the value returned by DoDragDrop and if it is equal to DragDropEffects.All, this means that the item was safely dropped on a valid target and thus we remove the item from our list box. Otherwise we should not remove it as it means that the dropping was done in a meaningless area.
DragDropEffects Enumeration
Member Name Description
All The data is copied, removed from the drag source, and scrolled in the drop target.
Copy The data is copied to the drop target.
Link The data from the drag source is linked to the drop target.
Move The data from the drag source is moved to the drop target.
None The drop target does not accept the data.
Scroll Scrolling is about to start or is currently occurring in the drop target.
private void listBox1_MouseDown(
    object sender, System.Windows.Forms.MouseEventArgs e)
{ 
    if(listBox1.Items.Count==0)
        return;
    
    int index = listBox1.IndexFromPoint(e.X,e.Y);
    string s = listBox1.Items[index].ToString(); 
    DragDropEffects dde1=DoDragDrop(s,
        DragDropEffects.All);
 
    if(dde1 == DragDropEffects.All )
    { 
        listBox1.Items.RemoveAt(listBox1.IndexFromPoint(e.X,e.Y)); 
    } 
}
Alright, now that we have setup the drag-drop source we need to work on the drag-drop target which for us is the listbox on the right. There are four events associated with a drag-drop target. The events are DragEnter, DragOver, DragDrop and DragLeave. A DragEnter occurs when the mouse pointer has dragged something into the control's client area. A DragLeave occurs if it is dragged out of the control's client area without dropping the item. We won't concern ourselves with those two events.
The DragOver event occurs after the DragEnter event and we need to signal our readiness to accept the dropped item. We do this by setting the Effect property of the DragEventsArg object passed to the handler to one of the DragDropEffects enumerations. If we set this to DragDropEvents.None, then we have essentially rejected the drop.
private void listBox2_DragOver(
    object sender, System.Windows.Forms.DragEventArgs e)
{
    e.Effect=DragDropEffects.All;
}
The DragDrop event occurs if the mouse is releases on top of our control's client area. If we have not signaled our readiness to accept the drop, then instead of a DragDrop event a DragLeave event occurs. We are passed a DragEventArgs object as our second parameter. This has a IDataObject member called Data. We call the GetDataPresent member function on it to verify if the data format in the data is what we are expecting. In our case we are expecting a string. So we check with DataFormats.StringFormat. Then once we are sure the data is in the expected format we call GetData to retrieve our string and add it to our list box.
private void listBox2_DragDrop(
    object sender, System.Windows.Forms.DragEventArgs e)
{
    if(e.Data.GetDataPresent(DataFormats.StringFormat))
    { 
        string str= (string)e.Data.GetData(
            DataFormats.StringFormat);
            
        listBox2.Items.Add(str); 
    }
}
That's about it I guess. This is just a minimal introduction to dragging and dropping. But you can play around with it more. Feel free to post you comments on the article forum, but do not mail me directly, specially not to my busterboy.org email address. It's not a fast server for me and I do not enjoy popping too many mails from there. Thank You.

An editable multi-line listbox in C#



Overview

MultiLineListBox is a fully owner drawn ListBox derived class that supports multi-line items as well as in-place editing of items. It has been wrapped into a class library for ease of deployment. You don't have to do anything special when using it. Just use it as you would use a normal list box. Whenever you add a string that's too long for a single line, the MultiLineListBox will wrap the long string into multiple lines. Editing items is also easy. Just right click on any item or press the F2 key when an item is selected, this will superimpose an edit box exactly on top of the selected or clicked item. You can make your changes and either press the Enter key or you can click anywhere else within the list box for the modifications to take effect. If you want to cancel the changes and get back to the original text, simply hit the Escape key.
The class will not allow you to make an item null, and will pop up a message box alert and won't let you take focus away from the item till you've either cancelled the modification by pressing Escape or you have entered some text.

If you enter a lot of text into the item edit text box, the overlaid text box itself will allow you to scroll vertically.

Using the class

Simply add the control to your toolbox. Now use it just as you  would be using a regular list box. Try entering long strings. And run the program. Try editing the strings by either pressing the F2 key or by right clicking on an item. See how the alert message box pops up when you try to modify an item string to a null string. I added this feature because in the project where I'll be using this, null strings are strictly forbidden. Perhaps you might want to allow null strings, if so feel free to comment out the relevant code in the source code.

Technical details

Well obviously the DrawMode is set to DrawMode.OwnerDrawVariable. We need to figure out the height required per item. This is how we do it it in the OnMeasureItem override,
//...

string s = Items[e.Index].ToString();
SizeF sf = e.Graphics.MeasureString(s,Font,Width);
int htex = (e.Index==0) ? 15 : 10;
e.ItemHeight = (int)sf.Height + htex;   
e.ItemWidth = Width;

//...
Now we need to actually draw the  text as this is an owner drawn list box. We override OnDrawItem as shown below.
protected override void OnDrawItem(DrawItemEventArgs e)
{
    //...

    /*chk if list box has any items*/
    if(e.Index > -1)
    {
        string s = Items[e.Index].ToString();                           

        /*Normal items*/
        if((e.State & DrawItemState.Focus)==0)
        {
            e.Graphics.FillRectangle(
                new SolidBrush(SystemColors.Window),
                e.Bounds);
            e.Graphics.DrawString(s,Font,
                new SolidBrush(SystemColors.WindowText),
                e.Bounds);              
            e.Graphics.DrawRectangle(
                new Pen(SystemColors.Highlight),e.Bounds);              
        }
        else /*Selected item, needs highlighting*/
        {
            e.Graphics.FillRectangle(
                new SolidBrush(SystemColors.Highlight),
                e.Bounds);
            e.Graphics.DrawString(s,Font,
                new SolidBrush(SystemColors.HighlightText),
                e.Bounds);
        }
    }
}
Well, so far so good. Now for the in-place editing, what we do is to derive a class from TextBox and add it to our list box. And we handle the OnMouseUp method to check if the user has right clicked an item.
protected override void OnMouseUp(
    System.Windows.Forms.MouseEventArgs e)
{
    //...


        /* Is it a right mouse clk? */
        if(e.Button == MouseButtons.Right)
        {

            string s = Items[index].ToString();
            Rectangle rect = GetItemRectangle(index);

            //overlay the text box right over
            //the list box item to be edited
            tbox.Location = new Point(rect.X,rect.Y);
            tbox.Size = new Size(rect.Width,rect.Height);
            tbox.Text = s;              
            tbox.index = index;
            tbox.SelectAll();
            tbox.Show();
            tbox.Focus();
        }

    //...
}
And similarly we handle OnKeyDown for checking whether the user has pressed the F2 key.
protected override void OnKeyDown(KeyEventArgs e)
{
    if(e.KeyData == Keys.F2)
    {
        //...

            string s = Items[index].ToString();
            Rectangle rect = GetItemRectangle(index);

            tbox.Location = new Point(rect.X,rect.Y);
            tbox.Size = new Size(rect.Width,rect.Height);               
            
        //...
    }
    
    //...
}
In the TextBox derived class we override both OnLostFocus and OnKeyPress (check for Enter key) and make checks to ensure that the user will not enter a null string. The source code can be examined for the finer details, but basically that's all the class does and this class is a private inner class of the MultiLineListBox class. I also check for the Escape key in the OnKeyPress handler to allow the user to cancel a modification.

Conclusion

I hope to get your feedback - both good and bad. I'd also like to know whether anyone actually found this useful enough to use in an application. Or whether the class can be improved in any particular manner. As for myself I spent the whole day dealing with various kinds of issues I ran into, mostly due to my custom control coding inexperience rather than due to any great difficulty in what I was attempting.

multi-column combobox in C#




Introduction

I had to write a multi-column combobox at work that supported generic data binding, and I thought it might prove useful for others too. MultiColumnComboBox is a ComboBox derived class written entirely in C# and you can bind it to any data source that has multiple columns (though it doesn't matter if it only has a single column either). It also works in unbound mode though it doesn't make much sense to use it if you are not using data binding.

Class usage

Using the class is fairly straightforward. Once you have your data source you just need to set the DataSource property of the MultiColumnComboBox class. The control does not support the ComboBoxStyle.Simple style and in addition it will insist on DrawMode being set to OwnerDrawVariable. Exceptions are thrown so that you won't inadvertently attempt to break either of those limitations which is pretty handy because the Visual Studio property grid will not then let you change those values.

The class has been tested on Windows XP SP2 as well as on Windows Vista (Ultimate Edition) both from a Visual Studio design perspective as well as from a runtime perspective. Here are some examples of populating the control with various types of data sources. In this first example, we populate it using a DataTable.
// Populate using a DataTable

DataTable dataTable = new DataTable("Employees");

dataTable.Columns.Add("Employee ID", typeof(String));
dataTable.Columns.Add("Name", typeof(String));
dataTable.Columns.Add("Designation", typeof(String));

dataTable.Rows.Add(new String[] { "D1", "Natalia", "Developer" });
dataTable.Rows.Add(new String[] { "D2", "Jonathan", "Developer" });
dataTable.Rows.Add(new String[] { "D3", "Jake", "Developer" });
dataTable.Rows.Add(new String[] { "D4", "Abraham", "Developer" });
dataTable.Rows.Add(new String[] { "T1", "Mary", "Team Lead" });
dataTable.Rows.Add(new String[] { "PM1", "Calvin", "Project Manager" });
dataTable.Rows.Add(new String[] { "T2", "Sarah", "Team Lead" });
dataTable.Rows.Add(new String[] { "D12", "Monica", "Developer" });
dataTable.Rows.Add(new String[] { "D13", "Donna", "Developer" });

multiColumnComboBox1.DataSource = dataTable;
multiColumnComboBox1.DisplayMember = "Employee ID";
multiColumnComboBox1.ValueMember = "Name";
The DisplayMember property will dictate the value that's visible in the edit box part of the combobox. And the ValueMember property will dictate which of the columns will show up in bold. If you look at the screenshots, you can clearly see this in action. In the next example, we use an array of a custom type.
public class Student
{
    public Student(String name, int age)
    {
        this.name = name;
        this.age = age;
    }

    String name;

    public String Name
    {
        get { return name; }
    }

    int age;

    public int Age
    {
        get { return age; }
    }
}

// Populate using a collection

Student[] studentArray = new Student[] 
{ new Student("Andrew White", 10), new Student("Thomas Smith", 10), 
  new Student("Alice Brown", 11), new Student("Lana Jones", 10), 
  new Student("Jason Smith", 9), new Student("Amamda Williams", 11)
};

multiColumnComboBox2.DataSource = studentArray;
multiColumnComboBox2.DisplayMember = multiColumnComboBox2.ValueMember = "Name";
Notice how we've set both DisplayMember and ValueMember to the same column field - this is perfectly okay to do. By the way if you don't set the ValueMember it will use the first column by default. You must set the DisplayMember though, else you'll see some odd strings depending on how a specific type's ToString is implemented. I decided not to provide a default as it would most likely result in non-ideal columns getting displayed. I've used a drop-down list style combobox for my 3rd example and also used a List<> object - though by now it must be pretty obvious to anyone reading this that you can basically use any standard data source.
// Drop-down list (non-editable)

List<Student> studentList = new List<Student>(studentArray);
The main difference in using a drop-down list will be that you'll see the multiple columns even when the combobox is not dropped down. Note that those who want to prevent this behavior can check if DrawItemEventArgs.State has the ComboBoxEdit flag (in the OnDrawItem method) and change the behavior accordingly. For our purposes this behavior was pretty good and I personally thought it to be the more intuitive way to do it. And finally, you can use it without data-binding, though I can't think of any reason why you'd want to do that.
// Trying to use as a regular combobox

multiColumnComboBox4.Items.Add("Cat");
multiColumnComboBox4.Items.Add("Tiger");
multiColumnComboBox4.Items.Add("Lion");
multiColumnComboBox4.Items.Add("Cheetah");
multiColumnComboBox4.SelectedIndex = 0;

Implementation details

One of the first things I did was to hide both the DrawMode and the DropDownStyle properties to prevent users from inadvertently setting unsupported values.
public new DrawMode DrawMode 
{ 
    get
    {
        return base.DrawMode;
    } 
    set
    {
        if (value != DrawMode.OwnerDrawVariable)
        {
            throw new NotSupportedException("Needs to be DrawMode.OwnerDrawVariable");
        }
        base.DrawMode = value;
    }
}

public new ComboBoxStyle DropDownStyle
{ 
    get
    {
        return base.DropDownStyle;
    } 
    set
    {
        if (value == ComboBoxStyle.Simple)
        {
            throw new NotSupportedException("ComboBoxStyle.Simple not supported");
        }
        base.DropDownStyle = value;
    } 
}
I overrode OnDataSourceChanged so that the column names could be initialized.
protected override void OnDataSourceChanged(EventArgs e)
{
    base.OnDataSourceChanged(e);

    InitializeColumns();
}

private void InitializeColumns()
{
    PropertyDescriptorCollection propertyDescriptorCollection = 
        DataManager.GetItemProperties();

    columnWidths = new float[propertyDescriptorCollection.Count];
    columnNames = new String[propertyDescriptorCollection.Count];

    for (int colIndex = 0; colIndex < propertyDescriptorCollection.Count; colIndex++)
    {
        String name = propertyDescriptorCollection[colIndex].Name;
        columnNames[colIndex] = name;
    }
}
I use the DataManager property which returns the CurrencyManager objects that managed the bound objects for the control. Initially I've also set a widths array to 0 (later the required widths will be calculated). I also override the OnValueMemberChanged method so that I could correctly set the value member column internally which I use in the drawing code to make the value column drawn in bold text.
protected override void OnValueMemberChanged(EventArgs e)
{
    base.OnValueMemberChanged(e);

    InitializeValueMemberColumn();
}

private void InitializeValueMemberColumn()
{
    int colIndex = 0;
    foreach (String columnName in columnNames)
    {
        if (String.Compare(columnName, ValueMember, true, 
            CultureInfo.CurrentUICulture) == 0)
        {
            valueMemberColumnIndex = colIndex;
            break;
        }
        colIndex++;
    }
}
OnMeasureItem will be called once for every row in the combobox and that's where I do my width calculations.
protected override void OnMeasureItem(MeasureItemEventArgs e)
{
    base.OnMeasureItem(e);

    if (DesignMode)
        return;

    for (int colIndex = 0; colIndex < columnNames.Length; colIndex++)
    {
        string item = Convert.ToString(
            FilterItemOnProperty(Items[e.Index], columnNames[colIndex]));
        SizeF sizeF = e.Graphics.MeasureString(item, Font);
        columnWidths[colIndex] = Math.Max(columnWidths[colIndex], sizeF.Width);
    }

    float totWidth = CalculateTotalWidth();

    e.ItemWidth = (int)totWidth;
}
The interesting trick here is to use FilterItemOnProperty to get the text associated with a specific column. The width calculation is elementary and I calculate the total width using a CalculateTotalWidth method which merely adds all the individual column widths. I also add width for the vertical scrollbar (in case one shows up). We must also remember to override OnDropDown to set the drop down width appropriately (remember this is different from the width of the combobox itself).
protected override void OnDropDown(EventArgs e)
{
    base.OnDropDown(e);
    this.DropDownWidth = (int)CalculateTotalWidth();
}
Now we come to the meat of the class -the OnDrawItem override.
protected override void OnDrawItem(DrawItemEventArgs e)
{
    base.OnDrawItem(e);

    if (DesignMode)
        return;

    e.DrawBackground();

    Rectangle boundsRect = e.Bounds;
    int lastRight = 0;

    using (Pen linePen = new Pen(SystemColors.GrayText))
    {
        using (SolidBrush brush = new SolidBrush(ForeColor))
        {
            if (columnNames.Length == 0)
            {
                e.Graphics.DrawString(Convert.ToString(Items[e.Index]), 
                    Font, brush, boundsRect);
            }
            else
            {
                for (int colIndex = 0; colIndex < columnNames.Length; colIndex++)
                {
                    string item = Convert.ToString(FilterItemOnProperty(
                        Items[e.Index], columnNames[colIndex]));

                    boundsRect.X = lastRight;
                    boundsRect.Width = (int)columnWidths[colIndex] + columnPadding;
                    lastRight = boundsRect.Right;

                    if (colIndex == valueMemberColumnIndex)
                    {
                        using (Font boldFont = new Font(Font, FontStyle.Bold))
                        {
                            e.Graphics.DrawString(item, boldFont, brush, boundsRect);
                        }
                    }
                    else
                    {
                        e.Graphics.DrawString(item, Font, brush, boundsRect);
                    }

                    if (colIndex < columnNames.Length - 1)
                    {
                        e.Graphics.DrawLine(linePen, boundsRect.Right, boundsRect.Top, 
                            boundsRect.Right, boundsRect.Bottom);
                    }
                }
            }
        }
    }

    e.DrawFocusRectangle();
}
Though it's the longest function in the class (and probably exceeds the Marc Clifton approved limit for maximum number of lines in a method), it's quite straightforward. For each row, it iterates through all the columns, gets the column text and draws the text along with vertical lines that will act as column separators.

REFERENCE LINK

C# 
http://www.c-sharpcorner.com
http://www.codeproject.com
http://www.developerfusion.com/tools/convert/vb-to-csharp/
http://www.csharp-station.com/Tutorial.aspx


CSS LINK:
http://www.csstemplatesfree.org
http://www.templatemo.com
http://www.sheir.org
http://www.w3schools.com/

Ajax/ASP:
https://skydrive.live.com
http://asp-net-example.blogspot.in
http://www.w3schools.com/

PHP:
http://www.9lessons.info

C/C++ Interview Questions:

C/C++ Notes for Interviews:

Microsoft Interview Questions:

Puzzles:

Operating Systems Notes:

Win32 Tutorials:

Data Structure Notes:

Software Testing Notes:

Mathematical Puzzles

WPF DataGrid Control

Introduction

Since .NET 4.0, Microsoft is shipping a DataGrid control that provides all the basic functionality needed, like:

Auto generation of columns
Manual definition of columns
Selection
Grouping
Column sorting, reordering and resizing
Row Details
Alternating BackgroundBrush
Frozen columns
Headers Visibility
How to template autogenerated columns


Basic usage: Auto generate columns

To show a basic data grid , just drop a DataGrid control to your view and bind the ItemsSource to a collection of data objects and you're done. The DataGrid provides a feature called AutoGenerateColumns that automatically generates column according to the public properties of your data objects. It generates the following types of columns:
  • TextBox columns for string values
  • CheckBox columns for boolean values
  • ComboBox columns for enumerable values
  • Hyperlink columns for Uri values

 
<DataGrid ItemsSource="{Binding Customers}" />
 
 


Manually define columns

Alternatively you can define your columns manually by setting the AutoGenerateColumns property to False. In this case you have to define the columns in the Columns collection of the data grid. You have the following types of columns available:
  • DataGridCheckBoxColumn for boolean values
  • DataGridComboBoxColumn for enumerable values
  • DataGridHyperlinkColumn for Uri values
  • DataGridTemplateColumn to show any types of data by defining your own cell template
  • DataGridTextColumn to show text values

 
<DataGrid ItemsSource="{Binding Customers}" AutoGenerateColumns="False" >
    <DataGrid.Columns>
        <DataGridTemplateColumn Header="Image" Width="SizeToCells" IsReadOnly="True">
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <Image Source="{Binding Image}" />
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
            </DataGridTemplateColumn>
    </DataGrid.Columns>
</DataGrid>
 
 


Selection

The data grid includes a variety of selection modes. They are configured by the SelectionMode and SelectionUnit property.
  • The SelectionMode can be set to Single or Extended to define if one or multiple units can be selected simultaneously.
  • The SelectionUnit defines the scope of one selection unit. It can be set to Cell, CellAndRowHeader and FullRow.

 
<DataGrid ItemsSource="{Binding Customers}" 
          SelectionMode="Extended" SelectionUnit="Cell" />
 
 


Column sorting, reordering and resizing

The data grid provides features to sort, reorder and resize columns. They can be enabled or disabled by the following properties:
  • CanUserReorderColumns enables or disables column re-ordering
  • CanUserResizeColumns enables or disables column resizing
  • CanUserResizeRows enables or disables row resizing
  • CanUserSortColumns enables or disables column sorting

 
<DataGrid ItemsSource="{Binding Customers}" 
          CanUserReorderColumns="True" CanUserResizeColumns="True" 
          CanUserResizeRows="False" CanUserSortColumns="True"/>
 
 


Grouping

The data grid also supports grouping. To enable grouping you have to define a CollectionView that contains to least one GroupDescription that defines the criterias how to group.

 
Customers = new ListCollectionView(_customers);
Customers.GroupDescriptions.Add(new PropertyGroupDescription("Gender"));
 
 
Second thing you need to do is defining a template how the groups should look like. You can do this by setting the GroupStyle to something like the following snippet.
 
<DataGrid ItemsSource="{Binding GroupedCustomers}">
    <DataGrid.GroupStyle>
        <GroupStyle>
            <GroupStyle.HeaderTemplate>
                <DataTemplate>
                    <StackPanel>
                        <TextBlock Text="{Binding Path=Name}" />
                    </StackPanel>
                </DataTemplate>
            </GroupStyle.HeaderTemplate>
            <GroupStyle.ContainerStyle>
                <Style TargetType="{x:Type GroupItem}">
                    <Setter Property="Template">
                        <Setter.Value>
                            <ControlTemplate TargetType="{x:Type GroupItem}">
                                <Expander>
                                    <Expander.Header>
                                        <StackPanel Orientation="Horizontal">
                                          <TextBlock Text="{Binding Path=Name}" />
                                          <TextBlock Text="{Binding Path=ItemCount}"/>
                                          <TextBlock Text="Items"/>
                                        </StackPanel>
                                    </Expander.Header>
                                    <ItemsPresenter />
                                </Expander>
                            </ControlTemplate>
                        </Setter.Value>
                    </Setter>
                </Style>
            </GroupStyle.ContainerStyle>
        </GroupStyle>
    </DataGrid.GroupStyle>
</DataGrid>
 
 


Row Details

The data grid provides a feature that shows a detail panel for a selected row. It can be enabled by setting a DataTemplate to the RowDetailsTemplate property. The data template gets the object that is bound to this row passed by the DataContext and can bind to it.

 
<DataGrid ItemsSource="{Binding Customers}">
    <DataGrid.Columns>
    <DataGridTextColumn Header="First Name" Binding="{Binding FirstName}" />
    </DataGrid.Columns>
    <DataGrid.RowDetailsTemplate>
        <DataTemplate>
            <Image Height="100" Source="{Binding Image}" />
        </DataTemplate>
    </DataGrid.RowDetailsTemplate>
</DataGrid>
 
 

Row Details depending on the type of data

You can specify a RowDetailsTemplateSelector that selects a data template according to the type or data that this row contains. To do this, create a type that derives from DataTemplateSelector and override the SelectTemplate method. In the items argument you get the data and you can determine which data template to display. Return an instance of that data template as return value.

 
public class GenderTemplateSelector : DataTemplateSelector
{
    public DataTemplate MaleTemplate { get; set; }
    public DataTemplate FemaleTemplate { get; set; }
 
    public override DataTemplate SelectTemplate(object item, 
                  DependencyObject container)
    {
        var customer = item as Customer;
        if (customer == null)
            return base.SelectTemplate(item, container);
 
        if( customer.Gender == Gender.Male)
        {
            return MaleTemplate;
        }
        return FemaleTemplate;
    }
}
 
 

 
<l:GenderTemplateSelector x:Key="genderTemplateSelector">
    <l:GenderTemplateSelector.MaleTemplate>
        <DataTemplate>
            <Grid Background="LightBlue">
                <Image Source="{Binding Image}" Width="50" />
            </Grid>
        </DataTemplate>
    </l:GenderTemplateSelector.MaleTemplate>
    <l:GenderTemplateSelector.FemaleTemplate>
        <DataTemplate>
            <Grid Background="Salmon">
                <Image Source="{Binding Image}" Width="50" />
            </Grid>
        </DataTemplate>
    </l:GenderTemplateSelector.FemaleTemplate>
</l:GenderTemplateSelector>
 
<DataGrid ItemsSource="{Binding Customers}" 
          RowDetailsTemplateSelector="{StaticResource genderTemplateSelector}" />
 
 

Alternating BackgroundBrush

You can define a an AlternatingRowBackground that is applied every even row. You can additionally specify an AlternationCount if you only want to ink every every n-th data row.

 
<DataGrid ItemsSource="{Binding Customers}" 
          AlternatingRowBackground="Gainsboro"  AlternationCount="2"/>
 
 

Frozen Columns

The data grid also supports the feature to freeze columns. That means they stay visible while you scoll horizontally through all columns. This is a useful feature to keep a referencing column like an ID or a name always visible to keep your orientation while scrolling.
To freeze a numer of columns just set the FrozenColumnCount property to the number of columns you want to freeze.

 
<DataGrid ItemsSource="{Binding Customers}" FrozenColumnCount="2"  />
 
 

Headers visbility

You can control the visibility of row and column headers by setting the HeadersVisibility property to either None,Row,Column or All

 
<DataGrid ItemsSource="{Binding Customers}" HeadersVisibility="None" />
 
 

How to template autogenerated columns

If you want to autogenerate columns using AutoGenerateColumns="True", you cannot use CellTemplates, because the DataGrid autogenerates either a text, combo, hyperlink or checkbox column, but none of these are templateable. A simple workaround is to hook into the autogeneration, cancel it and always create a DataGridTemplateColumn. The following snippet shows the idea (the code is just a draft):
 
public class MyDataGrid : DataGrid
{
 
    public DataTemplateSelector CellTemplateSelector
    {
        get { return (DataTemplateSelector)GetValue(CellTemplateSelectorProperty); }
        set { SetValue(CellTemplateSelectorProperty, value); }
    }
 
    public static readonly DependencyProperty CellTemplateSelectorProperty =
        DependencyProperty.Register("Selector", typeof(DataTemplateSelector), typeof(MyDataGrid), 
        new FrameworkPropertyMetadata(null));
 
 
 
    protected override void OnAutoGeneratingColumn(DataGridAutoGeneratingColumnEventArgs e)
    {
        e.Cancel = true;
        Columns.Add(new DataGridTemplateColumn
            {
                Header = e.Column.Header, 
                CellTemplateSelector = CellTemplateSelector
            });
    }
}
 
 
 
<l:MyDataGrid ItemsSource="{Binding}" 
              AutoGenerateColumns="True" 
              CellTemplateSelector="{StaticResource templateSelector}" />
 
 

Introduction to XAML

XAML stands for Extensible Application Markup Language. Its a simple language based on XML to create and initialize .NET objects with hierarchical relations. Altough it was originally invented for WPF it can by used to create any kind of object trees.
Today XAML is used to create user interfaces in WPF, Silverlight, declare workflows in WF and for electronic paper in the XPS standard.
All classes in WPF have parameterless constructors and make excessive usage of properties. That is done to make it perfectly fit for XML languages like XAML.

Advantages of XAML

All you can do in XAML can also be done in code. XAML ist just another way to create and initialize objects. You can use WPF without using XAML. It's up to you if you want to declare it in XAML or write it in code. Declare your UI in XAML has some advantages:
  • XAML code is short and clear to read
  • Separation of designer code and logic
  • Graphical design tools like Expression Blend require XAML as source.
  • The separation of XAML and UI logic allows it to clearly separate the roles of designer and developer.

XAML vs. Code

As an example we build a simple StackPanel with a textblock and a button in XAML and compare it to the same code in C#.
 
<StackPanel>
    <TextBlock Margin="20">Welcome to Desosha Blog</TextBlock>
    <Button Margin="10" HorizontalAlignment="Right">OK</Button>
</StackPanel>
 
 
The same expressed in C# will look like this:
 
// Create the StackPanel
StackPanel stackPanel = new StackPanel();
this.Content = stackPanel;
 
// Create the TextBlock
TextBlock textBlock = new TextBlock();
textBlock.Margin = new Thickness(10);
textBlock.Text = "Welcome to Desosha Blog";
stackPanel.Children.Add(textBlock);
 
// Create the Button
Button button = new Button();
button.Margin= new Thickness(20);
button.Content = "OK";
stackPanel.Children.Add(button);
 
As you can see is the XAML version much shorter and clearer to read. And that's the power of XAMLs expressiveness.

Properties as Elements

Properties are normally written inline as known from XML <Button Content="OK" />. But what if we want to put a more complex object as content like an image that has properties itself or maybe a whole grid panel? To do that we can use the property element syntax. This allows us to extract the property as an own child element.
 
<Button>
  <Button.Content>
     <Image Source="Images/OK.png" Width="50" Height="50" />
  </Button.Content>
</Button>
 
 

Implicit Type conversion

A very powerful construct of WPF are implicit type converters. They do their work silently in the background. When you declare a BorderBrush, the word "Blue" is only a string. The implicit BrushConverter makes a System.Windows.Media.Brushes.Blue out of it. The same regards to the border thickness that is beeing converted implicit into a Thickness object. WPF includes a lot of type converters for built-in classes, but you can also write type converters for your own classses.
 
<Border BorderBrush="Blue" BorderThickness="0,10">
</Border>
 
 

Markup Extensions

Markup extensions are dynamic placeholders for attribute values in XAML. They resolve the value of a property at runtime. Markup extensions are surrouded by curly braces (Example: Background="{StaticResource NormalBackgroundBrush}"). WPF has some built-in markup extensions, but you can write your own, by deriving from MarkupExtension. These are the built-in markup extensions:
  • Binding
    To bind the values of two properties together.
  • StaticResource
    One time lookup of a resource entry
  • DynamicResource
    Auto updating lookup of a resource entry
  • TemplateBinding
    To bind a property of a control template to a dependency property of the control
  • x:Static
    Resolve the value of a static property.
  • x:Null
    Return null
The first identifier within a pair of curly braces is the name of the extension. All preciding identifiers are named parameters in the form of Property=Value. The following example shows a label whose Content is bound to the Text of the textbox. When you type a text into the text box, the text property changes and the binding markup extension automatically updates the content of the label.
 
<TextBox x:Name="textBox"/>
<Label Content="{Binding Text, ElementName=textBox}"/>
 
 

Namespaces

At the beginning of every XAML file you need to include two namespaces.

The first is http://schemas.microsoft.com/winfx/2006/xaml/presentation. It is mapped to all wpf controls in System.Windows.Controls.

The second is http://schemas.microsoft.com/winfx/2006/xaml it is mapped to System.Windows.Markup that defines the XAML keywords.

The mapping between an XML namespace and a CLR namespace is done by the XmlnsDefinition attribute at assembly level. You can also directly include a CLR namespace in XAML by using the clr-namespace: prefix.

  <Window xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation” xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”> </Window>