【问题标题】:WPF Convert TextBox Text using IValueConverterWPF 使用 IValueConverter 转换 TextBox 文本
【发布时间】:2019-12-30 03:38:39
【问题描述】:

我想实现一个 IValueConverter 类,它将文本从 textBox 转换为 TimeSpan 格式字符串。此外,如果用户输入简单的数字,则应将其转换为 TimeSpan,例如。 65.8 -> 0:01:05.800

转换器工作正常,每次击键后都会调用它,因此如果我想写 65.8,它会立即转换为 0:00:06。

怎么了?

IValueConverter 请注意,Solver 是静态类,其中检查时间格式等,这可以正常工作

public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {

            string time = (string)value;
            TimeSpan _ts = new TimeSpan();
            if (Solver.OnlySeconds(time, out _ts))
            {
                return _ts.ToString(Solver.__TFORMAT);
            }
            else return time;
        }
        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            return (string)value;
        }

XAML

<TextBox x:Name="txtTime" Width="100" Height="25" HorizontalAlignment="Center" VerticalAlignment="Center"
                 Text="{Binding RelativeSource={RelativeSource self},Path=Text, Converter={StaticResource ConvertToTime}, UpdateSourceTrigger=LostFocus}"/>

求解器

 public class Solver
    {
        #region constants
        /// <summary>
        /// Output TimeSpan format
        /// </summary>
        public const string __TFORMAT = @"%h\:mm\:ss\.fff";
        /// <summary>
        /// hours and minutes separator
        /// </summary>
        public const string __COL = ":";
        /// <summary>
        /// Negative sign
        /// </summary>
        public const string __NEG = "-";
        private const int __PREC = 1000; //determines precision to 1/1000 of second
        private const long __SECTOTICK = 10000000;
        #endregion
        /// <summary>
        /// Determines if value is convertable to seconds and creates new TimeSpan
        /// </summary>
        /// <param name="time">Time</param>
        /// <param name="TS">out, timeSpan representing Time value</param>
        /// <returns>True if succesfull, false if not</returns>
        #region public Methods
        public static bool OnlySeconds(string time, out TimeSpan TS)
        {
            double dSeconds;

            if (Double.TryParse(time, out dSeconds))
            {
                long ticks = (long)(dSeconds * __SECTOTICK);
                TS = new TimeSpan(ticks);
                return true;
            }
            TS = new TimeSpan();
            return false;

        }
        /// <summary>
        /// Determines if value is valid TimeSpan Format
        /// </summary>
        /// <param name="time">Time</param>
        /// <param name="TS">out TimeSpan value alwas with 0 days</param>
        /// <returns>true if conversions succesfull</returns>
        public static bool IsTimeValue(string time, out TimeSpan TS)
        {
            TimeSpan _ts = new TimeSpan();
            if (OnlySeconds(time,out TS))
            {
                return true;
            }
            if (TimeSpan.TryParse(time,out _ts))
            {
                TS = determineTimeFromString(time);
                return true;
            }
            return false;
        }
        #endregion
        #region private methods
        /// <summary>
        /// Converts selected string to TImeSpan. String has to be in valid TimeSpan format. Erases days
        /// </summary>
        /// <param name="sTime">Time</param>
        /// <returns>Time span</returns>
        private static TimeSpan determineTimeFromString(string sTime)
        {

                int _iColon = Regex.Matches(sTime, __COL).Count;
                string _sResult;
                TimeSpan _tsDays = new TimeSpan();

                if (TimeSpan.TryParse(sTime, out _tsDays))
                {
                    if (_tsDays.Days > 0)
                        return new TimeSpan(0, _tsDays.Hours, _tsDays.Minutes, _tsDays.Seconds, _tsDays.Milliseconds);
                }



                TimeSpan _ts = new TimeSpan();
                if (_iColon == 1) //minutes and seconds
                {
                    //add 0 hours and 0 days
                    _sResult = addTimeToTimeSpan(sTime, "0.0:");
                }
                else if
                  (_iColon == 2) //hours minutes and seconds
                {

                    //add 0 days
                    _sResult = addTimeToTimeSpan(sTime, "0.");
                }
                else _sResult = sTime;

                if (TimeSpan.TryParse(_sResult, out _ts))
                {
                    // in all cases remove day 
                    return new TimeSpan(0, _ts.Hours, _ts.Minutes, _ts.Seconds, _ts.Milliseconds);
                }
                else return _ts;


        }
        /// <summary>
        /// Adds time days or hours to time string
        /// </summary>
        /// <param name="sTime">string original time</param>
        /// <param name="sTimeToAdd">string to ADD</param>
        /// <returns>string</returns>
        private static string addTimeToTimeSpan(string sTime, string sTimeToAdd)
        {
            string _sResult;
            if (sTime.StartsWith(__NEG))
            {
                _sResult = __NEG + sTimeToAdd + sTime.Remove(0, 1);
            }
            else _sResult = sTimeToAdd + sTime;
            return _sResult;
        }
        #endregion region

    }
}

【问题讨论】:

  • 您确定Solver 工作正常吗?请分享OnlySeconds__TFORMAT 成员。看来,您在此成员中有些不正确
  • 我很确定它工作正常。但出版。我的问题是每次击键后都会触发转换器。我不想使用事件,因为我计划在 DataGrid 上对某些列进一步使用此转换器。
  • 我认为您需要添加绑定Delay=500 以防抖。
  • @JanOttis 尝试在TextBox 绑定中使用UpdateSourceTrigger=PropertyChanged
  • 抱歉,您的建议均无效

标签: c# wpf ivalueconverter


【解决方案1】:

您应该创建一个附加行为以在TextBox.LostFocus 上转换TextBox.Text

TextBox.cs

public class TextBox : DependencyObject
{
  #region IsTextConversionEnabled attached property

  public static readonly DependencyProperty IsTextConversionEnabledProperty = DependencyProperty.RegisterAttached(
    "IsTextConversionEnabled", 
    typeof(bool), 
    typeof(TextBox), 
    new PropertyMetadata(false, TextBox.OnIsTextConversionEnabledChanged));

  public static void SetIsTextConversionEnabled([NotNull] DependencyObject attachingElement, bool value) => attachingElement.SetValue(TextBox.IsTextConversionEnabledProperty, value);

  public static bool GetIsTextConversionEnabled([NotNull] DependencyObject attachingElement) => (bool) attachingElement.GetValue(TextBox.IsTextConversionEnabledProperty);

  #endregion

  #region Converter attached property

  public static readonly DependencyProperty ConverterProperty = DependencyProperty.RegisterAttached(
    "Converter", 
    typeof(IValueConverter), 
    typeof(TextBox), 
    new PropertyMetadata(default(IValueConverter)));

  public static void SetConverter([NotNull] DependencyObject attachingElement, IValueConverter value) => attachingElement.SetValue(TextBox.ConverterProperty, value);

  public static IValueConverter GetConverter([NotNull] DependencyObject attachingElement) => (IValueConverter) attachingElement.GetValue(TextBox.ConverterProperty);

  #endregion

  private static void OnIsTextConversionEnabledChanged(DependencyObject attachingElement, DependencyPropertyChangedEventArgs e)
  {
    if (!(attachingElement is System.Windows.Controls.TextBox textBox))
    {
      return;
    }

    bool isEnabled = (bool) e.NewValue;
    if (isEnabled)
    {
      textBox.LostFocus += TextBox.ConvertTextOnLostFocus;
    }
    else
    {
      textBox.LostFocus -= TextBox.ConvertTextOnLostFocus;
    }
  }

  private static void ConvertTextOnLostFocus(object sender, RoutedEventArgs e)
  {
    var textBox = sender as System.Windows.Controls.TextBox;
    textBox.Text = TextBox.GetConverter(textBox)?.Convert(
      textBox.Text,
      typeof(string),
      string.Empty,
      CultureInfo.CurrentUICulture) as string ?? textBox.Text;
  }
}

用法

<Resources>

  <!-- Your IValueConverter implementation -->
  <DoubleToTimeStampConverter x:Key="DoubleToTimeStampConverter" />
</Resources>

<TextBox TextBox.IsTextConversionEnabled="True" 
         TextBox.Converter="{StaticResource DoubleToTimeStampConverter}" />

另一种解决方案是扩展 TextBox 并在内部处理 LostFocus 事件。

【讨论】:

  • 非常感谢女士或先生,这非常有效。更重要的是我开始了解(可能是)wpf 方法。我最初的问题和想法(方法)是错误的。一月
猜你喜欢
  • 2021-10-11
  • 1970-01-01
  • 2020-05-15
  • 2012-11-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多