是否可以在 ListView 中显示带有文本 + 图标的行?

Posted

技术标签:

【中文标题】是否可以在 ListView 中显示带有文本 + 图标的行?【英文标题】:Is it possible to display lines with text + icons in a ListView? 【发布时间】:2021-04-16 15:24:11 【问题描述】:

我想在ListView 中显示带有通知的不同行。

我尝试了StackPanel,但我不确定我是否走在正确的道路上。

<StackPanel Margin="5" Orientation="Horizontal" Background="DarkBlue" Height="28">
   <Image Source="../Resources/crown.png" Height="18"/>
   <TextBlock Text="Hello, I am a text block!" Margin="3 0 0 0"/>
</StackPanel>

它并不总是相同的行,它也可以只是文本。

有没有人知道我可以如何实现这样的东西(可能也在代码隐藏中)?

【问题讨论】:

数据的数据结构是什么(日期/时间、文本、图标、一般的内容行,...)?如果我们不知道您要显示的数据,则很难猜测什么是合适的解决方案。 从 lineviewmodel 列表的角度考虑。 lineviewmodel 有一个属性,它是一个对象列表。我会让每一行都成为项目控件。使用一个项目面板,它是一个水平堆栈面板。定义两个数据模板。一个是文本块。再来一张图。相应的视图模型。在一个中公开文本,在另一个中公开一个 url。这些是上面的对象。您将您拥有的任何数据逐行翻译成文本......图片来源......文本。等等。 @thatguy 目前还没有数据结构。我想在一行上动态显示文本和图像。在这里我只是不知道该怎么做。 【参考方案1】:

您没有任何数据结构,所以让我们在下面创建它们。这种方法并不完整,只有太多的选择来实现这个场景。您可以随时调整、改进和扩展示例以满足您的要求。

我将使用ItemsControl,因为这似乎是一个只读通知控件。如果您希望项目可以选择,您可以轻松地将其替换为 ListBoxListView

这个想法很简单,有一个Line 模型包含所有要显示的信息,它是DateTime 类型的属性,用于时间戳LineFragment 的可枚举,它代表所有不同的数据类型显示在一行中。

public class Line

   public Line(DateTime dateTime, IEnumerable<LineFragment> fragments)
   
      DateTime = dateTime;
      Fragments = fragments;
   

   public DateTime DateTime  get; 

   public IEnumerable<LineFragment> Fragments  get; 

LineFragment 是许多派生类型的基类型,它们在一行中表示文本和其他数据。

public abstract class LineFragment


一个简单的TextFragment 表示一行中的纯文本。

public class TextFragment : LineFragment

   public TextFragment(string text)
   
      Text = text;
   

   public string Text  get; 

代表玩家的玩家片段,例如Knochenbrecher Messerkämpferin.

public class PlayerFragment : LineFragment

   public PlayerFragment(string name)
   
      Name = name;
   

   public string Name  get; 

代表头骨和牙冠的玩家状态片段。

public class PlayerStatFragment : LineFragment

   public PlayerStatFragment(int skulls, int crowns)
   
      Skulls = skulls;
      Crowns = crowns;
   

   public int Skulls  get; 

   public int Crowns  get; 


一个属性统计片段,它具有代表 GloryExperienceSilver 等属性的衍生物。

public abstract class AttributeStatFragment : LineFragment

   protected AttributeStatFragment(string name, AttributeStatOperator statOperator, int value)
   
      Name = name; 
      Operator = statOperator;
      Value = value;
   

   public string Name  get; 

   public AttributeStatOperator Operator  get; 

   public int Value  get; 


public class GloryStatFragment : AttributeStatFragment

   public GloryStatFragment(string name, AttributeStatOperator statOperator, int value) : base(name, statOperator, value)
   
   


public class ExperienceStatFragment : AttributeStatFragment

   public ExperienceStatFragment(string name, AttributeStatOperator statOperator, int value) : base(name, statOperator, value)
   
   


public class SilverStatFragment : AttributeStatFragment

   public SilverStatFragment(string name, AttributeStatOperator statOperator, int value) : base(name, statOperator, value)
   
   


public enum AttributeStatOperator

   Plus,
   Minus

代表税收的税收片段和衍生品,如公会税

public abstract class TaxFragment : LineFragment

   public TaxFragment(string name, int value)
   
      Name = name;
      Value = value;
   

   public string Name  get; 

   public int Value  get; 


public class GuildTaxFragment : TaxFragment

   public GuildTaxFragment(string name, int tax) : base(name, tax)
   
   

现在您可以在视图模型或代码隐藏中公开Lines 的集合。如果您在运行时添加项目,则必须使用ObervableCollection&lt;T&gt;,否则添加、删除或插入项目等更改将不会反映在用户界面中。

public ObservableCollection<Line> Lines  get; 

不要忘记初始化集合属性。之后,您可以像这样添加您的项目:

Lines.Add(new Line(DateTime.Now, new List<LineFragment>

   new TextFragment("Du hast"),
   new GloryStatFragment(GloryStatName, AttributeStatOperator.Plus, 820),
   new PlayerStatFragment(390, 273),
   new TextFragment("erhalten")
));

Lines.Add(new Line(DateTime.Now, new List<LineFragment>

   new TextFragment("Du erhältst"),
   new ExperienceStatFragment(ExperienceStatName, AttributeStatOperator.Plus, 42)
));

Lines.Add(new Line(DateTime.Now, new List<LineFragment>

   new PlayerFragment("Knochenbrecher Messerkämpferin"),
   new TextFragment("hat"),
   new TextFragment("für dich regeneriert")
));

Lines.Add(new Line(DateTime.Now, new List<LineFragment>

   new TextFragment("Du hast"),
   new SilverStatFragment(SilverStatName, AttributeStatOperator.Plus, 184),
   new PlayerStatFragment(75, 61),
   new TextFragment("erhalten")
));

Lines.Add(new Line(DateTime.Now, new List<LineFragment>

   new TextFragment("Du hast"),
   new GuildTaxFragment(GuildTaxName, 46),
   new TextFragment("bezahlt")
));

为了显示片段,我们必须在 XAML 中为我们的项目创建DataTemplates。请注意,出于演示目的,我创建了位于 Resources 文件夹中的虚拟图像。

<Style x:Key="LineFragmentImageStyle"
       TargetType="x:Type Image">
   <Setter Property="Width"
           Value="10" />
   <Setter Property="Height"
           Value="10" />
   <Setter Property="Margin"
           Value="2" />
</Style>

<Style x:Key="OperatorTextBlockStyle"
       TargetType="x:Type TextBlock">
   <Setter Property="Text"
           Value="+ " />
   <Style.Triggers>
      <DataTrigger Binding="Binding"
                   Value="x:Static local:AttributeStatOperator.Minus">
         <Setter Property="Text"
                 Value="- " />
      </DataTrigger>
   </Style.Triggers>
</Style>

<DataTemplate DataType="x:Type local:TextFragment">
   <TextBlock Text="Binding Text, StringFormat='0 '" />
</DataTemplate>
<DataTemplate DataType="x:Type local:PlayerFragment">
   <TextBlock Text="Binding Name, StringFormat='0 '" />
</DataTemplate>

<DataTemplate DataType="x:Type local:PlayerStatFragment">
   <StackPanel Orientation="Horizontal">
      <TextBlock Text="( " />
      <Image Source="Resources/skull.png"
             Style="StaticResource LineFragmentImageStyle" />
      <TextBlock Text="Binding Skulls, StringFormat=' 0 '" />
      <Image Source="Resources/crown.png"
             Style="StaticResource LineFragmentImageStyle" />
      <TextBlock Text="Binding Crowns, StringFormat=' 0 '" />
      <TextBlock Text=" ) " />
   </StackPanel>
</DataTemplate>

<DataTemplate DataType="x:Type local:ExperienceStatFragment">
   <StackPanel Orientation="Horizontal">
      <TextBlock DataContext="Binding Operator"
                 Style="StaticResource OperatorTextBlockStyle" />
      <Image Source="Resources/key.png"
             Style="StaticResource LineFragmentImageStyle" />
      <TextBlock Text="Binding Value, StringFormat=' 0 '" />
      <TextBlock Text="Binding Name, StringFormat='0 '" />
   </StackPanel>
</DataTemplate>

<DataTemplate DataType="x:Type local:GloryStatFragment">
   <StackPanel Orientation="Horizontal">
      <TextBlock DataContext="Binding Operator"
                 Style="StaticResource OperatorTextBlockStyle" />
      <Image Source="Resources/badge.png"
             Style="StaticResource LineFragmentImageStyle" />
      <TextBlock Text="Binding Value, StringFormat=' 0 '" />
      <TextBlock Text="Binding Name, StringFormat='0 '" />
   </StackPanel>
</DataTemplate>

<DataTemplate DataType="x:Type local:SilverStatFragment">
   <StackPanel Orientation="Horizontal">
      <TextBlock DataContext="Binding Operator"
                 Style="StaticResource OperatorTextBlockStyle" />
      <Image Source="Resources/silver.png"
             Style="StaticResource LineFragmentImageStyle" />
      <TextBlock Text="Binding Value, StringFormat=' 0 '" />
      <TextBlock Text="Binding Name, StringFormat='0 '" />
   </StackPanel>
</DataTemplate>

<DataTemplate DataType="x:Type local:GuildTaxFragment">
   <StackPanel Orientation="Horizontal">
      <Image Source="Resources/silver.png"
             Style="StaticResource LineFragmentImageStyle" />
      <TextBlock Text="Binding Value, StringFormat=' 0 '" />
      <TextBlock Text="Binding Name, StringFormat='0 '" />
      <TextBlock Text="(" />
      <Image Source="Resources/armor.png"
             Style="StaticResource LineFragmentImageStyle" />
      <TextBlock Text=")" />
   </StackPanel>
</DataTemplate>

然后我们为Line 本身创建一个数据模板。每行显示一个带有TextBlock 的时间戳,旁边是一个ItemsControl,它使用上面定义的数据模板水平显示所有片段。 WrapPanel 超出视口会自动换行。

<DataTemplate DataType="x:Type local:Line">
   <Grid>
      <Grid.ColumnDefinitions>
         <ColumnDefinition Width="Auto" />
         <ColumnDefinition />
      </Grid.ColumnDefinitions>
      <TextBlock Grid.Column="0"
                 Margin="3"
                 Text="Binding DateTime, StringFormat=[hh:mm:ss]" />
      <ItemsControl Grid.Column="1"
                    Margin="3"
                    ItemsSource="Binding Fragments">
         <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
               <WrapPanel Orientation="Horizontal" />
            </ItemsPanelTemplate>
         </ItemsControl.ItemsPanel>
      </ItemsControl>
   </Grid>
</DataTemplate>

最后但同样重要的是,要显示Lines 集合,我们必须将ItemsControl 添加到使用Line 数据模板来显示行的用户界面XAML。

<ScrollViewer>
   <ItemsControl ItemsSource="Binding Lines" Style="StaticResource LinesItemsControlStyle" />
</ScrollViewer>

就是这样。您可以轻松地将其与其他项目一起扩展。看起来是这样的:

【讨论】:

感谢您的详细解答。这对我帮助很大。【参考方案2】:

如果您希望图像实际上包含在文本中(如表情符号),那么您将不得不做一些工作。这听起来像是我真正想要一个用户控件的少数几次之一,其重点是扫描文本以查找表情符号值并动态构建数据模板。

请记住,您可以在 XAML 中执行的任何操作都可以在代码中执行,因此我正在考虑的代码将遵循以下总体思路:

    扫描文本以获取表情符号值并为数据元素创建值列表。 创建一个 DockPanel。 对于 List 中的每个元素,添加 TextBlock 或 Image(基于值)。 将 this.Content 设置为 DockPanel。

我认为这样的东西实际上是您正在寻找的东西,但如果您只想要一个图像,那么 ValueConverter 建议会起作用。

【讨论】:

跟这个问题有什么关系? 她想将图像添加到她的测试中。这就是我解释的方法

以上是关于是否可以在 ListView 中显示带有文本 + 图标的行?的主要内容,如果未能解决你的问题,请参考以下文章

ListView窗体的增删改查

如何在带有文本的列表视图中显示从 API 下载的图像

颤动 - 是否可以在同一屏幕上沿ListView显示小部件?

是否可以在带有删除线效果的控制台中显示文本?

搜索视图和可过滤:显示带有搜索文本的栏

在listview的edittext中输入的所有数字的总和