2010-04-05 2 views
1

Я нашел этот вопрос MVVM and the TextBox's SelectedText property. Тем не менее, у меня возникли проблемы с получением решения для работы. Это мой нерабочий код, в котором я пытаюсь отобразить выделенный текст в текстовом поле во втором текстовом поле.MVVM- Как я могу привязать свойство, которое не является DependancyProperty?

Вид:

SelectedText и текст просто строковые свойства из моей ViewModel.

<TextBox Text="{Binding Path=Text, UpdateSourceTrigger=PropertyChanged}" Height="155" HorizontalAlignment="Left" Margin="68,31,0,0" Name="textBox1" VerticalAlignment="Top" Width="264" AcceptsReturn="True" AcceptsTab="True" local:TextBoxHelper.SelectedText="{Binding SelectedText, UpdateSourceTrigger=PropertyChanged, Mode=OneWayToSource}" /> 
     <TextBox Text="{Binding SelectedText, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" Height="154" HorizontalAlignment="Left" Margin="82,287,0,0" Name="textBox2" VerticalAlignment="Top" Width="239" /> 

TextBoxHelper

public static class TextBoxHelper 
{ 
    #region "Selected Text" 
    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); 
     } 
    } 
    #endregion 

} 

Что я делаю неправильно?

ответ

1

Причина, по которой это не работает, заключается в том, что обратный вызов изменения свойств не поднимается (поскольку связанное значение с вашей виртуальной машины такое же, как значение по умолчанию, указанное в метаданных для этого свойства). Более фундаментально, однако, ваше поведение будет отделяться, когда выбранный текст установлен в null. В подобных случаях я имею тенденцию иметь другое прикрепленное свойство, которое просто используется для включения мониторинга выбранного текста, а затем свойство SelectedText может быть связано. Так, что-то вроде этого:

#region IsSelectionMonitored 
public static readonly DependencyProperty IsSelectionMonitoredProperty = DependencyProperty.RegisterAttached(
    "IsSelectionMonitored", 
    typeof(bool), 
    typeof(PinnedInstrumentsViewModel), 
    new FrameworkPropertyMetadata(OnIsSelectionMonitoredChanged)); 

[AttachedPropertyBrowsableForType(typeof(TextBox))] 
public static bool GetIsSelectionMonitored(TextBox d) 
{ 
    return (bool)d.GetValue(IsSelectionMonitoredProperty); 
} 

public static void SetIsSelectionMonitored(TextBox d, bool value) 
{ 
    d.SetValue(IsSelectionMonitoredProperty, value); 
} 

private static void OnIsSelectionMonitoredChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e) 
{ 
    TextBox tb = obj as TextBox; 
    if (tb != null) 
    { 
     if ((bool)e.NewValue) 
     { 
      tb.SelectionChanged += tb_SelectionChanged; 
     } 
     else 
     { 
      tb.SelectionChanged -= tb_SelectionChanged; 
     } 

     SetSelectedText(tb, tb.SelectedText); 
    } 
} 
#endregion 

#region "Selected Text" 
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) 
    { 
     tb.SelectedText = e.NewValue as string;    
    } 
} 

static void tb_SelectionChanged(object sender, RoutedEventArgs e) 
{ 
    TextBox tb = sender as TextBox; 
    if (tb != null) 
    { 
     SetSelectedText(tb, tb.SelectedText); 
    } 
} 
#endregion 

И тогда в вашем XAML, вы должны добавить, что имущество первого TextBox:

<TextBox ... local:TextBoxHelper.IsSelectionMonitored="True" local:TextBoxHelper.SelectedText="{Binding SelectedText, Mode=OneWayToSource}" /> 
-1

Вам нужна нормальная обертку .net свойство для DependencyProperty, некоторые, как:

public string SelectedText 
{ 
    set {SetSelectedText(this, value);} 
... 

Это не требуется выполнения (среда использования набор/получить), но требуется дизайнер и компилятор.

+0

SelectedText свойство является Attached (Dependency) Свойство не является 'нормальным' Dependency Property. Для обзора см. Http://msdn.microsoft.com/en-us/library/ms749011.aspx –

+0

Хорошо, я не очень осторожно, когда читал оригинальный вопрос. Но разве вы не считаете, что голосом слишком много, чтобы попытаться помочь? – Codism

+0

Не принимайте лидирующее отношение лично. Это всего лишь инструмент, помогающий людям отбирать полезные ответы от бесполезных. Если вы понимаете, что вы опубликовали бесполезный ответ, и он занижен, вы можете его удалить. – RandomEngy

1

Для того, чтобы обработчик SelectedTextChanged для запуска свойства SelectedText должен иметь начальное значение. Если вы не инициализируете это до некоторого значения (string.Empty как минимум), то этот обработчик никогда не будет срабатывать, и в свою очередь вы никогда не зарегистрируете обработчик tb_SelectionChanged.

+0

Я изменил его следующим образом: new FrameworkPropertyMetadata (string.Empty, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, SelectedTextChanged)); Но это все еще не работает. Разве я не понял, что вы говорите? – Justin

+0

Когда я пробежал ваш образец кода, я установил значение свойства SelectedText в ViewModel в string.Empty. Изменение PropertyMetadata не приведет к срабатыванию измененного обработчика. –

+0

Я попытался настроить SelectedText на string.Empty, но текст, выделенный в первом текстовом поле, по-прежнему не отображается во втором текстовом поле. – Justin

0

Ваших связывающие попыток связать Text свойства вашего TextBox в SelectedText свойства контекстатекущих данных TextBox «s. Поскольку вы работаете с прикрепленной собственностью, а не свойство висит от вашего контекста данных, вам нужно будет предоставить более подробную информацию в вашем связывании:

<TextBox Text="{Binding local:TextBoxHelper.SelectedText, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" ... /> 

Где local был связан с пространством имен CLR, содержащими TextBoxHelper класс.

+0

В текущем контексте данных есть свойство SelectedText, и оно привязано к вложенному свойству через: local: TextBoxHelper.SelectedText = "{Binding SelectedText, UpdateSourceTrigger = PropertyChanged, Mode = OneWayToSource}" – Justin

1

Это работает для меня, используя класс TextBoxHelper. Как уже упоминалось, вам нужно инициализировать свойство SelectedText TextBoxHelper с ненулевым значением. Вместо привязки данных к строковому свойству (SelText) в представлении вы должны привязываться к строковому свойству вашей виртуальной машины, которая должна реализовать INotifyPropertyChanged.

XAML:

<Window x:Class="TextSelectDemo.Window1" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:local="clr-namespace:TextSelectDemo" 
    Height="300" Width="300"> 
    <StackPanel> 
     <TextBox local:TextBoxHelper.SelectedText="{Binding Path=SelText, Mode=TwoWay}" /> 
     <TextBox Text="{Binding Path=SelText}" /> 
    </StackPanel> 
</Window> 

Код позади:

using System.ComponentModel; 
using System.Windows; 

namespace TextSelectDemo 
{ 
    public partial class Window1 : Window, INotifyPropertyChanged 
    { 
     public Window1() 
     { 
      InitializeComponent(); 

      SelText = string.Empty; 

      DataContext = this; 
     } 

     private string _selText; 
     public string SelText 
     { 
      get { return _selText; } 
      set 
      { 
       _selText = value; 
       if (PropertyChanged != null) 
       { 
        PropertyChanged(this, new PropertyChangedEventArgs("SelText")); 
       } 
      } 
     } 

     public event PropertyChangedEventHandler PropertyChanged; 
    } 
} 
Смежные вопросы