在 WPF 中使用自定义转换器时强制 Convert 始终运行?

发布于 2024-07-17 12:15:46 字数 2163 浏览 10 评论 0原文

我正在 WPF 中实现一个自定义日期转换器,其想法是更聪明地输入日期,就像 Outlook(能够输入“今天”等),所以我编写了自己的转换器,它正在工作。 它将用户输入的格式设置为 M/d/yy 格式。 例如,如果他们输入:8-2,他们将看到 8/2/09。 迷人的。

问题是:用户可以输入多种内容,最终得到相同的日期。 (8-2 和 8/2,是简单的例子)。 因此,我们假设他们首先输入 8/2,然后通过 ConvertBack 和 Convert 运行,并显示为 8/2/09。 到目前为止,一切都很好。 现在假设他们随后在同一字段中输入 8-2(或再次输入 8/2)。 它通过 ConvertBack 运行,它产生与绑定属性中已经存在的相同日期,因此不必运行 Convert,这意味着“8/2”位于文本框中。 哎呀! 没有数据问题,只是显示问题,但是嘿,整洁很重要。

如何强制 WPF 在所有(非错误)条目之后运行 Convert?

这是转换器的简化版本:

    public class DateConverter : IValueConverter
{
    #region IValueConverter Members

    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        if (value != null)
        {
            string tempStr = value.ToString();
            return ((DateTime.Parse(tempStr)).ToString("M/d/yy"));
        }
        else
        {
            return null;
        }
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return DateTime.Parse(value.ToString());
    }

    #endregion
}

这是它的使用方式:

      <local:FilteredTextBox.Text>
        <Binding Path="Value" ElementName="root" Converter="{StaticResource DateConv}" 
           UpdateSourceTrigger="LostFocus"  Mode="TwoWay" diagnostics:PresentationTraceSources.TraceLevel="High"
        NotifyOnValidationError="True" ValidatesOnDataErrors="True" ValidatesOnExceptions="True">
          <Binding.ValidationRules>
                <local:DateValidation/>
          </Binding.ValidationRules>
        </Binding>
      </local:FilteredTextBox.Text>

谢谢! 斯科特

为了回应下面的评论,这里是支持属性:

      public DateTime? Value
    {
        get
        {
            return (DateTime?)GetValue(ValueProperty);
        }
        set
        {
            SetValue(ValueProperty, value);
            OnPropertyChanged(new DependencyPropertyChangedEventArgs(ValueProperty, null, value)); // I just added this line, it makes no difference
        }
    }

I'm implementing a custom date converter in WPF, the idea to be more clever about date entry, a la Outlook (being able to enter "today", etc.) So I've written my own converter, which is working. It formats the user's entry in the format M/d/yy. So for example, if they enter: 8-2, they'll see 8/2/09. Lovely.

The question is: there are several things the user can enter that ultimately result in the same date. (8-2 and 8/2, being easy examples). So let's just say they start off by entering 8/2, which gets run through ConvertBack and Convert, and gets displayed as 8/2/09. So far so good. Now let's say they enter 8-2 (or 8/2 again) in that same field, right afterwards. That gets run though ConvertBack, which yields the SAME date that's already there in the bound property, so it doesn't bother to run Convert, which means that that "8/2" is sitting there in the textbox. Yick! There's no data issue, just a display one, but hey, neatness counts.

How can I force WPF to run Convert after ALL (non-error) entries?

Here's a simplified version of the converter:

    public class DateConverter : IValueConverter
{
    #region IValueConverter Members

    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        if (value != null)
        {
            string tempStr = value.ToString();
            return ((DateTime.Parse(tempStr)).ToString("M/d/yy"));
        }
        else
        {
            return null;
        }
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return DateTime.Parse(value.ToString());
    }

    #endregion
}

and here's what the use of it looks like:

      <local:FilteredTextBox.Text>
        <Binding Path="Value" ElementName="root" Converter="{StaticResource DateConv}" 
           UpdateSourceTrigger="LostFocus"  Mode="TwoWay" diagnostics:PresentationTraceSources.TraceLevel="High"
        NotifyOnValidationError="True" ValidatesOnDataErrors="True" ValidatesOnExceptions="True">
          <Binding.ValidationRules>
                <local:DateValidation/>
          </Binding.ValidationRules>
        </Binding>
      </local:FilteredTextBox.Text>

Thanks!
Scott

In response to a comment below, here's the backing property:

      public DateTime? Value
    {
        get
        {
            return (DateTime?)GetValue(ValueProperty);
        }
        set
        {
            SetValue(ValueProperty, value);
            OnPropertyChanged(new DependencyPropertyChangedEventArgs(ValueProperty, null, value)); // I just added this line, it makes no difference
        }
    }

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

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

发布评论

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

评论(2

白云悠悠 2024-07-24 12:15:46

是否有可能支持数据属性仅在实际更改值时才触发 PropertyChanged ? 无论值是否更改,只要调用 set 函数,您都可以尝试触发 PropertyChanged。 这将导致绑定被更新。

Is it possible that the backing data property is only firing PropertyChanged if it actually changes value? You could try firing PropertyChanged whenever the set function is called regardless of whether the value changes. This would cause the binding to be updated.

素食主义者 2024-07-24 12:15:46

非常感谢 Josh G - 在他的帮助下,我找到了(或至少是一个)答案。

这是我正在创建的 DatePicker 控件中的文本框。 因此,我没有将文本框直接“锁定”到控件的值,而是创建了一个中间属性,然后将集合调用为依赖属性:

  public DateTime? DateValue
    {
        get
        {
            return _dateValue;
        }
        set
        {
            _dateValue = value;
            OnPropertyChanged("DateValue");
            SetValue(ValueProperty, _dateValue);
        }
    }

这完全可以正常工作。 再次感谢,乔什!

Many thanks to Josh G - with his help, I figured out the (or at least an) answer.

This was for a textbox within a DatePicker control I'm creating. So rather than "lock" the textbox directly to the value of the control, I created an intermediate property, which THEN calls the set to the dependency property:

  public DateTime? DateValue
    {
        get
        {
            return _dateValue;
        }
        set
        {
            _dateValue = value;
            OnPropertyChanged("DateValue");
            SetValue(ValueProperty, _dateValue);
        }
    }

and this totally works as it should. Thanks again, Josh!

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