WPF PathTrimmingTextBlock






4.56/5 (5投票s)
如何在 GridViewColumn 的 TextBlock 中显示文件路径,并在中心添加省略号。
介绍
我经常需要在 ListView/GridView 中显示文件路径,但如果列的尺寸不足,文件部分(以及一些目录)会被截断。使用 TextBlock.TextTrimming
并没有帮助,它只会简单地在字符串末尾添加省略号。那么,我们如何有效地在 GridViewColumn
中显示长文件路径呢?
背景
我最初的想法是,这应该是一个简单的 Converter 的工作。只需传入 Path
和 TextBlock
本身,使用 FormattedText
类执行一些操作,然后完成!但事实证明,这并不像想象的那么简单。
问题在于 TextBlock.ActualWidth
不是一个 DependencyProperty
,因此,当 TextBlock
的 Size
改变时,Converter 不会重新计算。好吧...放弃这个想法。
然后我想,好吧...我直接从 TextBlock
派生,创建一个名为 Path
的 DependencyProperty
,挂钩 SizeChanged
事件,然后完成!
好吧...它几乎奏效了。
当 GridViewColumn
的 Width 增加时,SizeChanged
事件会被调用,但当它减小时,不会被调用。嗯,什么?
因此,在 MSDN 上得到 nguyentrucdn 的帮助 (http://social.msdn.microsoft.com/Forums/en/wpf/thread/8a00e43d-7091-49e7-b57c-86fc0951c4d0),我发现 TextBlock
在 GridViewColumn
中,当其 Width
减小时,实际上不会发布 SizeChanged
事件...但它的 Container 会
因此...我想,好吧,我将在 XAML 中用 Grid
包装 TextBlock
,并在 TextBlock
的 Loaded 处理程序中获取父容器,并挂钩它的 SizeChanged
事件,并将它的 ActualWidth
传入到修剪算法中,然后完成!成功了!
使用代码
使用非常简单,但有一个注意事项。你必须将 PathTrimmingTextBlock
放在 Grid
或其他 Container 中。否则,它会抛出一个 InvalidOperationException
。否则,它只是...
<ListView ItemsSource="{Binding }" HorizontalContentAlignment="Stretch">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"></Setter>
</Style>
</ListView.ItemContainerStyle>
<ListView.View>
<GridView>
<GridViewColumn Header="Filename">
<GridViewColumn.CellTemplate>
<DataTemplate>
<Grid>
<WpfApplication307:PathTrimmingTextBlock FontSize="40"
Path="{Binding}"></WpfApplication307:PathTrimmingTextBlock>
</Grid>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
请记住,你必须引用正确的 xmlns,而不是 WpfApplication307。
省略号算法很简单。传入所需的宽度和完整路径,将目录与文件名分开,删除目录的最后一个字符,直到 FormattedText
告诉你它的宽度小于目录 + "..." + 文件名,并将 Text
设置为该值。我的实现如下...
string GetTrimmedPath(double width)
{
string filename = System.IO.Path.GetFileName(Path);
string directory = System.IO.Path.GetDirectoryName(Path);
FormattedText formatted;
bool widthOK = false;
bool changedWidth = false;
do
{
formatted = new FormattedText(
"{0}...\\{1}".FormatWith(directory, filename),
CultureInfo.CurrentCulture,
FlowDirection.LeftToRight,
FontFamily.GetTypefaces().First(),
FontSize,
Foreground
);
widthOK = formatted.Width < width;
if (!widthOK)
{
changedWidth = true;
directory = directory.Substring(0, directory.Length - 1);
if (directory.Length == 0) return "...\\" + filename;
}
} while (!widthOK);
if (!changedWidth)
{
return Path;
}
return "{0}...{1}".FormatWith(directory, filename);
}
兴趣点
一个 TextBlock
在其 Width 减小时不会发布 SizeChanged
事件...至少如果它是 GridViewColumn
的一部分!
我还应该指出,你不一定需要在 GridViewColumn
中使用它,它在任何地方都可以工作
历史
- 2012/9/28 - 发布文章。