WPF:TextBox文本不更新

8
我有一个用户控件,我在DataTemplate内使用它,这个UserControl包含一个绑定了Value属性的TextBox(声明为DependencyProperty)。在数据模板中,我将这个Value属性与我的实际属性Name(也是DependencyProperty)绑定。它正常工作,我在加载时给Name属性分配一个值,我的TextBox显示它,我从TextBox更改值,它也更新了我的Name属性。
现在问题在于,当我在依赖属性中添加一个PropertyChangedEventHandler时,我检查该值是否有效,如果有效则不执行任何操作,如果无效则分配旧值。在值无效的情况下,当我分配旧值时,属性会更新,但它不会在我的中的TextBox中显示更新后的值。有人可以告诉我原因吗?
以下是我的的XAML:
<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 属性,然后更新 myClassName 属性。我为 myClassName 属性分配了一个 PropertyChangedCallback,执行一些验证并重新赋值 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
    }

2
没有看到你的代码,这将是一个难以适当评论的问题。你能发一下你的代码吗? - Pete OHanlon
这太多了,无法张贴。如果需要更多解释,您可以提问。 - viky
2
不行,你需要写出最少的代码来复现问题...否则我们只能猜测,而不是回答。没有人喜欢不确定性。特别是程序员。 - Anvaka
4个回答

8

1

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

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

0

安纳拉格,

我需要做出很多假设,但我会尝试一下。

你可能有类似这样的东西...

// ...
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回调方法。使用已注册的字符串属性,在您的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
        {
            // 检查值是否通过了您的验证逻辑
            if(SomeCondtion(value))
            {
                // 如果是,则设置该值,并记录旧值。
                SetValue(ValueProperty, value);
                _oldValue = value;
            }
            else
            {
                // 否则逻辑失败,将值设置为旧值。
                SetValue(ValueProperty, _oldValue);
            }
            // 实现INotifyPropertyChanged以更新TextBox。
            if(PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs("Value"));
        }
    }
    

正如你从我的回答中看到的那样,无论你的解决方案有多复杂(如果你想得到一个好的答案,你需要付出努力提出一个好问题),你仍然可以在你的问题中展示代码来帮助其他人回答你的问题。我的答案可能对你不起作用,但也许它可以给你一些“谷歌”的方向。希望能帮到你。


我已经更新了我的问题,抱歉耽搁了。为什么我的文本框会出现这种情况? - viky
你的示例中在 setter 中添加的验证不会在 WPF 通过绑定、setter 或其他机制更新属性时发生。建议在使用依赖属性时,永远不要将任何内容放入访问器或变异器中。 - jpierson

0

看起来你正在从代码后台直接设置属性值时破坏绑定。

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


我也尝试了这种方法,但问题仍然存在,我的文本框的值没有更新。 - viky
我已经更新了我的问题,你能给我一些建议吗? 抱歉耽搁了。 - viky

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接