65.9K
CodeProject 正在变化。 阅读更多。
Home

WPF PathTrimmingTextBlock

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.56/5 (5投票s)

2012年9月28日

CPOL

2分钟阅读

viewsIcon

47104

downloadIcon

719

如何在 GridViewColumn 的 TextBlock 中显示文件路径,并在中心添加省略号。

介绍 

我经常需要在 ListView/GridView 中显示文件路径,但如果列的尺寸不足,文件部分(以及一些目录)会被截断。使用 TextBlock.TextTrimming 并没有帮助,它只会简单地在字符串末尾添加省略号。那么,我们如何有效地在 GridViewColumn 中显示长文件路径呢?

背景 

我最初的想法是,这应该是一个简单的 Converter 的工作。只需传入 PathTextBlock 本身,使用 FormattedText 类执行一些操作,然后完成!但事实证明,这并不像想象的那么简单。

问题在于 TextBlock.ActualWidth 不是一个 DependencyProperty,因此,当 TextBlockSize 改变时,Converter 不会重新计算。好吧...放弃这个想法。

然后我想,好吧...我直接从 TextBlock 派生,创建一个名为 PathDependencyProperty,挂钩 SizeChanged 事件,然后完成!

好吧...它几乎奏效了。

GridViewColumn 的 Width 增加时,SizeChanged 事件会被调用,但当它减小时,不会被调用。嗯,什么?

因此,在 MSDN 上得到 nguyentrucdn 的帮助 (http://social.msdn.microsoft.com/Forums/en/wpf/thread/8a00e43d-7091-49e7-b57c-86fc0951c4d0),我发现 TextBlockGridViewColumn 中,当其 Width 减小时,实际上不会发布 SizeChanged 事件...但它的 Container 会 Smile

因此...我想,好吧,我将在 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 中使用它,它在任何地方都可以工作 Smile | <img src=   

历史 

  • 2012/9/28 - 发布文章。
© . All rights reserved.