|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Announcements
Chapters
Services
Feature Zones
|
The DemoThe demo shows a table with a list of employees, with their salary and the distance they need to travel. The red and green bars show the travel distance in a more graphic way. These bars are scaled to the largest value shown in that column. Below the table is a footer with some extra information about the data. These textboxes are bound in a similar way as the bars in the table, they use the exact same converters. The three buttons show different selections of the same data. IntroductionIn a lot of cases, when we present a table to a user, we want to show some extra information. For example, the average salary of the selected employees, or the total number of a specific product in a selection of orders. In a project I'm working on at the moment, I needed to calculate the maximum value of one of the columns in a WPF With Reflection, you can parameterize the property of the list you want to aggregate, thus making the converter generic again! To do this, we need to create a converter that takes a generic Value converterTo create a value converter, we need to create a class which inherits and implements public class MaxConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
double Max = 0.0; // initialize a variable to keep track of the highest value
Type ValueType = value.GetType(); // get the type of the provided value
if(ValueType.Name == typeof(List<>).Name) // Check if we're dealing with a list
{
foreach (var item in (IList)value)//if so, loop thru all items in the list
{
// Get the type of the item
Type ItemType = item.GetType();
//Get the propetry information
PropertyInfo ItemPropertyInfo = ItemType.GetProperty((string)parameter);
// get the actual value of the item
double ItemValue = (double)ItemPropertyInfo.GetValue(item, null);
if (ItemValue > Max) // compare ..
Max = ItemValue; // .. and assign value to max if needed
}
return Max;
}
return 0.0; // It's not a list so return 0.0
}
public object ConvertBack(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{ throw new NotImplementedException(); }
}
A variable is initialized to hold the maximum value, Now that we have got the value, we can do all kinds of complex calculations with it. In our case, we compare it to the largest value we kept in the XAMLTo make the convert visible to our XAML file, we first need to add the namespace to the XAML file (if it isn't there already). In the demo, the converter is in the <window
.
.
xmlns:local="clr-namespace:AggregateConverterExample"
.
.
>
After that, the namespace is available in the XAML file and can be accessed by using the <window.resources>
.
.
<local:MaxConverter x:Key="MaxConverter" />
.
.
</window.resources>
The demo shows a textbox with the largest salary. To make this work, we bind the .
.
<TextBlock VerticalAlignment="Center"
Grid.Column="4"
Text="{Binding Path=ItemsSource,
ElementName=TheList,
Converter={StaticResource MaxConverter},
ConverterParameter=Salary}"/>
.
.
What about a DataTemplate?In the demo project, I used a <DataTemplate x:Key="ExampleDataTemplate">
.
.
<ProgressBar Foreground="Red"
Grid.Column="3"
Maximum="{Binding RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type ListView}},
Path=ItemsSource,
Converter={StaticResource MaxConverter},
ConverterParameter=TravelDistance}"
Value="{Binding Path=TravelDistance}" />
.
.
</DataTemplate>
The binding to the Where to Go from HereOne thing these converters don't implement at this moment is exception handling. When using these in a "real" project, you may want to catch ReferencesHistory
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||