WPF:文本框文本未更新

发布于 2024-08-09 21:47:04 字数 2909 浏览 6 评论 0原文

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

我的UserControlXAML

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

Value后面的代码中是一个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 中输入值,该值更新我的 UserControlValue 属性,进而更新< myClass 的 em>Name 属性 我正在将 PropertyChangedCallback 分配给 myClass 中的 Name 属性,执行一些验证并在验证失败时重新分配 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
    }

I have a user control that i am using inside a DataTemplate, this UserControl contains a TextBox which is binded with Value property(declared as a DependencyProperty) of my UserControl. In data template I bind this Value property with my actual property say Name (also a DependencyProperty). It works properly, I assign a value to Name property while loading and my TextBox displays it, i change the value from TextBox and it updates my Name property also.
Now the problem comes while I add a PropertyChangedEventHandler in 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 TextBox of UserControl. Can anyone tell me why?

XAML of my UserControl:

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

In code behind Value is a DependencyProperty

I am using this in my 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 TreeView I enter value in the TextBox which updates the Value property of my UserControl, that in turn updates Name property of myClass I am assigning a PropertyChangedCallback to my Name Property in myClass, performing some validation and reassigning the OldValue if the validation fails. It in turn updates Value property also, but i am still seeing that the TextBox has the same value that i entered earlier not the updated one.

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
    }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

仅此而已 2024-08-16 21:47:04

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

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

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

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

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.

This is what explains the solution better

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

稚然 2024-08-16 21:47:04

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

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

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

rtb.AppendText("Text");
rtb.ScrollToEnd();
rtb.UpdateLayout();
月依秋水 2024-08-16 21:47:04

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

您不应该以这种方式修改属性。使用值强制机制并验证强制值回调中的输入。

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 mechanism and validate input in the Coerce value callback.

萌辣 2024-08-16 21:47:04

Anurag,

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

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

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

    public static readonly DependencyProperty ValueProperty = DependencyProperty.Register("Value", typeof(string), typeof(UserControlWithTextBox));
    
    
    私有字符串_oldValue;
    公共字符串值
    {
        get { 返回 GetValue(ValueProperty) 作为字符串; }
        放
        {
            // 检查该值是否通过您的验证逻辑
            if(某些条件(值))
            {
                // 如果是,则设置该值,并记录旧值。
                SetValue(ValueProperty, 值);
                _oldValue = 值;
            }
            别的
            {
                // 否则逻辑失败,将值设置为旧值。
                SetValue(ValueProperty, _oldValue);
            }
            // 实现 INotifyPropertyChanged 以更新 TextBox。
            if(属性更改!= null)
                PropertyChanged(this, new PropertyChangedEventArgs("值"));
        }
    }
    

再一次,正如您从我的回答中看到的那样,您仍然可以在问题中显示代码来帮助其他人回答您的问题,无论您的解决方案有多复杂(如果您想要一个好的答案,就需要付出努力去问一个好问题)。我的答案可能不适合你,但也许它可能会给你一些“谷歌搜索”的指导。希望有帮助。

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

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文