WPF - 如何在与字符串列表绑定的 TextBlock 中正确显示文本

让-米洛斯特·雷蒙德

对于未来的专业项目,我需要评估 WPF 功能。

在这种情况下,我创建了一个小型测试项目,其中包含 1 个字符串树和 1 个图像网格。我希望我的图像网格显示给定目录中包含的所有 jpeg 图像,并且对于每个图像,在图像下方显示提取的文件名,没有其路径和扩展名。

实际上,我的演示根据我的目标正常工作,除了一点:我添加了每个格式化的文件名以显示在 List 集合中,我尝试将其与每个图像底部显示的 TextBlock 绑定。然而,这个格式化的名称是不可见的,而是我看到了完整的文件名,就好像 TextBlock 直接从 Image 对象中提取它一样。

我试图自己解决这个问题,遵循几个教程,对我来说没有任何效果。我无法弄清楚我做错了什么。有人可以向我解释一下吗?

这是我的 xaml 文件内容

<Window x:Class="VirtualTrees.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:VirtualTrees"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Window.Resources>
        <Style x:Key="myHeaderStyle" TargetType="{x:Type GridViewColumnHeader}">
            <Setter Property="Visibility" Value="Collapsed" />
        </Style>
        <DataTemplate x:Key="itImageCell">
            <WrapPanel>
                <Grid>
                    <Grid.RowDefinitions>
                        <RowDefinition Height="100"/>
                        <RowDefinition Height="20"/>
                    </Grid.RowDefinitions>
                    <Image Width="120" Stretch="Uniform" Source="{Binding}"/>
                    <TextBlock Grid.Row="1" Width="120" Text="{Binding}" TextTrimming="CharacterEllipsis"/>
                </Grid>
            </WrapPanel>
        </DataTemplate>
        <local:ListToStringConverter x:Key="ListToStringConverter" />
    </Window.Resources>
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="400"/>
            <ColumnDefinition Width="400*"/>
        </Grid.ColumnDefinitions>
        <ListView Margin="10" Name="lvStringTree">
            <ListView.View>
                <GridView>
                    <GridViewColumn Header="Name" Width="120" DisplayMemberBinding="{Binding Name}" />
                    <GridViewColumn Header="Age" Width="50" DisplayMemberBinding="{Binding Age}" />
                    <GridViewColumn Header="Mail" Width="150" DisplayMemberBinding="{Binding Mail}" />
                </GridView>
            </ListView.View>
        </ListView>
        <Grid x:Name="grImages" Grid.Column="1">
            <Grid.RowDefinitions>
                <RowDefinition Height="auto"/>
                <RowDefinition Height="auto"/>
            </Grid.RowDefinitions>
            <ListView Grid.Row="1" Name="lvImages" ItemsSource="{Binding Path=m_ImageList}" ItemTemplate="{StaticResource itImageCell}">
                <ListView.Background>
                    <ImageBrush/>
                </ListView.Background>
                <ListView.ItemsPanel>
                    <ItemsPanelTemplate>
                        <UniformGrid Columns="3" />
                    </ItemsPanelTemplate>
                </ListView.ItemsPanel>
            </ListView>
            <TextBlock Name="tbImageName" Text="{Binding Path=m_ImageNames, Converter={StaticResource ResourceKey=ListToStringConverter}}" DataContext="{StaticResource itImageCell}" />
        </Grid>
    </Grid>
</Window>

还有我的 C# 代码

using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using System.Windows;
using System.Windows.Data;
using System.Windows.Media;
using System.Windows.Media.Imaging;

namespace VirtualTrees
{
    [ValueConversion(typeof(List<string>), typeof(string))]
    public class ListToStringConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            if (targetType != typeof(string))
                throw new InvalidOperationException("The target must be a string");

            return string.Join(", ", ((List<string>)value).ToArray());
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }

    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public class User
        {
            public string Name { get; set; }
            public int    Age  { get; set; }
            public string Mail { get; set; }
        }

        List<ImageSource> m_ImageList    = new List<ImageSource>();
        List<string>      m_ImageNames   = new List<string>();
        string            m_RegexPattern = @"\\([\w ]+).(?:jpg|png)$";

        public MainWindow()
        {
            InitializeComponent();

            PopulateStringTree();
            PopulateImageGrid();
        }

        public void PopulateStringTree()
        {
            List<User> vstItems = new List<User>();

            for (ulong i = 0; i < 100000; ++i)
            {
                vstItems.Add(new User() { Name = "John Doe",  Age = 42, Mail = "[email protected]" });
                vstItems.Add(new User() { Name = "Jane Doe",  Age = 39, Mail = "[email protected]" });
                vstItems.Add(new User() { Name = "Sammy Doe", Age = 7,  Mail = "[email protected]" });
            }

            lvStringTree.ItemsSource = vstItems;
        }

        public void PopulateImageGrid()
        {
            // get jpeg image file list from target dir
            string       moviePosterPath = @"W:\Labo\WPF\VirtualTrees\VirtualTrees\Resources\Images";
            List<string> fileNames       = new List<string>(System.IO.Directory.EnumerateFiles(moviePosterPath, "*.jpg"));

            // iterate through files
            foreach (string fileName in fileNames)
            {
                // load image and add it to image list
                m_ImageList.Add(new BitmapImage(new Uri(fileName)));
                Console.WriteLine("filename " + fileName);

                // extract image file name and add it to name list
                Match regexMatch = Regex.Match(fileName.Trim(), m_RegexPattern);
                m_ImageNames.Add(regexMatch.Groups[1].Value);
                Console.WriteLine("Movie Name: " + regexMatch.Groups[1].Value);
            }

            // bind data to image grid
            lvImages.ItemsSource = m_ImageList;
        }
    }
}
仿生代码

DataTemplate是错误的根源。您必须检查TextBlock. 您绑定到DataContextwhich 是 a BitmapSourceTextBlock隐式调用BitmapSource.ToString()要获得类型的字符串表示。BitmapSourceToString()覆盖以返回完整的文件路径。要解决此问题,您需要使用IValueConverter.

修改DataTemplateTextBlock结合现在使用转换器将转换BitmapSource到文件名:

<DataTemplate x:Key="itImageCell">
  <WrapPanel>
    <Grid>
      <Grid.RowDefinitions>
        <RowDefinition Height="100" />
        <RowDefinition Height="20" />
      </Grid.RowDefinitions>
      <Image Width="120"
             Stretch="Uniform"
             Source="{Binding}" />
      <TextBlock Grid.Row="1"
                 Width="120"
                 Text="{Binding ., Converter={StaticResource BitmapSourceToFilenameConverter}}"
                 TextTrimming="CharacterEllipsis" />
    </Grid>
  </WrapPanel>
</DataTemplate>

用于TextBlock绑定的 IValueConverter将 转换BitmapSource为文件名:

[ValueConversion(typeof(BitmapSource), typeof(string))]
public class  BitmapSourceToFilenameConverter : IValueConverter
{
  public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
  {
    if (value is BitmapSource bitmapSource)
      return bitmapSource.UriSource.AbsolutePath;

    return Binding.DoNothing;
  }

  public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
  {
    throw new NotImplementedException();
  }
}

我在您的代码中意识到的一个小错误:

您首先在 上设置绑定ListView

<ListView Name="lvImages" ItemsSource="{Binding Path=m_ImageList}" />

然后你覆盖(删除)它

// bind data to image grid
lvImages.ItemsSource = m_ImageList;

这不是绑定(评论不正确)。

你应该做m_ImageList一个ObservableCollection<ImageSource>而不是List. 添加、移动或删除项目时ObservableCollection将自动更新ListView然后从你的MainWindow班级中删除这一行lvImages.ItemsSource = m_ImageList;

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

TextBlock 的 WPF 属性绑定

如何在WPF中通过DynamicResource破坏TextBlock的文本

在WPF TextBlock中显示XAML格式的文本

WPF MVVM将TextBlock的文本绑定到ObservableCollection成员

WPF DataTemplate和与TextBlock绑定

WPF:Textblock作为ComboBox中的项目:如何将Textblock的文本垂直居中?

WPF。如何获取TextBlock的DrawingContext?

WPF字形不像TextBlock那样正确呈现文本

单击wpf中的textBlock时如何更改textblock背景?

WPF TextBlock中的文本垂直对齐

从datagrid wpf中的textblock复制文本内容

使用 wpf TextBlock 控件显示错误消息

WPF 以编程方式绑定 TextBlock 运行

WPF TextBlock绑定不起作用

如何获取TextBlock的文本(TextBlock是Button的内容)

即使在绑定后,TextBlock也不会显示文本

如何扩展TextBlock以显示轮廓文本?

WPF C#如何使用Text属性在TextBlock中设置格式化文本

WPF如何像在ComboBox中一样在DataGrid的TextBlock中显示关系数据

如何将多个值绑定到单个WPF TextBlock?

WPF - 无法从字符串解析 TextBlock 元素

WPF; 将简单字符串转换为我的 TextBlock 文本失败并且由于找不到资源命名

TextBlock:文本和StringFormat的绑定

将字符串绑定到TextBlock WPF-我在做什么错?

WPF。如果 TextBlock 中的文本与 ComboBox 中的文本相同,则更改背景色 TextBlock

如何在WPF TextBlock中更改TextDecoration颜色?

WPF:减少/删除TextBlock中文本上方的空白区域

WPF 根据属性将文本添加到 TextBlock

WPF C#-从TextBlock获取内联格式的粗体文本