Today’s article was guest authored by Rick Kierner, a software developer friend of mine from Columbus, OH. You can learn more about Rick at http://rickdoes.net.
Today is Day #18 of the 31 Days of Silverlight, and today we’re going to take a look at the new Silverlight 3.0 Effects.
Effects were a concept introduced to Silverlight in version 3.0. They are intended to create a visual stimulus to alter or distort an element in your Silverlight application. Visual stimulus are very useful when attempting to attract or distract a user’s focus to a specific part of the application.
Out of the box, there are 2 kinds of effects: BlurEffect and DropShaddowEffect. These effects are useful in a wide variety of applications. Since I spend my day working with Silverlight in line of business applications, we’ll investigate how to leverage these two effects appropriately in a line of business application.
Most line of business applications end up having some type of data grid to display data. we’ve discussed Silverlight Charting on Day #15. Now, we have the opportunity to make our charts pop off the page in not one but two different ways.
Setup
Here’s our scenario. There is a team lead who needs to track the way that hours are spent on specific tasks on a software development project. Not to muddy up the issue, let’s assume that there are only three ways to work on a specific task: Design, Implementation, and Quality Assurance. Remember this is an example for Silverlight not a discussion on team mechanics.
So it sounds like we’ll need a class to hold this information so we’ll create this class as follows:
1: public class Task
2: {
3: public string Name { get; set; }
4: public int DesignHours { get; set; }
5: public int ImplementationHours { get; set; }
6: public int QualityAssuranceHours { get; set; }
7: public List<KeyValuePair<string, int>> Values
8: {
9: get
10: {
11: return new List<KeyValuePair<string, int>>{
12: new KeyValuePair<string, int>("Design Hours", DesignHours),
13: new KeyValuePair<string, int>("Implementation Hours", ImplementationHours),
14: new KeyValuePair<string, int>("QA Hours", QualityAssuranceHours)
15: };
16:
17:
18: }
19: }
20:
21: }
Next, we need to create a DataGrid that has 4 columns:
- Task Name
- Design Hours
- Implementation Hours
- Quality Assurance Hours
Here is the XAML to put that together:
1: <UserControl x:Class="ApplyingEffects.Silverlight.MainPage"
2: xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
3: xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
4: xmlns:Controls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"
5: xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
6: mc:Ignorable="d" d:DesignWidth="500" d:DesignHeight="400">
7: <Grid x:Name="LayoutRoot" Width="400" Height="200">
8: <Grid.RowDefinitions>
9: <RowDefinition Height="*"/>
10: </Grid.RowDefinitions>
11: <Controls:DataGrid x:Name="Grid" AutoGenerateColumns="False" Grid.Row="0">
12: <Controls:DataGrid.Columns>
13: <Controls:DataGridTextColumn x:Name="NameColumn" Header="Name" Binding="{Binding Path=Name}"/>
14: <Controls:DataGridTextColumn x:Name="DesignColumn" Header="Design Hours" Binding="{Binding Path=DesignHours}"/>
15: <Controls:DataGridTextColumn x:Name="ImplementationColumn" Header="Implementation Hours" Binding="{Binding Path=ImplementationHours}"/>
16: <Controls:DataGridTextColumn x:Name="QualityAssuranceColumn" Header="QA Hours" Binding="{Binding Path=QualityAssuranceHours}"/>
17: </Controls:DataGrid.Columns>
18: </Controls:DataGrid>
19: </Grid>
20: </UserControl>
To make things easy, let’s create the data to populate this DataGrid in the constructor:
1: public MainPage()
2: {
3: InitializeComponent();
4: Grid.ItemsSource = new List<Task>{
5: new Task{Name="Task A", DesignHours = 4, ImplementationHours = 12, QualityAssuranceHours = 1},
6: new Task{Name="Task B", DesignHours = 6, ImplementationHours = 10, QualityAssuranceHours = 8},
7: new Task{Name="Task C", DesignHours = 8, ImplementationHours = 8, QualityAssuranceHours = 16},
8: new Task{Name="Task D", DesignHours = 10, ImplementationHours = 6, QualityAssuranceHours = 32},
9: new Task{Name="Task E", DesignHours = 12, ImplementationHours = 7, QualityAssuranceHours = 64},
10: new Task{Name="Task F", DesignHours = 14, ImplementationHours = 9, QualityAssuranceHours = 12}
11: };
12: }
If you run this, you can see that we have a populated DataGrid. Wonderful!
Now we just need to show a pie chart of the break down of hours. We do this because visual aids make our applications more useful and efficient for people to leverage. Let’s get started.
First, we need to break open our layout a bit and put a chart next to the DataGrid. I know there isn’t much room on our app but we’ll address that in a minute. For now, let’s create a small chart that will report the percentage of time that was spent on each category for a given task. To do that, we will add a chart to a canvas which we’ll add to the XAML (line 26-30). We also add a new row (line 11), two new column definitions (line 14-15).
1: <UserControl x:Class="ApplyingEffects.Silverlight.MainPage"
2: xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
3: xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
4: xmlns:ChartingToolkit="clr-namespace:System.Windows.Controls.DataVisualization.Charting;assembly=System.Windows.Controls.DataVisualization.Toolkit"
5: xmlns:Controls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"
6: xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
7: mc:Ignorable="d" d:DesignWidth="600" d:DesignHeight="400">
8: <Grid x:Name="LayoutRoot" Width="600" Height="400">
9: <Grid.RowDefinitions>
10: <RowDefinition Height="*"/>
11: <RowDefinition Height="Auto"/>
12: </Grid.RowDefinitions>
13: <Grid.ColumnDefinitions>
14: <ColumnDefinition Width="400"/>
15: <ColumnDefinition Width="200"/>
16: </Grid.ColumnDefinitions>
17: <Controls:DataGrid x:Name="Grid" AutoGenerateColumns="False" Grid.Row="0" Grid.Column="0">
18: <Controls:DataGrid.Columns>
19: <Controls:DataGridTextColumn x:Name="NameColumn" Header="Name" Binding="{Binding Path=Name}"/>
20: <Controls:DataGridTextColumn x:Name="DesignColumn" Header="Design Hours" Binding="{Binding Path=DesignHours}"/>
21: <Controls:DataGridTextColumn x:Name="ImplementationColumn" Header="Implementation Hours" Binding="{Binding Path=ImplementationHours}"/>
22: <Controls:DataGridTextColumn x:Name="QualityAssuranceColumn" Header="QA Hours" Binding="{Binding Path=QualityAssuranceHours}"/>
23: </Controls:DataGrid.Columns>
24: </Controls:DataGrid>
25:
26: <Canvas x:Name="ChartCanvas" Grid.Row="0" Grid.Column="1">
27: <ChartingToolkit:Chart Background="White" Grid.Row="0" x:Name="Chart" Title="{Binding SelectedItem.Name, ElementName=Grid}" BorderBrush="Gray" Margin="0" Canvas.Top="0" Canvas.Left="0" Width="400" Height="200">
28: <ChartingToolkit:PieSeries ItemsSource="{Binding SelectedItem.Values, ElementName=Grid}" IndependentValueBinding="{Binding Key}" DependentValueBinding="{Binding Value}" />
29: </ChartingToolkit:Chart>
30: </Canvas>
31: </Grid>
32: </UserControl>
Make sure to notice the binding on the control. This is a little different than the way we did it on Day #15. We’re binding the ItemsSource property to the SelectedItem.Values of the Grid Control. Silverlight will bind to the Values property of the selected Task object. We want the IndependentValueBinding and DependentValueBinding to be the Key and Value property of the List<T> of KeyValuePair<string, int> respectfully. At this point, it will look something like below.
The Effects
Personally, I think that the chart is too small. I also want it to pop out of the page a little. For this, we’ll add a button to line 25 above like this:
1: <Button x:Name="btnToggle" HorizontalAlignment="Left" Width="100" Content="Make Bigger" Grid.Row="1" Grid.RowSpan="2" Click="btnToggle_Click"/>
We have an event handler for the Click Event that will do most of the work for us:
1: private void btnToggle_Click(object sender, RoutedEventArgs e)
2: {
3: if (Canvas.GetZIndex(ChartCanvas) == 100)
4: {
5: //Reduce Size
6: Canvas.SetZIndex(ChartCanvas, 1);
7:
8: Canvas.SetLeft(Chart, 0);
9: Chart.Width = 400;
10: Chart.Height = 200;
11: Chart.Effect = null;
12: btnToggle.Content = "Make Bigger";
13: Grid.Effect = null;
14: }
15: else
16: {
17: Canvas.SetZIndex(ChartCanvas, 100);
18: Canvas.SetZIndex(Chart, 100);
19: Canvas.SetLeft(Chart, -200);
20: Chart.Width = 600;
21: Chart.Height = 400;
22: Chart.Effect = new DropShadowEffect { BlurRadius = 8 };
23: btnToggle.Content = "Make Smaller";
24: Grid.Effect = new BlurEffect { Radius = 8 };
25: }
26: }
What we’re doing is first determining if the Chart is already “popped†out. If it is, then we want to un-pop it back into place. On lines 6-10 and 17-21, we’re moving the chart around to give it the size and placement that we want. The sweet effects are made on lines 22 & 24.
These effects actually adjust the visible pixels. Silverlight gives you two effects out of the box but you can create your own if you so choose. As mentioned earlier, these two effects that Silverlight gives you are DropShaddowEffect and BlurEffect. Naturally, we want our chart to pop, so we’re going to give it a drop shaddow. This will give the user the illusion that the chart has moved toward them, thus grabbing their attention. Secondly, we want to detract the user from paying attention the grid. It’s not the focus here anyway. So we want to apply the BlurEffect to the grid. By adjusting the BlurRadius and Radius properties respectfully, we can change the depth and blurriness where we feel like it.
Here’s the finished product. Note if you click the “View Detail†button in a row, you can see the breakdown of hours allocated to a task in a pie chart. Notice also that box the chart is in floats over the data grid in what appears to be two completely different layers. To further pull attention to the chart, the DataGrid behind the chart is blurred out until the user closes the chart.
Summary
In this article we examined how we can apply Effects to Silverlight elements and why/when we would like to use Effects.
Leave a Reply