wpfmvvmtextboxselectedtext

MVVM and the TextBox's SelectedText property


I have a TextBox with a ContextMenu in it. When the user right clicks inside the TextBox and chooses the appropriate MenuItem, I would like to grab the SelectedText in my viewmodel. I have not found a good way to do this the "MVVM" way.

So far I have my appliction utilizing Josh Smith's way of MVVM. I am looking to tranfer over to Cinch. Not sure if the Cinch framework will handle issues like this. Thoughts?


Solution

  • There's no straightforward way to bind SelectedText to a data source, because it's not a DependencyProperty... however, it quite easy to create an attached property that you could bind instead.

    Here's a basic implementation :

    public static class TextBoxHelper
    {
    
        public static string GetSelectedText(DependencyObject obj)
        {
            return (string)obj.GetValue(SelectedTextProperty);
        }
    
        public static void SetSelectedText(DependencyObject obj, string value)
        {
            obj.SetValue(SelectedTextProperty, value);
        }
    
        // Using a DependencyProperty as the backing store for SelectedText.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty SelectedTextProperty =
            DependencyProperty.RegisterAttached(
                "SelectedText",
                typeof(string),
                typeof(TextBoxHelper),
                new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, SelectedTextChanged));
    
        private static void SelectedTextChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
        {
            TextBox tb = obj as TextBox;
            if (tb != null)
            {
                if (e.OldValue == null && e.NewValue != null)
                {
                    tb.SelectionChanged += tb_SelectionChanged;
                }
                else if (e.OldValue != null && e.NewValue == null)
                {
                    tb.SelectionChanged -= tb_SelectionChanged;
                }
    
                string newValue = e.NewValue as string;
    
                if (newValue != null && newValue != tb.SelectedText)
                {
                    tb.SelectedText = newValue as string;
                }
            }
        }
    
        static void tb_SelectionChanged(object sender, RoutedEventArgs e)
        {
            TextBox tb = sender as TextBox;
            if (tb != null)
            {
                SetSelectedText(tb, tb.SelectedText);
            }
        }
    
    }
    

    You can then use it like that in XAML :

    <TextBox Text="{Binding Message}" u:TextBoxHelper.SelectedText="{Binding SelectedText}" />