WP7 Custom Control Binding Inner Control
I'm creating a custom control that has a PasswordBox
in it. How do I hook up a DependencyProperty
of my custom control to the Password
property of the PasswordBox
?
From all the examples I see, hooking it up the password in the template using TemplateBinding
shoul开发者_如何转开发d do the trick, but this doesn't seem to be working. What am I missing?
generic.xaml
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:CustomControlBinding="clr-namespace:CustomControlBinding">
<Style TargetType="CustomControlBinding:PasswordBoxTest">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="CustomControlBinding:PasswordBoxTest">
<Grid Background="Transparent">
<PasswordBox Password="{TemplateBinding Text}" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
PasswordBoxTest.cs
namespace CustomControlBinding
{
public class PasswordBoxTest : Control
{
public static readonly DependencyProperty TextProperty = DependencyProperty.Register( "Text", typeof( string ), typeof( PasswordBoxTest ), new PropertyMetadata( OnTextPropertyChanged ) );
public string Text
{
get { return GetValue( TextProperty ) as string; }
set { SetValue( TextProperty, value ); }
}
public PasswordBoxTest()
{
DefaultStyleKey = typeof( PasswordBoxTest );
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
}
private static void OnTextPropertyChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e )
{
}
}
}
You have to use RelativeSource bindings, for it to work. Or you have to set the DataContext of your UserControl to this
.
TemplateBinding is ok. You need to set somehow the binding source (for example through mentioned DataContext or simply in Xaml using Text attribute), but I cannot judge where's the problem since you omitted this code.
I don't know what's the purpose of this class, but probably adding some features to the standard PasswordBox. I would keep both implementations as similar as possible. What I mean the Text property should be called Password etc.
On more remark: The presented template does not need the Grid. Unless you have extra reason for using it, remove it - it just adds on the layout complexity. Note that the default template of the PasswordBox is already wrapped in an identical Grid...
I haven't been able to get this to work no matter what I do. What I did instead that does work is setting up some fake binding in code.
namespace CustomControlBinding
{
public class PasswordBoxTest : Control
{
private PasswordBox passwordBox;
private string passwordSetBeforeTemplateApplied;
public static readonly DependencyProperty PasswordProperty = DependencyProperty.Register( "Password", typeof( string ), new PropertyMetadata( OnPasswordPropertyChanged ) );
public string Password
{
get { return GetValue( PasswordProperty ) as string; }
set { SetValue( PasswordProperty, value ); }
}
public PasswordBoxTest()
{
DefaultStyleKey = typeof( PasswordBoxTest );
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
passwordBox = (PasswordBox)GetTemplateChild( "PasswordElement" );
passwordBox.PasswordChanged += PasswordBoxPasswordChanged;
if( !string.IsNullOrEmpty( passwordSetBeforeTemplateApplied ) )
{
passwordBox.Password = passwordSetBeforeTemplateApplied;
}
}
public static void OnPasswordPropertyChanged( DependencyObject d, DependencyPropertyChangedEventArgs e )
{
( (WatermarkPasswordBox)d ).OnPasswordChanged( d, e );
}
private void OnPasswordChanged( DependencyObject d, DependencyPropertyChangedEventArgs e )
{
if( passwordBox == null )
{
passwordSetBeforeTemplateApplied = Password;
return;
}
if( Password != passwordBox.Password )
{
passwordBox.Password = Password;
}
}
private void PasswordBoxPasswordChanged( object sender, RoutedEventArgs e )
{
if( passwordBox.Password != Password )
{
Password = passwordBox.Password;
}
}
}
}
精彩评论