Completing a WPF To-Do List Application

In this conclusion to a four-part series that illustrates WPF through the example of building a to-do list application, we will complete the program we started. You will learn how to make the software handle deleting tasks, and how to give it the look and feel you want.

Contributed by
Rating: 5 stars5 stars5 stars5 stars5 stars / 4
September 15, 2008
Rate this Article:
MEH MEH++


SEARCH ASP FREE
TOOLS YOU CAN USE

advertisement

Deleting tasks

Now that a mechanism for the addition of new tasks has been added, the user needs a way to delete an existing task. In the code, deleting tasks is much easier than adding tasks. The element representing the selected task simply needs to be removed from the XML when the user clicks the delete button.

In Visual Studio, double click the delete button in the designer to automatically create a click event handler, or manually add it:


<Button Name="DeleteButton" Grid.Row="1" Grid.Column="1" Content="Delete Task" Click="DeleteButton_Click">


The code for deletion is really simple. First, the code needs to check that an item is indeed selected. If nothing is selected in TaskListBox, then its SelectedIndex property will be -1. So, the code simply needs to check that SelectedIndex isn't -1. If it isn't, then the value of the SelectedItem property of TaskListBox needs to be cast into an XmlElement object, and this element needs to be removed from its parent element (Tasks):


private void DeleteButton_Click(object sender, RoutedEventArgs e)

{

 if (TaskListBox.SelectedIndex != -1)

{

 XmlElement task = (XmlElement)TaskListBox.SelectedItem;

task.ParentNode.RemoveChild(task);

}

}


When a task is selected and the delete button is pressed, the task will now be deleted from the list.

Saving the task list

You've probably noticed that even though tasks can be added to and deleted from the list, the changes are erased when the program is closed. This is because with an XML data source, the binding really only goes one way. Any changes are actually only saved to an in-memory XML document, not the original source file.

However, it's not very difficult to work around this. We simply need to add code that writes the in-memory document to the physical XML file. Perhaps the easiest way to do this is to write the changes when the application is closed, although a more complex system would be better in a real application.

In the XAML for Window1, add an attribute pointing to a handler for the Closing event:


<Window x:Class="WpfToDo.Window1"

 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

 xmlns:local="clr-namespace:WpfToDo"

  Closing="Window_Closing"

 Title="To-Do List" SnapsToDevicePixels="true" Height="480" Width="384">


The code for this handler is pretty straightforward. The XmlDataSource needs to be fetched, and the XML document needs to be saved on disk:


private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)

{

 XmlDataProvider tasks = (XmlDataProvider)FindResource("tasks");

tasks.Document.Save("Tasks.xml");

}


Now changes to the application will be saved when the main window is closed, and, functionally, the application is complete.

Stylizing the application

The to-do list works fine, but it does look a bit dull. We need to fix this by stylizing the application a bit. After all, WPF was built with the user's visual experience in mind, and why not take advantage of this?

One way—the most basic way—to change the look of the to-do list is to manipulate properties of the controls at the attribute level in XAML. The Properties Window in Visual Studio provides a convenient way to explore some of these properties and assign values.

Using attributes in XAML, we can easily modify the look of the “Add Task” button to give it an orange look:


<Button Name="AddButton" Grid.Row="1" Grid.Column="0" Margin="0,3,2,0" Content="Add Task" Click="AddButton_Click" Background="PaleGoldenrod" BorderBrush="DarkOrange" FontSize="14" Foreground="DarkOrange" />


If you run the application, you'll see that this works just fine: the button now sports a new look. However, if the look of one button is changed, then the look of other buttons must be changed, along with the looks of the other controls. Otherwise, the look is inconsistent and probably unappealing. However, applying a style to each control individually through attributes quickly gets tiring, and, moreover, the resulting XAML will look like a complete mess and be very difficult to read, much less manage or update. Rather than dealing with every control individually, we need to deal with the controls in groups.

Fortunately, WPF provides a way to do just that. Using styles, we can apply a consistent look for a target set of controls. This way, we can style the buttons the exact same way, the labels, and so on, without having to apply the style to each control individually. All we need to do is set the attributes one time. This saves a lot of work, and the resulting XAML is neat. Moreover, the look of the application can be changed very quickly, since it doesn't involve changing each control individually.

Styles belong in the same group as templates: they're resources, and so they need to go in a Resources section of the XAML. However, the to-do list application uses two windows, and, as a result, we can't put styles in Windows.Resources. Instead, the styles must be put in Application.Resources inside the App.xaml file. This way, the styles will be global rather than specific to a certain window. If you look inside of App.xaml, you'll notice that the Application.Resources tag is already there.

Defining styles is very simple. We only need to specify the target type (Button, CheckBox, etc.) and then list the properties we want to set and the values with which we'll be setting them. Let's start by applying the style from the “Add Task” button to all buttons. Go ahead and remove the style attributes from the button, if you've added them. Next, put the following XAML inside of the Application.Resources element:


<Style TargetType="{x:Type Button}">

 <Setter Property="Background" Value="PaleGoldenrod" />

 <Setter Property="BorderBrush" Value="DarkOrange" />

 <Setter Property="Foreground" Value="Orange" />

 <Setter Property="FontSize" Value="14" />

</Style>


When the application is run, all buttons will share the same look, even the buttons in the add task dialog. This creates a little problem, however. The dialog buttons are much smaller than the main window buttons, but the font size is the same in both. This means the text on the dialog buttons is cut off at the bottom. In this situation, a completely consistent look works against us.

Stylizing the application, continued

This problem is easily fixed, thankfully. Just as, in C#, one class can inherit from another, so too, in XAML, can one style inherit from another. The default button style was defined at the application level. However, any other definitions at a lower level (at the window level or the layout level—it's also possible to give, for example, a Grid its own resources) will take precedence. When we do define a new style, we can re-use elements from another style so that the properties don't all have to be redefined. First, though, the button style that we just created will need to have an identifier:


<Style x:Key="orangeButtonStyle" TargetType="{x:Type Button}">


The dialog window will need its own Resources section in AddTaskDialog.xaml:


<Window.Resources>


</Window.Resources>


Inside this section, we can create a new style which is based on the other one and will only apply to buttons within the dialog:


<Style TargetType="{x:Type Button}" BasedOn="{StaticResource orangeButtonStyle}">

 <Setter Property="FontSize" Value="11" />

</Style>


The font size now fits the small size of the button.

Notice that this creates another problem, however. When the first style is given an identifier, it ceases to be the default style automatically applied to everything. It is possible, though, to explicitly apply a style to a control:


<Button Name="AddButton" Grid.Row="1" Grid.Column="0" Margin="0,3,2,0" Content="Add Task" Click="AddButton_Click" Style="{StaticResource orangeButtonStyle}" />

<Button Name="DeleteButton" Grid.Row="1" Grid.Column="1" Margin="2,3,0,0" Content="Delete Task" Click="DeleteButton_Click" Style="{StaticResource orangeButtonStyle}" />


Still, a neater, more practical solution would just be to inherit from orangeButtonStyle in the main window itself:


<Style TargetType="{x:Type Button}" BasedOn="{StaticResource orangeButtonStyle}" />


Finishing Up

Now that you've learned the basics of styles, it's time to finish up the application. The principles are the same as before. We can create additional styles in the exact same way:


<Style TargetType="{x:Type TextBox}">

 <Setter Property="Background" Value="PaleGoldenrod" />

 <Setter Property="BorderBrush" Value="DarkOrange" />

</Style>

<Style TargetType="{x:Type ComboBox}">

 <Setter Property="Background" Value="PaleGoldenrod" />

 <Setter Property="BorderBrush" Value="DarkOrange" />

</Style>

<Style TargetType="{x:Type ListBox}">

 <Setter Property="BorderBrush" Value="DarkOrange" />

</Style>


Of course, feel free to stylize the application as you see fit. One of the things you might want to do is create a base style for all controls, and then derive other styles from that, creating styles for specific controls while saving a lot of space. Of course, there's more to styles, but everything can't possibly be covered here in such a small amount of space.

Now the to-do application is complete, and you've seen a little bit of WPF in action. We've worked with XAML, controls, events, databinding, styles, templates, and a little bit of code. However, there is a lot more to WPF, and this only serves as a short introduction. But now you know the basics, and continuing on won't be very difficult at all. See if you can expand upon the to-do list and add new features to it, such as a menu or a calendar feature.

blog comments powered by Disqus
WINDOWS SCRIPTING ARTICLES

- More Windows Scripting Workarounds from Nilpo
- Overloading Methods and More in VBScript
- Improving MFC for Windows Vista
- Regular Expressions in VBScript
- Working with Dates in WMI
- Completing Calendars with VBScript Date Func...
- Building Calendars with VBScript Date Functi...
- Working With Dates and Times in VBScript
- Designing WCF DataContract Classes Using the...
- Understanding Dates and Times in VBScript
- Working With Arrays in VBScript
- Compressed Folders in WSH
- Using .NET Interops in VBScript
- Nilpo`s Scripting Secrets, Vol I
- Database operations using Silverlight 2.0 WC...

ASP Web Hosting ASP.Net Web Hosting Windows Web Hosting
ASP Free Forums 
 RSS  Tutorials RSS
 RSS  Forums RSS
 RSS  All Feeds
Site Map 
Request Media Kit
Write For Us Get Paid 
Weekly Newsletter
 
Developer Updates  
Free Website Content 
Privacy Policy 
Support 


© 2003-2012 by Developer Shed. All rights reserved. DS Cluster 8 - Follow our Sitemap
Most Popular Topics
All ASP.Net Tutorials