Coercion in Silverlight does not work
I've a custom control look like this:
generic.xaml
<Style TargetType="controls:MyControl">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="controls:MyControl">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="20" />
<RowDefinition Height="20" />
</Grid.RowDefinitions>
<TextBox Grid.Row="0"
Text="{Binding ElementName=slider, Path=Value}" />
<Slider Grid.Row="1" Name="slider" Width="120"
Minimum="1" Maximum="12"
Val开发者_如何学运维ue="{Binding Mode=TwoWay,
RelativeSource={RelativeSource TemplatedParent},
Path=Value}"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
MyControl.cs
public static readonly DependencyProperty ValueProperty =
DependencyProperty.Register("Value",
typeof(double),
typeof(MyControl),
new PropertyMetadata(0d, OnValueChanged));
public double Value
{
get { return (double)base.GetValue(ValueProperty); }
set { base.SetValue(ValueProperty, value); }
}
private static void OnValueChanged(DependencyObject source,
DependencyPropertyChangedEventArgs e)
{
MyControl myControl = (MyControl)source;
myControl.OnValueChanged((double)e.OldValue, (double)e.NewValue);
}
protected virtual void OnValueChanged(double oldValue, double newValue)
{
double coercedValue = CoerceValue(newValue);
if (coercedValue != newValue)
{
this.Value = coercedValue;
}
}
private double CoerceValue(double value)
{
double limit = 7;
if (value > limit)
{
return limit;
}
return value;
}
The TextBox is just a dummy to show the value.
Now when I add this control to an Application, I am able to set the Slider value greater than 7, although the value of my DependencyProperty is set to 7.
What I am doing wrong? Does the TwoWayBinding does not work in this situation?
Thanks in advance
Steps for my repro:-
- Create a fresh new Silverlight Application in VS2010 call SilverlightApplication1.
- Add new "Silverlight Templated Control" to the silverlight project, naming it "MyControl".
Copied the inner contents or you ControlTemplate into the ControlTemplate of the themes/Generic.xaml file. This Entire generic file looks like:-
<Style TargetType="local:MyControl"> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="local:MyControl"> <Grid> <Grid.RowDefinitions> <RowDefinition Height="20" /> <RowDefinition Height="20" /> </Grid.RowDefinitions> <TextBox Grid.Row="0" Text="{Binding ElementName=slider, Path=Value}" /> <Slider Grid.Row="1" Name="slider" Width="120" Minimum="1" Maximum="12" Value="{Binding Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}, Path=Value}"/> </Grid> </ControlTemplate> </Setter.Value> </Setter> </Style>
- Copied your C# placed in in MyControl.cs. The whole file looks like:-
using System.Windows; using System.Windows.Controls;
namespace SilverlightApplication1
{
public class MyControl : Control
{
public MyControl()
{
this.DefaultStyleKey = typeof(MyControl);
}
public static readonly DependencyProperty ValueProperty =
DependencyProperty.Register("Value",
typeof(double),
typeof(MyControl),
new PropertyMetadata(0d, OnValueChanged));
public double Value
{
get { return (double)base.GetValue(ValueProperty); }
set { base.SetValue(ValueProperty, value); }
}
private static void OnValueChanged(DependencyObject source,
DependencyPropertyChangedEventArgs e)
{
MyControl myControl = (MyControl)source;
myControl.OnValueChanged((double)e.OldValue, (double)e.NewValue);
}
protected virtual void OnValueChanged(double oldValue, double newValue)
{
double coercedValue = CoerceValue(newValue);
if (coercedValue != newValue)
{
this.Value = coercedValue;
}
}
private double CoerceValue(double value)
{
double limit = 7;
if (value > limit)
{
return limit;
}
return value;
}
}
}
Added an instance of MyControl to MainPage.xaml, which now looks like:-
<UserControl x:Class="SilverlightApplication1.MainPage" 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:local="clr-namespace:SilverlightApplication1" mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="400"> <Grid x:Name="LayoutRoot" Background="White"> <local:MyControl /> </Grid> </UserControl>
Run the solution, works fine.
精彩评论