Search code examples
c#windows-phone-8mvvmwindows-phone

Can I bind to a utility class?


I have a common class filled with generic functions like the one below to parse a text box:

public static void DoubleParse_KeyDown(object sender, KeyEventArgs e)
{
    if (e.Key == Key.Decimal)
    {
        var textBox = sender as TextBox;
        if (textBox != null)
            textBox.Text += Convert.ToChar(CultureInfo.CurrentCulture.NumberFormat.CurrencyDecimalSeparator);
    }
    else
    {
        e.Handled = (e.Key >= Key.D0 && e.Key <= Key.D9) ||
                    (e.Key >= Key.NumPad0 && e.Key <= Key.NumPad9) || 
                    e.Key == Key.Back || e.Key == Key.Delete ||
                    e.Key == Key.Left || e.Key == Key.Right || e.Key == Key.Unknown;
    }
}

I thought I could use this everywhere across my pages as a single source for TextBox keydown events. New to MVVM implementation in WP8, curious if there's a way to achieve this?

In the spirit of MVVM (though I'm not a purist), I understand it doesn't need to be in the viewmodel specifically, but I'd still like it centralized.

A quick note:

  • The class isn't static, I understand I can't use that directly in xaml.
  • I thought to make the class some kind of StaticResource and reference the functions in xaml. But that doesn't seem to work.
  • I'm currently just using pass through functions in the code-behind and passing the sender on to the static functions.

Solution

  • You want an Attached Behavior.

    public static class TextBoxBehavior
    {
        public static bool GetAllowOnlyDecimalInput(TextBox texbox)
        {
            return (bool)texbox.GetValue(AllowOnlyDecimalInputProperty);
        }
    
        public static void SetAllowOnlyDecimalInput(
          TextBox texbox, bool value)
        {
            texbox.SetValue(AllowOnlyDecimalInputProperty, value);
        }
    
        public static readonly DependencyProperty AllowOnlyDecimalInputProperty =
            DependencyProperty.RegisterAttached(
            "AllowOnlyDecimalInput",
            typeof(bool),
            typeof(TextBox),
            new PropertyMetadata(false, OnAllowOnlyDecimalInputChanged));
    
        static void OnAllowOnlyDecimalInputChanged(
          DependencyObject depObj, DependencyPropertyChangedEventArgs e)
        {
            TextBox item = depObj as TextBox;
            if (item == null)
                return;
    
            if (e.NewValue is bool == false)
                return;
    
            if ((bool)e.NewValue)
                item.KeyDown += OnTextBoxDoubleParse_KeyDown;
            else
                item.KeyDown -= OnTextBoxDoubleParse_KeyDown;
        }
    
        static void OnTextBoxDoubleParse_KeyDown(object sender, KeyEventArgs e)
        {
            if (!Object.ReferenceEquals(sender, e.OriginalSource))
                return;
    
            TextBox item = e.OriginalSource as TextBox;
            if (item != null) {
                if (e.Key == Key.Decimal)
                {
                    var textBox = sender as TextBox;
                    if (textBox != null)
                        textBox.Text += Convert.ToChar(CultureInfo.CurrentCulture.NumberFormat.CurrencyDecimalSeparator);
                }
                else
                {
                    e.Handled = (e.Key >= Key.D0 && e.Key <= Key.D9) ||
                                (e.Key >= Key.NumPad0 && e.Key <= Key.NumPad9) || 
                                e.Key == Key.Back || e.Key == Key.Delete ||
                                e.Key == Key.Left || e.Key == Key.Right || e.Key == Key.Unknown;
                }
            }
        }
    
        #endregion // AllowOnlyDecimalInput
    }
    

    In XAML use it with

    <TextBox my:TextBoxBehavior.AllowOnlyDecimalInput="True" />
    

    You can also set this in an WPF Style and have it reusable within all or many controls rather than adding the property each time manually.