Posts Tagged ‘wpf’

.Net WPF – Using Data Triggers

3 Comments

Data triggers are a great feature of WPF. They allow you to change the style properties of a control depending on the data of the bound items of that control.

In this tutorial, I am going to bind a set of data to a ListBox, and use Data Triggers to let me know when something is wrong.

So first, I am going to create a Person class. This class will have three public properties: Name, Age, and IsValid. All three properties will be readonly. The IsValid property will return whether the data of the class is good or not.

Person.cs

public class Person
{
    private string name;

    public string Name
    {
        get { return name; }
        private set { name = value; }
    }
    private int age;

    public int Age
    {
        get { return age; }
        private set { age = value; }
    }

    public bool IsValid
    {
        // will return false if either the name is blank
        //   or if the age is 0.
        get { return (!string.IsNullOrEmpty(name) && age != 0); }
    }

    public Person(string _name, int _age)
    {
        name = _name;
        age = _age;
    }
}

This is a simple example to show the concept. Basically, I am going to set the data to values that we don’t want.


MainWindow.xaml.cs

public partial class MainWindow : Window
{
    ObservableCollection<Person> col;

    public MainWindow()
    {
        InitializeComponent();

        this.Loaded += new RoutedEventHandler(MainWindow_Loaded);
    }

    void MainWindow_Loaded(object sender, RoutedEventArgs e)
    {
        col = new ObservableCollection<Person>();
        col.Add(new Person("John Doe", 24));
        col.Add(new Person("", 24));
        col.Add(new Person("John Doe", 0));

        PersonListBox.ItemsSource = col;
    }
}

As you can see, I set the name to being blank for one object, and the age to being 0 for another object.

Now for the XAML. First, we need to add a new style to the Window.Resources. This style will target the ListBoxItem type.

<Window.Resources>
    <Style TargetType="{x:Type ListBoxItem}" x:Key="ItemStyle">
        <Style.Triggers>
            <DataTrigger Binding="{Binding IsValid}" Value="false">
                <Setter Property="Background" Value="Red" />
            </DataTrigger>
        </Style.Triggers>
    </Style>
</Window.Resources>

So if our IsValid property is false, then we will set the Background property of the ListBoxItem to Red.

Then we have our ListBox,

<Grid>
   <ListBox
       Name="PersonListBox"
       ItemsSource="{Binding}"
       ItemContainerStyle="{StaticResource ItemStyle}"
       Height="142"
       HorizontalAlignment="Left"
       Margin="39,30,0,0"
       VerticalAlignment="Top"
       Width="190">

       <ListBox.ItemTemplate>

          <DataTemplate>

             <StackPanel Orientation="Vertical">

                 <StackPanel Orientation="Horizontal">

                    <TextBlock
                        Text="Name:"
                        Width="50" />

                    <TextBlock
                        Text="{Binding Name}"
                        Width="150"  />

                 </StackPanel>

                 <StackPanel Orientation="Horizontal">

                    <TextBlock
                       Text="Age:"
                       Width="50" />

                    <TextBlock
                       Text="{Binding Age}"
                       Width="50"  />

                 </StackPanel>

             </StackPanel>

         </DataTemplate>

     </ListBox.ItemTemplate>

   </ListBox>
</Grid>

So I am binding the ItemsSource to the collection in the code-behind. Also notice that I am binding the style we created to the ItemContainerStyle. The DataTemplate simply creates a custom ItemTemplate to show the data.

So now if we run our code, we get this…

1

But that’s not all. Let’s say that we want to highlight the rows in different colors depending on if the name is blank or if the age is 0. We can create two separate triggers for that. We would simply change our style to this…

<Window.Resources>
   <Style TargetType="{x:Type ListBoxItem}" x:Key="ItemStyle">
       <Style.Triggers>
          <DataTrigger Binding="{Binding Name}" Value="">
               <Setter Property="Background" Value="Blue" />
          </DataTrigger>
          <DataTrigger Binding="{Binding Age}" Value="0">
               <Setter Property="Background" Value="Yellow" />
          </DataTrigger>
       </Style.Triggers>
   </Style>
</Window.Resources>

With that change, our ListBox now shows this…

2

As you can see, Data Triggers are a very powerful part of WPF. Now if only Microsoft would add this to Silverlight.

Tags: ,

.Net, Silverlight Silverlight – Custom ListBox Item Template

7 Comments

In this tutorial, I will show how to create a custom ListBox Item Template.

For anybody who has tried doing a custom Item Template in WinForms, you would know that it is not fun. You have to override Draw/Paint events, and other jazz to get a ListBox to show how you want it to. However, in Silverlight/WPF, this process is so much easier.

I will be using Blend 4 in my example, as Blend makes the process even more easier.

So first we are going to create a Silverlight project. I will name it CustomListBoxItemTemplate.

10-24-2010 8-46-18 AM

Next, we are going to add a ListBox to our page. I made mine with a Height of 250, and a Width of 300, and gave it the name lstPeople.

<ListBox
   x:Name="lstPeople"
   ItemsSource="{Binding}"
   DisplayMemberPath="FullName"
   Margin="145,92,195,138"/>

Before we get to styling the ListBox, we need to create some test data to load into our ListBox. I created a simply Person class.

public class Person
{
    // Insert code required on object creation below this point.
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public int Age { get; set; }
    public string FullName { get { return FirstName + " " + LastName; } }

    public Person(string _fName, string _lName, int _age)
    {
        FirstName = _fName;
        LastName = _lName;
        Age = _age;
    }
}

And add it to the ListBox…

public partial class MainPage : UserControl
{
	public MainPage()
	{
	     // Required to initialize variables
	     InitializeComponent();

             ObservableCollection<Person> peopleList = new ObservableCollection<Person>();
             peopleList.Add(new Person("John", "Doe", 32));
             peopleList.Add(new Person("Jane", "Doe", 20));
             peopleList.Add(new Person("Betty", "Sue", 65));

             lstPeople.ItemsSource = peopleList;
	}
}

So now, our ListBox looks like this…

10-24-2010 9-12-12 AM

Let’s say that we want to display the age below the Full Name. We can use Blend to edit the Item Template of the ListBox.

In the Objects And Timeline window, right-click on the ListBox –> Edit Additional Templates –> Edit Generated Items(ItemTemplate) –> Create Empty. You could also use the “Edit A Copy” if it’s available.

10-24-2010 9-16-07 AM

We will name it MyListBoxItemTemplate.

10-24-2010 9-16-54 AM

If you switch over to the XAML view, you will see that the ItemTemplate of the ListBox has now been binded to a Static Resource. Right above the LayoutRoot in the UserControl.Resources, you should a DataTemplate.

You will now see a small Grid on the screen. We will expand the grid to a Height of 55 and a Width of 225. Inside the grid, we are going to add 4 TextBlocks. Two will be for display purposes and the other two will show our information. Notice I am also Binding the FullName and Age properties to the Text property of the TextBlock.

<Grid Width="225" Height="55">

	<TextBlock
		Text="Full Name:"
		HorizontalAlignment="Left"
		Height="15"
		Margin="12,8,0,0"
		TextWrapping="Wrap"
		VerticalAlignment="Top"
		Width="70"/>

	<TextBlock
		Text="Age:"
		HorizontalAlignment="Left"
		Margin="46,27,0,13"
		TextWrapping="Wrap"
		Width="33"/>

	<TextBlock
		x:Name="FullNameTextBlock"
		Text="{Binding FullName}"
		Height="15"
		Margin="86,8,8,0"
		TextWrapping="Wrap"
		VerticalAlignment="Top" />

	<TextBlock
		x:Name="AgeTextBlock"
		Text="{Binding Age}"
		Margin="86,27,92,13"
		TextWrapping="Wrap" />

</Grid>

And that’s all we need to do. To get out of the ItemTemplate editing, click on the ListBox at the top…

10-24-2010 9-32-30 AM

Now run the application, and your ListBox will now look like this…

10-24-2010 9-32-45 AM

As you can see, using Blend in a Silverlight or WPF application, you can customize a ListBox in only a few minutes.

<ListBox
x:Name=”lstPeople”
ItemsSource=”{Binding}”
DisplayMemberPath=”FullName”
Margin=”145,92,195,138″/>
Tags: , , ,

.Net WPF – Dynamically Loading LINQ-To-SQL Tables and Columns Into ComboBox

2 Comments

Here is some code to dynamically load the table names into a ComboBox.  Then on the selection of a specific table, load the columns for that table into a second ComboBox.

First is the XAML:

<Window x:Class="WpfApplication4.MainWindow"
       
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
       
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
       
Title="MainWindow" Height="350" Width="525">
   
<Grid>
       
<ComboBox
           
Name="cboTables"
           
Height="23"
           
HorizontalAlignment="Left"
           
Margin="186,60,0,0"
           
VerticalAlignment="Top"
           
Width="120"
           
ItemsSource="{Binding}"
           
Selectionchanged="cboTables_Selectionchanged"
           
DisplayMemberPath="RowType.Name"
           
SelectedValuePath="RowType.DataMembers" />
       
       
<ComboBox
           
Height="23"
           
HorizontalAlignment="Left"
           
Margin="186,107,0,0"
           
Name="cboColumns"
           
VerticalAlignment="Top"
           
Width="120"
           
ItemsSource="{Binding}"
           
DisplayMemberPath="MappedName"/>
       
<Label
           
Name="label1"
           
Content="Tables:"
           
Height="28"
           
HorizontalAlignment="Left"
           
Margin="134,60,0,0"  
           
VerticalAlignment="Top" />

       
<Label
           
Name="label2"
           
Content="Columns:"
           
Height="28"
           
HorizontalAlignment="Left"
           
Margin="121,107,0,0"
           
VerticalAlignment="Top" />
   
</Grid>
</Window>

Notice that we have set the ItemsSource attribute to {Binding}. This lets the control know that we are binding data to the control(big surprise). Notice that I have also set theDisplayMemberPath and SelectedValuePath in the Tables ComboBox and theDisplayMemberPath in the Columns ComboBox.

Next is the code:

using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Controls;

namespace WpfApplication4
{
   
/// <summary>
   
/// Interaction logic for Mainwindow.xaml
   
/// </summary>
   
public partial class MainWindow : Window
   
{
       
public MainWindow()
       
{
           
InitializeComponent();

           
this.Loaded += new RoutedEventHandler(MainWindow_Loaded);
       
}

       
void MainWindow_Loaded(object sender, RoutedEventArgs e)
       
{
           
// creates a new instance of our DataContext
           
using (InformationDataContext db = new InformationDataContext())
           
{
               
// gets the list of tables
               
var tableList = db.Mapping.GetTables();
                cboTables
.ItemsSource = tableList;
           
}
       
}

       
private void cboTables_Selectionchanged(object sender, SelectionchangedEventArgs e)
       
{
            cboColumns
.ItemsSource = cboTables.SelectedValue as ReadOnlyCollection<System.Data.Linq.Mapping.MetaDataMember>;
       
}
   
}
}

We use the GetTables method of the DataContext class to get the list of tables. The objects themselves are of type System.Data.Linq.Mapping.AttributedMetaTable. Two properties of this class are RowType.Name and RowType.DataMembers. The RowType.Name is the name of the table without the “dbo” in front. The RowType.DataMembers is a list of the columns of that table.

The RowType.DataMembers objects are of type System.Data.Linq.Mapping.MetaDataMember. One property of this class is the MappedName property that we are using as the DisplayMemberPath. This gives us the name of the column without any extra data.

Tags: , ,