Archives

Archives / 2010 / September
  • Silverlight AutoCompleteBox DataTemplate

    This is more a note for myself how to do this. The Silverlight 4 SDK contains a pretty good AutoCompleteBox that you can use. Download/install the SDK and and the control will be available in your Silverlight Controls Toolbox.

    If you try to use this with RIA Services, you may notice it is displaying the Id/Key in the dropdown, but you yourself want to show a name or description. In that case you have to add a DataTemplate section to the AutoCompleteBox:

    <sdk:AutoCompleteBox x:Name="FilterTextBox"
                           FilterMode="Contains"
                           MaxDropDownHeight="150"
    ItemsSource="{Binding Data, ElementName=dds}"
                           ValueMemberBinding="{Binding Name}">
        <sdk:AutoCompleteBox.ItemTemplate>
            <DataTemplate>
                <TextBlock Text="{Binding Name}" />
            </DataTemplate>
        </sdk:AutoCompleteBox.ItemTemplate>
    </sdk:AutoCompleteBox>

    That should do it.

  • Masked Silverlight TextBox for Swedish National Identification Number (Personnummer)

    In our upcoming Silverlight 4 project there’s a need for a textbox with a mask for entering a Swedish national identification number (personnummer) with either 10 or 12 digits, in the form of yyyymmdd-nnnn. It’s quite simple, I just want to make sure only digits are entered and that the dash (-) is placed automatically and a few other small things that I’d like to tweak.

    As far as I can see (correct me if I’m wrong here) there’s no mask feature in SL4 (yet), so I’m simply going to inherit and extend the built in TextBox. Validation of the number is done in the viewmodel instead of built into the control. See upcoming blogpost for that.

    So, enough talk already, hope it can be of use:

    public class PersonnummerTextBox : TextBox
    {
        public bool TwelveDigits { get; set; }

        private int _leftPart;
        private Key _lastKey;

        public PersonnummerTextBox()
        {
            TextChanged += OnTextChanged;
            Loaded += OnLoaded;
        }

        private void OnLoaded(object sender, RoutedEventArgs e)
        {
            _leftPart = TwelveDigits ? 8 : 6;
        }

        /// <summary>
        /// Only allow digits and tab, no shifts or ctrl
        /// </summary>
        /// <param name="e"></param>
        protected override void OnKeyDown(KeyEventArgs e)
        {
            _lastKey = e.Key;   //used in OnTextChanged to handle Del key

            base.OnKeyDown(e);

            if (((e.Key >= Key.NumPad0 && e.Key <= Key.NumPad9) ||
                (e.Key >= Key.D0 && e.Key <= Key.D9) ||
                e.Key == Key.Tab) &&    //so that we can TAB out from the control ;)
                (Keyboard.Modifiers & ModifierKeys.Shift) == 0 &&
                (Keyboard.Modifiers & ModifierKeys.Control) == 0)
            {
                e.Handled = false;
                return;
            }

            e.Handled = true;
        }

        /// <summary>
        /// Make sure the dash (-) is placed on the correct place automatically
        /// either as yyyymmdd-nnnn or yymmdd-nnnn
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OnTextChanged(object sender, TextChangedEventArgs e)
        {
            var leftPartPlusDash = (_leftPart + 1);
            var cursorPosition = SelectionStart;
            var strippedText = Text.Replace("-", "");

            if (strippedText.Length > _leftPart)
            {
                //move the cursor after the dash
                if (strippedText.Length == leftPartPlusDash &&
                    cursorPosition == leftPartPlusDash &&
                    _lastKey != Key.Delete)
                    cursorPosition = (_leftPart + 2);

                //put a dash in the right place
                Text = string.Format("{0}-{1}",
                    strippedText.Substring(0, _leftPart),
                    strippedText.Substring(_leftPart, Math.Min(4, strippedText.Length - _leftPart)));
            }
            else
                Text = strippedText;

            //move cursor to the wanted position
            SelectionStart = cursorPosition;
        }
    }
  • Silverlight Watermark TextBox Behavior

    (using Visual Studio 2010 and .NET/Silverlight 4)

    Maybe there is a working solution for this already out there, but I created my own Silverlight Behavior for a basic TextBox Watermark which might be useful.

    I wanted to use it like this in my XAML (look at the behaviors tag):

    <TextBlock Margin="5">Watermarked textbox:</TextBlock>
    <TextBox Margin="5">
        <Interactivity:Interaction.Behaviors>
            <local:Watermark Text="Watermark" Foreground="LightGray" />
        </Interactivity:Interaction.Behaviors>
    </TextBox>

     

    The result should be something like this:

    image

     

    To create a Behavior for Silverlight, you must get hold of the System.Windows.Interactivity assembly which ships with Expression Blend. In my system it’s located at:

    c:\Program Files (x86)\Microsoft SDKs\Expression\Blend\Silverlight\v4.0\Libraries\System.Windows.Interactivity.dll

     

    And the code for the Behavior:

    public class Watermark : Behavior<TextBox>
    {
        private bool _hasWatermark;
        private Brush _textBoxForeground;

        public String Text { get; set; }
        public Brush Foreground { get; set; }

        protected override void OnAttached()
        {
            _textBoxForeground = AssociatedObject.Foreground;

            base.OnAttached();
            if (Text != null)
                SetWatermarkText();
            AssociatedObject.GotFocus += GotFocus;
            AssociatedObject.LostFocus += LostFocus;
        }

        private void LostFocus(object sender, RoutedEventArgs e)
        {
            if (AssociatedObject.Text.Length == 0)
                if (Text != null)
                    SetWatermarkText();
        }

        private void GotFocus(object sender, RoutedEventArgs e)
        {
            if (_hasWatermark)
                RemoveWatermarkText();
        }

        private void RemoveWatermarkText()
        {
            AssociatedObject.Foreground = _textBoxForeground;
            AssociatedObject.Text = "";
            _hasWatermark = false;
        }

        private void SetWatermarkText()
        {
            AssociatedObject.Foreground = Foreground;
            AssociatedObject.Text = Text;
            _hasWatermark = true;
        }

        protected override void OnDetaching()
        {
            base.OnDetaching();
            AssociatedObject.GotFocus -= GotFocus;
            AssociatedObject.LostFocus -= LostFocus;
        }
    }

    Like so many Watermark-solutions out there I’m hooking into the GotFocus/LostFocus events and to the work there. Works for me. Love Behaviors.