更新源触发器=属性更改和转换器

3
我有一个简单的“转换器”,它会在输入正数时在TextBox中添加“+”符号。当输入数字后,我想要触发一些操作,但我不想等到TextBox失去焦点:我希望在用户输入文本时立即更新绑定。 TextBox的默认行为是,当用户离开该框时,绑定源会被更新(UpdateSourceTrigger=LostFocus)。在这种情况下,我的转换器按预期工作,并添加了“+”。然而,当我将其更改为以下内容时,“+”就永远不会被添加。
<TextBox Text="{Binding Value, Converter={StaticResource PlusConverter}, UpdateSourceTrigger=PropertyChanged}" />

我可以想象我的converter.Convert()方法没有被调用,这可能有一个很好的理由。我希望以下行为得到实现:
  1. 当用户输入文本时,源立即更新
  2. TextBox失去焦点时,加上+
现在,我正在寻找一种优雅而通用的方式来实现此目标(因为我的应用程序中有许多这样的TextBox)。到目前为止,我还没有找到一个合适的解决方案。

请发布您的转换器代码。 - Kent Boogaart
4个回答

1
另一件你可能想做的事情是编辑 TextBox 的模板并将实际的 PART_ContentHost 往右移一点,然后使用 TextBlock 指示 +/- 部分;也就是从下面这个 TextBox 模板进行更改:
Control
- Border
-- PART_ContentHost (the actual editing part)

转换为:

Control
- Border
-- Horizontal StackPanel
--- TextBlock (contains +/- sign, has 2px right margin)
--- PART_ContentHost (actual editable section)

然后,将TextBlock的内容绑定到文本上,但使用一个转换器来写入“+”或“-”。这样,用户就无法删除+/-部分,您也不必担心解析它;如果您想要做一些像使负号变成红色之类的事情,这也会更容易。

1
感谢您的回答!我自己进一步研究了这个问题,并想出了以下解决方案(虽然我不完全满意,但它可以正常工作)。
我创建了一个自定义控件,为TextBox添加了功能。
它提供了一个LostFocus事件处理程序。当此事件发生时,我的转换器被调用。
然而,我解决转换器的方式并不是很令人满意(我从与我的TextBox相关联的样式中获取它)。该样式具有Text属性的Setter。从那个Setter中,我可以访问我的转换器。
当然,我也可以制作一个“PlusTextBox”,但我使用不同的转换器,我想要一个通用的解决方案。
public class TextBoxEx : TextBox
{
    public TextBoxEx()
    {
        AddHandler(LostFocusEvent,
          new RoutedEventHandler(CallConverter), true);
    }

    public Type SourceType
    {
        get { return (Type)GetValue(SourceTypeProperty); }
        set { SetValue(SourceTypeProperty, value); }
    }

    // Using a DependencyProperty as the backing store for SourceType.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty SourceTypeProperty =
        DependencyProperty.Register("SourceType", typeof(Type), typeof(TextBoxEx), new UIPropertyMetadata(null));

    private static void CallConverter(object sender, RoutedEventArgs e)
    {
        TextBoxEx textBoxEx = sender as TextBoxEx;
        if (textBoxEx.Style == null) {
            return;
        }
        if (textBoxEx.SourceType == null) {
        }
        foreach (Setter setter in textBoxEx.Style.Setters) {
            if (setter.Property.ToString() == "Text") {
                if (! (setter.Value is Binding) ) {
                    return;
                }
                Binding binding = setter.Value as Binding;
                if (binding.Converter == null) {
                    return;
                }
                object value = binding.Converter.ConvertBack(textBoxEx.Text, textBoxEx.SourceType, binding.ConverterParameter, System.Globalization.CultureInfo.CurrentCulture);
                value = binding.Converter.Convert(value, typeof(string), binding.ConverterParameter, System.Globalization.CultureInfo.CurrentCulture);
                if (!(value is string)) {
                    return;
                }
                textBoxEx.Text = (string)value;
            }
        }
    }
}

1

同意Kent B的观点,您需要发布您的转换器代码。

我已经成功使用简单的转换器完成了第一部分(我绑定了第二个未转换的TextBlock以显示该值确实已经更新)。

然而,如果我理解您的第二部分,您正在尝试使TextBox失去焦点后以“+”更新其文本。 这有点棘手,我认为您不能仅使用IConverter来完成此操作。 如果可以完成,我也很想知道答案。

您实际上正在要求的是水印输入行为,例如允许用户输入某些数据,并在基础DataBinding和UI中正确格式化它。 最快/最脏的解决方案是处理TextBoxes' LostFocus,但由于您在整个应用程序中都在使用它,因此这可能不可行。

您还可以考虑将TextBox包装在自己的UserControl中。 如果查看WPFToolkit的DatePicker实现,它具有类似的行为:允许用户输入自由格式的文本,然后自动将值转换为DateTime(如果有效),并以本地化格式显示DateTime。

希望对您有所帮助。


0
在你的转换器中,你能不能检查一下键盘当前的焦点呢?就像这样:
TextBox focusedTextBox = Keyboard.FocusedElement as TextBox;
if (focusedTextBox == null || focusedTextBox != senderOrWhatever)
{
 ' this is where you'd add the +, because the textbox doesn't have focus.
}

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