/// <summary>
        /// Extend the string constructor with a string.Format like syntax.
        /// </summary>
        /// <param name="args"></param>
        /// <param name="placing"></param>
        /// <returns></returns>
        private static string FormatWith(EllipsisPlacement placing,
                                         params object[] args)
        {
            string formatString;

            switch (placing)
            {
            case EllipsisPlacement.None:
                formatString = "{0}{1}";
                break;

            case EllipsisPlacement.Left:
                formatString = "...{0}{1}";
                break;

            case EllipsisPlacement.Center:
                formatString = "{0}...{1}";
                break;

            case EllipsisPlacement.Right:
                formatString = "{0}{1}...";
                break;

            default:
                throw new ArgumentOutOfRangeException(placing.ToString());
            }

            return(string.Format(CultureInfo.InvariantCulture, formatString, args));
        }
        // Sets Text to a substring of LongText based on _placement and _curLen.
        private void CalcText()
        {
            if (LongText == null)
            {
                switch (EllipsisPlacement)
                {
                case EllipsisPlacement.Left:
                case EllipsisPlacement.Center:
                case EllipsisPlacement.Right:
                case EllipsisPlacement.Path:
                    SetText(LongText);
                    break;
                }

                return;
            }

            switch (EllipsisPlacement)
            {
            case EllipsisPlacement.Right:
                SetText(LongText.Substring(0, _curLen) + "\u2026");
                break;

            case EllipsisPlacement.Center:
                int firstLen  = _curLen / 2;
                int secondLen = _curLen - firstLen;
                SetText(LongText.Substring(0, firstLen) + "\u2026" + LongText.Substring(LongText.Length - secondLen));
                break;

            case EllipsisPlacement.Left:
                int start = LongText.Length - _curLen;
                SetText("\u2026" + LongText.Substring(start));
                break;

            case EllipsisPlacement.Path:
                var sb = new StringBuilder(_curLen + 1);
                PathCompactPathEx(sb, LongText, _curLen, 0);
                SetText(sb.ToString());
                break;

            default:
                throw new Exception("Unexpected switch value: " + EllipsisPlacement.ToString());
            }
        }
        /// <summary>
        /// Compute the text to display (with ellipsis) that fits the ActualWidth of the container
        /// </summary>
        /// <param name="inputString">Input string to measure whether it fits into container width or not.</param>
        /// <param name="constraint">ActualWidth restriction by container element (eg.: Grid)</param>
        /// <param name="placement"></param>
        /// <param name="ctrl"></param>
        /// <returns></returns>
        private static Tuple <string, Size> GetTrimmedPath(string inputString,
                                                           Size constraint,
                                                           EllipsisPlacement placement,
                                                           Control ctrl)
        {
            Size   size      = new Size();
            string filename  = string.Empty;
            string directory = string.Empty;

            if (constraint.Width != double.PositiveInfinity)
            {
                size.Width = constraint.Width;
            }

            if (constraint.Height != double.PositiveInfinity)
            {
                size.Height = constraint.Height;
            }

            switch (placement)
            {
            // We don't want no ellipses to be shown for a string shortener
            case EllipsisPlacement.None:
                size = MeasureString(inputString, ctrl);
                return(new Tuple <string, Size>(inputString, size));

            // Try to show a nice ellipses somewhere in the middle of the string
            case EllipsisPlacement.Center:
                try
                {
                    if (string.IsNullOrEmpty(inputString) == false)
                    {
                        if (inputString.Contains(string.Empty + System.IO.Path.DirectorySeparatorChar))
                        {
                            // Lets try to display the file name with priority
                            filename  = System.IO.Path.GetFileName(inputString);
                            directory = System.IO.Path.GetDirectoryName(inputString);
                        }
                        else
                        {
                            // Cut this right in the middle since it does not seem to hold path info
                            int len      = inputString.Length;
                            int firstLen = inputString.Length / 2;
                            filename = inputString.Substring(0, firstLen);

                            if (inputString.Length >= (firstLen + 1))
                            {
                                directory = inputString.Substring(firstLen);
                            }
                        }
                    }
                    else
                    {
                        size = MeasureString(string.Empty, ctrl);
                        return(new Tuple <string, Size>(inputString, size));
                    }
                }
                catch (Exception)
                {
                    directory = inputString;
                    filename  = string.Empty;
                }
                break;

            case EllipsisPlacement.Left:
                directory = inputString;
                filename  = string.Empty;
                break;

            case EllipsisPlacement.Right:
                directory = string.Empty;
                filename  = inputString;
                break;

            default:
                throw new ArgumentOutOfRangeException(placement.ToString());
            }

            double fudgeValue   = 3.0;
            bool   widthOK      = false;
            int    indexString  = 0;
            string path         = inputString;
            bool   changedWidth = false;

            if (placement == EllipsisPlacement.Left)
            {
                indexString = 1;
            }

            do
            {
                path = FormatWith(placement, directory, filename);
                size = MeasureString(path, ctrl);

                widthOK = (size.Width + fudgeValue) < constraint.Width;

                if (widthOK == false)
                {
                    if (directory.Length == 0)
                    {
                        if (filename.Length > 0)
                        {
                            changedWidth = true;
                            filename     = filename.Substring(indexString, filename.Length - 1);
                        }
                        else
                        {
                            size = MeasureString(string.Empty, ctrl);
                            return(new Tuple <string, Size>(inputString, size));
                        }
                    }
                    else
                    {
                        changedWidth = true;
                        directory    = directory.Substring(indexString, directory.Length - 1);
                    }
                }
            }while (widthOK == false);

            size.Width += fudgeValue;

            if (changedWidth == false)
            {
                return(new Tuple <string, Size>(inputString, size));
            }

            return(new Tuple <string, Size>(path, size));
        }
        /// <summary>Initializes a new instance of the <see cref="TextBoxWithEllipsis"/> class.</summary>
        public TextBoxWithEllipsis()
        {
            // Initialize inherited stuff as desired.
            this.IsReadOnlyCaretVisible = true;

            // Initialize stuff added by this class
            this.IsEllipsisEnabled = true;
            this.UseLongTextForToolTip = true;
            this.FudgePix = 3.0;
            this.placement = EllipsisPlacement.Right;
            this.internalEnabled = true;

            this.LayoutUpdated += this.TextBoxWithEllipsisLayoutUpdated;
            this.SizeChanged += this.TextBoxWithEllipsisSizeChanged;
        }