سؤال

I was on to implement a UserControl called PhoneBox that contains a single TextBox, some custom logic, and has a DependencyProperty called PhoneNo. It was to be used in in a two-way binding scenario with a LostFocus for UpdateSourceTrigger. So I wrote the following code -

XAML (UserControl):

<StackPanel>
    <TextBox Name="txtPhone" MinWidth="120" MinHeight="23" LostFocus="txtPhone_LostFocus" GotFocus="txtPhone_GotFocus"/>
</StackPanel>  

Code-Behind (UserControl):

public partial class PhoneBox : UserControl
{
    //Some Code

    static PhoneBox()
    {
        FrameworkPropertyMetadata phoneNoMetadata =
            new FrameworkPropertyMetadata(new PropertyChangedCallback(OnPhoneNoChanged),
                                          new CoerceValueCallback(CoercePhoneNoValue));
        PhoneNoProperty = DependencyProperty.Register("PhoneNo", typeof (string), typeof (PhoneBox),
                                                       phoneNoMetadata,
                                                       new ValidateValueCallback(ValidatePhoneNoValue));
    }

    public readonly static DependencyProperty PhoneNoProperty;
    public string PhoneNo
    {
        get { return (string)GetValue(PhoneNoProperty); }
        set { SetValue(PhoneNoProperty, value); }
    }

    private static void OnPhoneNoChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        PhoneBox phoneBox = (PhoneBox)d;
        string newValue = (string)e.NewValue;

        phoneBox.txtPhone.Text = newValue;
    }

    private static object CoercePhoneNoValue(DependencyObject d, object basevalue)
    {
        return basevalue;
    }

    private static bool ValidatePhoneNoValue(object value)
    {
        return true;
    }

    private void txtPhone_LostFocus(object sender, RoutedEventArgs e)
    {
        this.SetValue(PhoneNoProperty, this.txtPhone.Text);
    }

    private void txtPhone_GotFocus(object sender, RoutedEventArgs e)
    {
        if (!String.IsNullOrEmpty(txtPhone.Text))
            this.txtPhone.Text = this.FilterText(txtPhone.Text);
    }

    private string FilterText(string text)
    {
        //Some cutom logic
    }

    //Some more Code
}  

XAML (Consumer):

<pbc:PhoneBox PhoneNo="{Binding Path=User.Phone, Mode=TwoWay, UpdateSourceTrigger=LostFocus}"/>  

It works. But my question is, the way I used the txtPhone_LostFocus event handler to set proerty value (and in turn update source), is that appropriate? Is there any more appropriate way to do this? I'm a novice in this DependencyProperty thing, so any guiding, suggestion, comments will be thankfully appreciated.

هل كانت مفيدة؟

المحلول

The WPF way to handle this situation is to have a Binding between your UserControl's DependencyProperty and the TextBox declared in the UserControl's XAML file. This is also where you would set the LostFocus UpdateSourceTrigger (which you don't have to, since it is the default behaviour). You'd declare the Binding on the TextBox (i.e. inside the UserControl), so client code using the UserControl would be free to set another binding on the PhoneNo property (from outside of the UserControl). Also, if your CoerceValue callback only returns the base value, better go without it from the start.

This might be what David meant initially...

نصائح أخرى

In this case, I would indeed rather use the UpdateSourceTrigger enumeration in the DP metadata than the LostFocus EventHandler, and get rid of all the redundant methods: it's always better to let WPF do those things for you if you can: it'll do them better and faster.

Plus in this case, I personally find it a lot easier to read in the metadata than in the lostFocus method. But this is a matter of taste I guess.

edit: no no, I understood what you meant, But I might not have been clear myself in my answer. Here is roughly what I would do (just to give you a hint, that would require some tuning in your case):

public partial class PhoneBox : UserControl
{
    public static readonly DependencyProperty PhoneNoProperty = DependencyProperty.Register(
        "PhoneNo",
        typeof (string),
        typeof (PhoneBox),
        new UIPropertyMetadata(UpdateSourceTrigger.LostFocus),
        new ValidateValueCallback(ValidatePhoneNoValue));

    public string PhoneNo
    {
        get { return (string)GetValue(PhoneNoProperty); }
        set { SetValue(PhoneNoProperty, value); }
    }

// ... your code here.

}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top