WPF:TextBox 文本未更新

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1648792/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-08 21:09:03  来源:igfitidea点击:

WPF: TextBox Text is not updating

wpfxamltextboxuser-controlsdatatemplate

提问by viky

I have a user control that i am using inside a DataTemplate, this UserControlcontains a TextBoxwhich is binded with Valueproperty(declared as a DependencyProperty) of my UserControl. In data template I bind this Valueproperty with my actual property say Name(also a DependencyProperty). It works properly, I assign a value to Nameproperty while loading and my TextBoxdisplays it, i change the value from TextBoxand it updates my Nameproperty also. Now the problem comes while I add a PropertyChangedEventHandlerin the dependency property, I check for the value if it is valid, do nothing if valid and assign old value if not valid. In case of value not valid, when I assign it that old value, property updates but it is not displaying updated value in my TextBoxof UserControl. Can anyone tell me why?

我有我使用内部的用户控件DataTemplate,这UserControl包含了TextBox其绑定与价值属性(声明为DependencyProperty我的)UserControl。在数据模板中,我将此Value属性与我的实际属性绑定,例如Name(也是 a DependencyProperty)。它工作正常,我在加载时为Name属性分配了一个值并TextBox显示它,我更改了值TextBox并更新了我的Name属性。现在问题来了,而我添加了PropertyChangedEventHandler在依赖属性中,我检查该值是否有效,如果有效则不执行任何操作,如果无效则分配旧值。如果值无效,当我为其分配旧值时,属性会更新,但不会在我TextBoxUserControl. 谁能告诉我为什么?

XAMLof my UserControl:

我的XAMLUserControl

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

In code behind Valueis a DependencyProperty

Value后面的代码中是一个DependencyProperty

I am using this in my DataTemplate:

我在我的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>

This template I am using in a TreeView. Inside TreeViewI enter value in the TextBoxwhich updates the Valueproperty of my UserControl, that in turn updates Nameproperty of myClassI am assigning a PropertyChangedCallbackto my NameProperty in myClass, performing some validation and reassigning the OldValueif the validation fails. It in turn updates Valueproperty also, but i am still seeing that the TextBoxhas the same value that i entered earlier not the updated one.

我在TreeView. 里面TreeView我输入值TextBox,其更新的价值我的财产UserControl,这反过来又更新名称的属性myClass,我分配PropertyChangedCallback到我的名字在房产myClass,执行一些验证和重新分配OldValue,如果验证失败。它反过来也会更新Value属性,但我仍然看到它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
    }

采纳答案by viky

After days of looking around and a lot of search i found the solution of my problem

经过几天的环顾和大量搜索,我找到了问题的解决方案

After all validation done and assigning old value and updating the dependecy property, i need to cal UpdateTarget() method, to Update the value in my TextBox.

在完成所有验证并分配旧值并更新依赖属性后,我需要调用 UpdateTarget() 方法,以更新我的 TextBox 中的值。

This is what explains the solution better

这就是更好地解释解决方案的原因

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

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

回答by mxgg250

I know this question was about TextBox but for RichTextBox you would use UpdateLayout().

我知道这个问题是关于 TextBox 但对于 RichTextBox 你会使用 UpdateLayout()。

rtb.AppendText("Text");
rtb.ScrollToEnd();
rtb.UpdateLayout();

回答by Anvaka

It looks like you are breaking binding when you set property value directly from code behind.

当您直接从后面的代码设置属性值时,看起来您正在破坏绑定。

You shouldn't modify property that way. Use value coercion mechanismand validate input in the Coerce value callback.

你不应该那样修改属性。使用值强制机制并验证强制值回调中的输入。

回答by Tri Q Tran

Anurag,

阿努拉格,

There are a lot of assumptions I have to make here, but I'll give it a shot.

我必须在这里做出很多假设,但我会试一试。

You probably have something like this...

你可能有这样的事情......

// ...
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);

}

This is definitely not the best approach to validate data. There are other, more efficient approaches that will give you more flexibility.

这绝对不是验证数据的最佳方法。还有其他更有效的方法可以为您提供更大的灵活性。

  1. Apply a ValidationRule on your TexBox. This is my first recommendation because it will give you control on displaying the error when validation fails. If you're after a simple validation, check out my article.
  2. Listen for the TextBox.TextChanged event. This is cumbersome and is not re-usable at most hacked.
  3. Don't use DependecyPropertyChanged callback method. Use a registered string Property and in your setter, apply logic, e.g.

    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"));
        }
    }
    
  1. 在 TexBox 上应用 ValidationRule。这是我的第一个建议,因为它可以让您在验证失败时控制显示错误。如果您需要简单的验证,请查看我的文章
  2. 侦听 TextBox.TextChanged 事件。这很麻烦,并且在大多数情况下无法重复使用。
  3. 不要使用 DependecyPropertyChanged 回调方法。使用注册的字符串属性并在您的 setter 中应用逻辑,例如

    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"));
        }
    }
    

Once again, as you can see from my answer that you can still show code in your question to help others answer your question no matter how complex your solution may be (if you want a good answer, you need to put in the effort to ask a good question). My answer may not work for you but maybe it might give you some "Googling" directions. Hope it helps.

再一次,正如您从我的回答中看到的,无论您的解决方案多么复杂,您仍然可以在您的问题中显示代码以帮助其他人回答您的问题(如果您想要一个好的答案,您需要努力提出问题)一个好问题)。我的回答可能对您不起作用,但可能会给您一些“谷歌搜索”的指导。希望能帮助到你。