带有省略号修剪和验证装饰的WPF TextBox

时间:2015-11-03 15:05:04

标签: wpf textbox ellipsis adorner

我目前正在开发一个用户控件,以便为TextBox添加更多功能:

  • 如果文本很大且文本框失去焦点,省略号修剪
  • TextBox前面的标签
  • 错误验证

我找到了省略号的示例。此示例存储当前值 依赖项属性中的TextBox,如果元素获得/失去焦点,则设置TextBox.Text属性。

这是我的用户控件的xaml代码:

<UserControl x:Class="WpfTextBoxEllipsis.EditUC"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         mc:Ignorable="d" 
         d:DesignHeight="300" d:DesignWidth="300"
         Name="EDIT"
         Loaded="EditUC_OnLoaded">
<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="Auto"/>
        <ColumnDefinition Width="*"/>
    </Grid.ColumnDefinitions>

    <TextBlock Text="Label" Margin="10,0" Grid.Column="0" VerticalAlignment="Center"/>
    <TextBox Name="Box" Grid.Column="1"
             LostFocus="BoxLostFocus"
             GotFocus="BoxGotFocus"
             LayoutUpdated="BoxOnLayoutUpdated"/>
</Grid>

我的用户控件背后的代码:

public partial class EditUC : UserControl
{
    private string textvalue;

    public EditUC()
    {
        InitializeComponent();
    }

    internal UpdateSourceTrigger UpdateTrigger { get; set; }

    #region Text property

    public static readonly DependencyProperty TextProperty = DependencyProperty.Register(
        "Text",
        typeof(string),
        typeof(EditUC),
        new FrameworkPropertyMetadata(string.Empty)
        {
            DefaultUpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged,
            BindsTwoWayByDefault = true
        });

    public string Text
    {
        get
        {
            return (string)GetValue(TextProperty);
        }

        set
        {
            SetValue(TextProperty, value);
        }
    }

    #endregion

    #region Ellisped TextBox

    public string TextValue
    {
        get
        {
            return this.textvalue;
        }

        set
        {
            if (this.textvalue == value)
            {
                return;
            }

            this.textvalue = value;
            this.Box.Text = this.CutTextToWidth(this.textvalue);
        }
    }

    private string CutTextToWidth(string value)
    {
        if (string.IsNullOrEmpty(value))
        {
            return value;
        }

        var width = this.Box.ActualWidth - 25;
        var validArea = false;
        var shortText = value;
        var lastlong = value.Length;
        var lastfit = 0;

        if (this.StringWidth(value) < width)
        {
            shortText = value;
        }
        else
        {
            while (!validArea)
            {
                if (width < this.StringWidth(shortText + "\u2026"))
                {
                    lastlong = shortText.Length;
                }
                else
                {
                    lastfit = shortText.Length;
                }

                int newLen = (lastfit + lastlong) / 2;

                if (shortText.Length != newLen)
                {
                    shortText = value.Substring(0, newLen);
                }
                else
                {
                    shortText = value.Substring(0, lastfit);
                    break;
                }

                var w = this.StringWidth(shortText + "\u2026");
                validArea = (width - 10 < w) && (w < width);
            }

            shortText += "\u2026";
        }

        return shortText;
    }

    private void BoxGotFocus(object sender, RoutedEventArgs e)
    {
        int index = this.Box.SelectionStart;
        this.Box.Text = this.textvalue;
        this.Box.SelectionStart = index;
        this.Box.TextChanged += this.BoxOnTextChanged;
    }

    private void BoxOnTextChanged(object sender, TextChangedEventArgs args)
    {
        if (sender != this.Box || args.Changes.Count <= 0 || this.UpdateTrigger != UpdateSourceTrigger.PropertyChanged)
        {
            return;
        }

        this.UpdateVM();
    }

    private void UpdateVM()
    {
        this.Text = this.Box.Text;

        ////var exp = BindingOperations.GetBindingExpression(this, TextProperty);
        ////if (exp != null)
        ////{
        ////    exp.UpdateSource();
        ////    bool he = exp.HasError;
        ////}
    }

    private void BoxLostFocus(object sender, RoutedEventArgs e)
    {
        this.Box.TextChanged -= this.BoxOnTextChanged;
        this.UpdateVM();
        this.TextValue = this.Box.Text;
        ToolTipService.SetToolTip(this.Box, this.textvalue);
    }

    private double StringWidth(string s)
    {
        if (s == " ")
        {
            s = "\u00a0";
        }

        var formattedText = new FormattedText(
                s,
                CultureInfo.CurrentUICulture,
                FlowDirection.LeftToRight,
                new Typeface(this.Box.FontFamily, this.Box.FontStyle, this.Box.FontWeight, this.Box.FontStretch),
                this.Box.FontSize,
                Brushes.Black);

        return formattedText.Width;

    }

    private void BoxOnLayoutUpdated(object sender, EventArgs e)
    {
        if (!this.Box.IsFocused)
        {
            var width = this.StringWidth(this.Box.Text);
            if (width > this.Box.ActualWidth || (width + 10 < this.Box.ActualWidth && this.Box.Text != this.TextValue))
            {
                this.Box.Text = this.CutTextToWidth(this.TextValue);
            }
        }
    }

    #endregion

    private void EditUC_OnLoaded(object sender, RoutedEventArgs e)
    {
        this.TextValue = this.Text;

        var exp = BindingOperations.GetBindingExpression(this, TextProperty);
        var parent = exp != null ? exp.ParentBinding : null;
        this.UpdateTrigger = parent != null ? parent.UpdateSourceTrigger : UpdateSourceTrigger.Default;

        if (this.UpdateTrigger == UpdateSourceTrigger.Default)
        {
            var def = TextProperty.GetMetadata(this) as FrameworkPropertyMetadata;
            if (def != null)
            {
                this.UpdateTrigger = def.DefaultUpdateSourceTrigger;
            }
        }

        this.AddHandler(Validation.ErrorEvent, new RoutedEventHandler(OnErrorEvent));
    }

    private void OnErrorEvent(object sender, RoutedEventArgs routedEventArgs)
    {
        if (sender == null)
        {
            return;
        }
    }
}

使用以下代码,我得到一个整体的红色边框 验证错误时的用户控制。

<local:EditUC Text="{Binding Text, ValidatesOnDataErrors=True}"/>

但我只想在TextBox周围添加一个错误装饰。

  1. 有没有人能解决我的问题?
  2. 我手动设置了TextBox“Box”的内容。

    1. 是否有可能将绑定TextProperty用于Box.Text?
    2. 这有助于
    3. 最后但并非最不重要的是我的viewmodel:

      public class MainVM : INotifyPropertyChanged, IDataErrorInfo
      {
          private string text;
      
          public string Text
          {
              get
              {
                  return this.text;
              }
      
              set
              {
                  if (this.text == value)
                  {
                      return;
                  }
      
                  this.text = value;
                  this.OnPropertyChanged();
              }
          }
      
          public event PropertyChangedEventHandler PropertyChanged;
      
          protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
          {
              PropertyChangedEventHandler handler = PropertyChanged;
              if (handler != null)
              {
                  handler(this, new PropertyChangedEventArgs(propertyName));
              }
          }
      
          public string this[string columnName]
          {
              get
              {
                  return this.Validate(columnName);
              }
          }
      
          public string Error
          {
              get
              {
                  return "asd";
              }
          }
      
          private string Validate(string properyName)
          {
              string msg = string.Empty;
              switch (properyName)
              {
                  case "Text":
                      msg = this.Text == "Valid" ? string.Empty : "Error";
                      break;
              }
              return msg;
          }
      }
      

      非常感谢你的帮助。

      祝你好运 基督教

0 个答案:

没有答案