WPF: TextBox Text не обновляется - PullRequest
       46

WPF: TextBox Text не обновляется

8 голосов
/ 30 октября 2009

У меня есть пользовательский элемент управления, который я использую внутри DataTemplate, этот UserControl содержит TextBox, который связан со свойством Value (объявленным как DependencyProperty) моего UserControl. В шаблоне данных я связываю это свойство Значение с моим фактическим свойством, скажем Имя (также DependencyProperty). Он работает правильно, я присваиваю значение Имя свойство во время загрузки, и мой TextBox отображает его, я изменяю значение с TextBox, и оно также обновляет мое свойство Имя . Теперь проблема возникает, когда я добавляю PropertyChangedEventHandler в свойство зависимостей, проверяю значение, если оно допустимо, ничего не делаю, если оно допустимо, и присваиваю старое значение, если оно недействительно. В случае, если значение недействительно, когда я присваиваю ему это старое значение, свойство обновляется, но оно не отображает обновленное значение в моем TextBox из UserControl. Может кто-нибудь сказать мне, почему?

XAML моего UserControl:

<UserControl x:Name="usercontrol">
   <StackPanel>
      <TextBlock ......./>
      <TextBox Binding={Binding ElementName=usercontrol, Path=Value, Mode=TwoWay}/>
   </StackPanel>
</UserControl>

В коде Значение равно DependencyProperty

Я использую это в моем DataTemplate:

<HierarchicalDataTemplate DataType="{x:Type myLib:myClass}" ItemsSource="{Binding Children}">
    <Expander Header="{Binding}">
        <WrapPanel>
            <edproperty:TextPropertyEditor Caption="Name" Value="{Binding Name, Mode=TwoWay}"/>
            <edproperty:TextPropertyEditor .................../>
            <edproperty:TextPropertyEditor .................../>
            <edproperty:TextPropertyEditor ...................../>
        </WrapPanel>
    </Expander>
</HierarchicalDataTemplate>

Этот шаблон я использую в TreeView. Внутри TreeView я ввожу значение в TextBox, которое обновляет свойство Значение моего UserControl, которое в свою очередь обновляет Имя свойство myClass Я присваиваю PropertyChangedCallback my Name Свойство в myClass, выполнение некоторой проверки и переназначение OldValue, если проверка не удалась. Это, в свою очередь, обновляет Значение свойство также, но я все еще вижу, что TextBox имеет то же значение, которое я ввел ранее, а не обновленное.

public string Name
    {
        get
        {
            return (string)GetValue(NameProperty);
        }
        set
        {
            SetValue(NameProperty, value);
        }
    }

    // Using a DependencyProperty as the backing store for Name.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty NameProperty =
        DependencyProperty.Register("Name", typeof(string), typeof(myClass), new UIPropertyMetadata(null, OnNameChanged));

    protected static void OnNameChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
    {
        if(checkRequired && !IsValid(e.NewValue.ToString()))
        {
            checkRequired=false;
            (sender as myClass).Name = args.OldValue.ToString();
        }
    }

    private static bool IsValid(string name)
    {
         .............some logic here
    }

Ответы [ 4 ]

8 голосов
/ 13 ноября 2009

После нескольких дней осмотра и большого количества поиска я нашел решение моей проблемы

После завершения проверки и присвоения старого значения и обновления свойства зависимости мне нужно вызвать метод UpdateTarget (), чтобы обновить значение в моем TextBox.

Это то, что лучше объясняет решение

http://social.msdn.microsoft.com/forums/en-US/wpf/thread/c404360c-8e31-4a85-9762-0324ed8812ef/

1 голос
/ 06 декабря 2011

Я знаю, что этот вопрос был о TextBox, но для RichTextBox вы бы использовали UpdateLayout ().

rtb.AppendText("Text");
rtb.ScrollToEnd();
rtb.UpdateLayout();
0 голосов
/ 31 октября 2009

Анураг,

Мне нужно сделать много предположений, но я попробую.

У вас, наверное, что-то вроде этого ...

// ...
public static string GetValue(Dependency obj)
{
   // ...
}

// ...
public static void SetValue(DependencyObject obj, string value)
{
    // ...
}

// Using a DependencyProperty as the backing store for Value.  This enables animation, styling, binding, etc...
public static readonly DependencyProperty ValueProperty =
    DependencyProperty.RegisterAttached("Value", typeof(string), typeof(MyCustomControl), new UIPropertyMetadata(OnValuePropertyChanged));

public static void OnValuePropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
    string newValue = e.NewValue as string;

    // You validate your value here,
    // Then if fails, revert to old value.
    if(!SomeCondtion(newValue)) SetValue(obj,e.OldValue as string);

}

Это определенно не лучший подход для проверки данных. Есть и другие, более эффективные подходы, которые дадут вам больше гибкости.

  1. Примените ValidationRule к вашему TexBox. Это моя первая рекомендация, потому что она даст вам возможность управления отображением ошибки при сбое проверки. Если вам нужна простая проверка, ознакомьтесь с моей статьей .
  2. Прослушивание события TextBox.TextChanged. Это громоздко и не может быть повторно использовано при взломе.
  3. Не используйте метод обратного вызова DependecyPropertyChanged. Используйте зарегистрированную строковую собственность и в вашем установщике примените логику, например,

    public static readonly DependencyProperty ValueProperty = DependencyProperty.Register("Value", typeof(string), typeof(UserControlWithTextBox));
    
    
    private string _oldValue;
    public string Value
    {
        get { return GetValue(ValueProperty) as string; }
        set
        {
            // Check if the value passes your validation logic
            if(SomeCondtion(value))
            {
                // If yes, then set the value, and record down the old value.
                SetValue(ValueProperty, value);
                _oldValue = value;
            }
            else
            {
                // Else logic fails, set the value to old value.
                SetValue(ValueProperty, _oldValue);
            }
            // Implement INotifyPropertyChanged to update the TextBox.
            if(PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs("Value"));
        }
    }
    

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

0 голосов
/ 30 октября 2009

Похоже, что вы нарушаете привязку, когда устанавливаете значение свойства непосредственно из кода позади.

Вы не должны изменять свойство таким образом. Используйте механизм приведения значения и подтвердите ввод в обратном вызове значения Coerce.

...