Skip to main content
Home Forums Silverlight Programming Silverlight Controls and Silverlight Toolkit Using ValueConverters in Custom Control Template Bindings
10 replies. Latest Post by sl.ayer on August 12, 2009.
(0)
michael_...
Member
29 points
38 Posts
12-03-2008 10:02 AM |
Is it possible to use a ValueConverter class in a custom control?
The reason that I ask is that I have been unsuccessful in my attempts to do so. I currently have a custom control defined in a custom control assembly where the template visuals are defined in generic.xaml and the control logic is defined in a backing control class. When I attempt to use a ValueConverter in binding one of the properties of one of the controls in the template, I get a runtime error indicating that the XAML parser can't parse the resulting markup. Note that I get no compile-time error and the binding syntax appears to be correct.
bryant
Star
9937 points
1,629 Posts
12-03-2008 11:49 AM |
You might want to use a TypeConverter in this case, not a value converter. I posted the difference here. Value converters are usually used with data binding, not template binding.
12-03-2008 12:33 PM |
Hi Bryant,
In my scenario, I am databinding. I'm attempting to define a binding between a data class property and a property on my control. But a ValueConverter is required to perform a type conversion between the property values. And using "normal" binding syntax with a converter in generic.xaml is throwing a runtime error.
12-03-2008 3:14 PM |
I don't think you do data binding in generic.xaml. Only templates go in there and I don't believe the data binding will work.
Can you post some sample code of what you're trying to do?
12-03-2008 4:35 PM |
Data binding actually works just fine and it's what you need to do when using Data Templates within your control template (as I am). The issue seems to be that it doesn't like the use of a converter in the data binding definition. Below is an excerpt of my code. The formatter is "pggFormatter" and the property is "Gender" on the "PersonGlyph" control in the ListBox Item DataTemplate:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:vsm="clr-namespace:System.Windows;assembly=System.Windows" xmlns:controls="clr-namespace:PPL.Silverlight.Controls.PeopleExplorer;assembly=PPL.Silverlight.Controls.PeopleExplorer" mc:Ignorable="d" d:DesignWidth="311" d:DesignHeight="350.783"> <controls:PersonGlyphGenderFormatter x:Key="pggFormatter" /> <!-- Built-In Style for PersonList --> <Style TargetType="controls:PersonList"> <Setter Property="Template"> <Setter.Value> <!-- ControlTemplate --> <ControlTemplate TargetType="controls:PersonList"> <!-- Template's Root Visual --> <Grid Margin="8,40,8,20" x:Name="peopleListContainer"> <ListBox x:Name="lbPeopleList" Style="{StaticResource PersonListListBoxStyle}" Background="{x:Null}" BorderThickness="0,0,0,0" Height="Auto" VerticalAlignment="Stretch" Margin="5,50,5,5" > <ListBox.ItemTemplate> <DataTemplate> <StackPanel HorizontalAlignment="Center" VerticalAlignment="Top" Orientation="Horizontal" Margin="2,2,2,2"> <controls:PersonGlyph EmploymentStatus="{Binding Path=EmployeeStatus}" Gender="{Binding Path=Gender Mode=OneWay Converter={StaticResource pggFormatter}}" SalaryType="{Binding Path=EmployeeClass}" Margin="2,0,0,0" x:Name="personGlyph" /> <TextBlock Text="{Binding Path=Name}" TextWrapping="NoWrap" x:Name="tbName" Margin="5,0,0,0" VerticalAlignment="Center" IsHitTestVisible="False" FontSize="11" MaxWidth="250" Width="250" /> <TextBlock Text="{Binding Path=WorkPhone}" MaxWidth="86" x:Name="tbPhone" Width="86" IsHitTestVisible="False" FontSize="11" TextWrapping="NoWrap" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="5,0,0,0"/> <TextBlock Text="{Binding Path=MailCode}" MaxWidth="70" x:Name="tbMailCode" Width="70" IsHitTestVisible="False" FontSize="11" TextWrapping="NoWrap" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="5,0,0,0"/> <TextBlock Text="{Binding Path=RespCtrDescription}" MaxWidth="250" x:Name="tbDepartment" Width="250" IsHitTestVisible="False" FontSize="11" TextWrapping="Wrap" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="5,0,0,0"/> </StackPanel> </DataTemplate> </ListBox.ItemTemplate> </ListBox> <TextBlock HorizontalAlignment="Left" Margin="15,15,0,0" VerticalAlignment="Top" Text="The following individuals match your search criteria. Select one for more information." TextWrapping="Wrap" Foreground="#FFFFFFFF" FontSize="14" Width="655.152"/> </Grid> </ControlTemplate> </Setter.Value> </Setter> </Style> </ResourceDictionary>
12-03-2008 6:08 PM |
Ok, now I see what you mean.
I think the problem is that your value converter doesn't exist as a resource on the page. Try moving it into the Grid.Resources and see if that works:
<Style TargetType="controls:PersonList"> <Setter Property="Template"> <Setter.Value> <!-- ControlTemplate --> <ControlTemplate TargetType="controls:PersonList"> <!-- Template's Root Visual --> <Grid Margin="8,40,8,20" x:Name="peopleListContainer"> <Grid.Resources> <controls:PersonGlyphGenderFormatter x:Key="pggFormatter" /> </Grid.Resources> <ListBox x:Name="lbPeopleList" Style="{StaticResource PersonListListBoxStyle}" Background="{x:Null}" BorderThickness="0,0,0,0" Height="Auto" VerticalAlignment="Stretch" Margin="5,50,5,5" > <ListBox.ItemTemplate> <DataTemplate> <StackPanel HorizontalAlignment="Center" VerticalAlignment="Top" Orientation="Horizontal" Margin="2,2,2,2"> <controls:PersonGlyph EmploymentStatus="{Binding Path=EmployeeStatus}" Gender="{Binding Path=Gender Mode=OneWay Converter={StaticResource pggFormatter}}" SalaryType="{Binding Path=EmployeeClass}" Margin="2,0,0,0" x:Name="personGlyph" /> <TextBlock Text="{Binding Path=Name}" TextWrapping="NoWrap" x:Name="tbName" Margin="5,0,0,0" VerticalAlignment="Center" IsHitTestVisible="False" FontSize="11" MaxWidth="250" Width="250" /> <TextBlock Text="{Binding Path=WorkPhone}" MaxWidth="86" x:Name="tbPhone" Width="86" IsHitTestVisible="False" FontSize="11" TextWrapping="NoWrap" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="5,0,0,0"/> <TextBlock Text="{Binding Path=MailCode}" MaxWidth="70" x:Name="tbMailCode" Width="70" IsHitTestVisible="False" FontSize="11" TextWrapping="NoWrap" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="5,0,0,0"/> <TextBlock Text="{Binding Path=RespCtrDescription}" MaxWidth="250" x:Name="tbDepartment" Width="250" IsHitTestVisible="False" FontSize="11" TextWrapping="Wrap" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="5,0,0,0"/> </StackPanel> </DataTemplate> </ListBox.ItemTemplate> </ListBox> <TextBlock HorizontalAlignment="Left" Margin="15,15,0,0" VerticalAlignment="Top" Text="The following individuals match your search criteria. Select one for more information." TextWrapping="Wrap" Foreground="#FFFFFFFF" FontSize="14" Width="655.152"/> </Grid> </ControlTemplate> </Setter.Value> </Setter> </Style>
12-03-2008 6:30 PM |
I tried this already with no luck. I also tried it at the <ListBox.Resources> level, too, with the same error (XamlParseException: AG_UNKNOWN_ERROR) resulting. If I remove the converter, everything else binds just fine and the control renders. The PersonGlyph control renders as the default value, though, because the Gender property binding fails because of the lack of a converter (but no error is thrown).
That's the issue here: The Gender property on the PersonGlyph control is an Enumeration defined in the control. The corresponding Gender property on the data class being bound is also an Enumeration defined in the data class. The conversion code should be as follows:
public class PersonGlyphGenderFormatter : IValueConverter { public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { PersonAvatar.PersonAvatarGender genderOut; Person.GenderType genderIn = (Person.GenderType)value; if (genderIn == Person.GenderType.Male) { genderOut = PersonAvatar.PersonAvatarGender.Male; } else { genderOut = PersonAvatar.PersonAvatarGender.Female; } return genderOut; } // No need to implement converting back on a one-way binding public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { throw new NotImplementedException(); } }
12-03-2008 6:49 PM |
Sorry for the run around on this. I have a couple more questions:
1) If you run in debug mode, does your converter ever get hit? If it does, is it returning the correct value?
2) It seems like you really should have a TypeConverter here and then decorate the attribute with it instead of using a value converter. But that is just my opinion and maybe I just misundertanding things again.
12-03-2008 7:03 PM |
No problem. I really appreciate the help.
When I run in debug mode with a breakpoint set at the beginning of the converter, the breakpoint is never reached. This lends support to my theory that the XAML parser does not consider the converter-related markup in the binding markup to be valid XAML. So I'm thinking that this might be a bug -- where data binding is supported in a custom control template but converters are not.
How exactly would a type converter work in this instance?
robmaransky
24 points
34 Posts
02-11-2009 4:08 PM |
Did you ever figure out how to use the ValueConverter in this scenario? I encountered the same issue. I worked around it by using a TemplateBinding together with a DependencyProperty and then binding outside of generic.xaml.
Rob
sl.ayer
Participant
840 points
158 Posts
08-12-2009 11:36 PM |
Just wanted to point out that ValueConverters in templates work in Silverlight 3.0