Ktouth Brand. on Web

け〜くんこと K.Ktouth のだらだらした日常と突発的に作るプログラムや読み物とかの雑多サイト



[2012年02月27日]

パス文字列の省略を行うTextBlock

2012年02月27日 21:41更新 筆者:K.Ktouth

久方ぶりに C# / WPF をいじりまわしてました(ぉぃ
WinForms やネイティブなRAD開発環境にはパス文字列の省略機能が普通にありますが、WPFのテキストブロックには対応する機能がありません。
無いと困るなーと思ったので、ちょっと調べて適当に実装。かなり強引なところがありますが、何かあったらまた実装しなおすって事で。

(以下、PathTextBlock コントロールの実装ソース)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Controls;
using System.Windows;
using System.Windows.Media;
using System.Globalization;
using System.Runtime.InteropServices;

namespace KtouthBrand.WPF.Controls
{
  public class PathTextBlock : TextBlock
  {
    [DllImport("shlwapi.dll", CharSet = CharSet.Auto)]
    private static extern bool PathCompactPathEx([Out] StringBuilder pszOut, string szPath, int cchMax, int dwFlags);

    private static string TruncatePath(string path, int length)
    {
      StringBuilder sb = new StringBuilder(length + 1);
      PathCompactPathEx(sb, path, length + 1, 0);
      return sb.ToString();
    }

    public string PathText
    {
      get { return (string)GetValue(PathTextProperty); }
      set { SetValue(PathTextProperty, value); }
    }

    public static readonly DependencyProperty PathTextProperty =
      DependencyProperty.Register("PathText", typeof(string), typeof(PathTextBlock), new UIPropertyMetadata(null, (dp, e) =>
      {
        PathTextBlock textBlock = dp as PathTextBlock;
        textBlock.ResizePathText = true;
        textBlock.ToolTip = e.NewValue;
        textBlock.InvalidateVisual();
      }));

    private bool ResizePathText = true;
    protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo)
    {
      base.OnRenderSizeChanged(sizeInfo);
      if ((ResizePathText || sizeInfo.WidthChanged) && (sizeInfo.NewSize.Width > 0.0))
      {
        var text = PathText;
        for (var len = text.Length; len > 0; len--)
        {
          text = TruncatePath(PathText, len);
          var ft = new FormattedText(text, CultureInfo.CurrentCulture, FlowDirection.LeftToRight,
                        new Typeface(this.FontFamily.Source), this.FontSize, this.Foreground);
          if (ft.WidthIncludingTrailingWhitespace <= sizeInfo.NewSize.Width) break;
        }
        if(String.IsNullOrEmpty(text)) { text = "???"; }
        this.Text = text;
        ResizePathText = false;
      }
    }
    private double MeasureString(string text)
    {
      var ft = new FormattedText(text, CultureInfo.CurrentCulture, FlowDirection.LeftToRight,
                    new Typeface(this.FontFamily.Source), this.FontSize, this.Foreground);
      return ft.WidthIncludingTrailingWhitespace;
    }
  }
}

本日のリンク元
その他のリンク元
検索