【问题标题】:How to add different ListBox items WPF如何添加不同的 ListBox 项目 WPF
【发布时间】:2015-11-07 20:07:52
【问题描述】:

我正在实现如下图所示的聊天应用程序:

我首先创建了一个 ListBox 并设置了一个 ListBox.ItemTemplate,但我不知道如何控制 ListBox 以将布局添加为接收或发送的消息(就像 Whatsapp 一样)。

这是我的代码:

<ListBox Name="ChatListBox" ScrollViewer.VerticalScrollBarVisibility="Auto" ScrollViewer.HorizontalScrollBarVisibility="Disabled" Background="#00FFFFFF" BorderBrush="{x:Null}" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch">
                            <ListBox.ItemsPanel>
                                <ItemsPanelTemplate>
                                    <StackPanel Background="#00FFFFFF"/>
                                </ItemsPanelTemplate>
                            </ListBox.ItemsPanel>
                            <ListBox.ItemContainerStyle>
                                <Style TargetType="{x:Type ListBoxItem}">
                                    <Setter Property="Focusable" Value="False"/>
                                </Style>
                            </ListBox.ItemContainerStyle>
                            <ListBox.ItemTemplate>
                                <DataTemplate>
                                    <Grid>
                                        <!--If the user sends a msg-->
                                        <Grid.ColumnDefinitions>
                                            <ColumnDefinition Width="9*"/>
                                            <ColumnDefinition Width="*"/>
                                        </Grid.ColumnDefinitions>
                                        <Border Grid.Column="0" Margin="0" BorderThickness="1" BorderBrush="#9f9f9f" Background="#c4df9b" CornerRadius="10">
                                            <TextBlock Name="MsgText" Background="#c4df9b" Foreground="Black" TextAlignment="Center" TextWrapping="Wrap" Margin="5" Text="{Binding text}" FontSize="14"/>
                                        </Border>
                                        <Image Grid.Column="1" Source="Images/user.png" Margin="5" Height="{Binding ElementName=MsgText, Path=ActualHeight}"/>
                                        <!--
                                        If the user receives a msg
                                        <Grid.ColumnDefinitions>
                                            <ColumnDefinition Width="*"/>
                                            <ColumnDefinition Width="9*"/>
                                        </Grid.ColumnDefinitions>
                                        <Image Grid.Column="0" Source="Images/user.png" Margin="5" Height="{Binding ElementName=MsgText, Path=ActualHeight}"/>
                                        <Border Grid.Column="1" Margin="0" BorderThickness="1" BorderBrush="#9f9f9f" Background="#c4df9b" CornerRadius="10">
                                            <TextBlock Name="MsgText" Background="#c4df9b" Foreground="Black" TextAlignment="Center" TextWrapping="Wrap" Margin="5" Text="{Binding text}" FontSize="14"/>
                                        </Border>-->
                                    </Grid>
                                </DataTemplate>
                            </ListBox.ItemTemplate>
                        </ListBox>

这是我的 C# 代码:

List<ChatItem> chatItem = new List<ChatItem>();
chatItem.Add(new ChatItem() { text = "Hello...", isFromUser = false });
        chatItem.Add(new ChatItem() { text = "hi!", isFromUser = true });
        chatItem.Add(new ChatItem() { text = "this is a test, this is a test, this is a test, this is a test, this is a test, this is a test, this is a test, this is a test, this is a test, this is a test", isFromUser = false });
        ChatListBox.ItemsSource = chatItem;

ListBox 是这样重绘的:

有没有什么方法可以使用 WPF 在 ListBox 中添加 IF 语句?或者我如何控制要添加的 ListBox.ItemTemplate。

【问题讨论】:

  • 为什么不使用数据模板选择器并根据您的消息属性选择正确的模板?
  • @BenjaminBaumann 你能给我一个dataTemplate选择器的例子吗?

标签: c# wpf listbox listboxitem


【解决方案1】:

如果您的消息属于同一类,您可以使用 itemsTemplateSelector,如 http://codingbandit.com/blog/?p=8

如果有不同的类,您应该只使用 Conditional List itemtemplate or datatemplate in WPF 中的 datatemplate 数据类型属性

【讨论】:

    【解决方案2】:

    另一种选择是简单地使用数据触发器:

    <DataTemplate x:Key="ToTemplate">
        ... etc ...
    </DataTemplate>
    
    <DataTemplate x:Key="FromTemplate">
        ... etc ...
    </DataTemplate>
    
    <Style TargetType="ListBoxItem">
        <Style.Triggers>
            <DataTrigger Binding="{Binding isFromUser}" Value="false">
                <Setter Property="Template" Value="{StaticResource ToTemplate}" />
            </DataTrigger>
            <DataTrigger Binding="{Binding isFromUser}" Value="true">
                <Setter Property="Template" Value="{StaticResource FromTemplate}" />
            </DataTrigger>
        </Style.Triggers>
    </Style>
    

    【讨论】:

      【解决方案3】:

      也许这会给你一个想法

      Xaml

      <Window x:Class="Q1.MainWindow"
          xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
          xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
          xmlns:local="clr-namespace:Q1"
          Title="MainWindow" Height="350" Width="525">
      <Window.Resources>
          <DataTemplate x:Key="intDataTemplate">
              <TextBox Text="{Binding Path=.}" Width="80"/>
          </DataTemplate>
          <DataTemplate x:Key="stringDataTemplate">
              <TextBlock Text="{Binding Path=.}"/>
          </DataTemplate>
          <local:MyDataTemplateSelector IntDataTemplate="{StaticResource intDataTemplate}"
                                        StringDataTemplate="{StaticResource stringDataTemplate}"
                                        x:Key="myDataTemplateSelector"/>
      </Window.Resources>
      <Grid>
          <ListBox x:Name="myListBox" ItemsSource="{Binding}"
                   ItemTemplateSelector="{StaticResource myDataTemplateSelector}">
      
          </ListBox>
      </Grid>
      

      代码隐藏

      using System;
      using System.Collections.Generic;
      using System.Linq;
      using System.Text;
      using System.Threading.Tasks;
      using System.Windows;
      using System.Windows.Controls;
      using System.Windows.Data;
      using System.Windows.Documents;
      using System.Windows.Input;
      using System.Windows.Media;
      using System.Windows.Media.Imaging;
      using System.Windows.Navigation;
      using System.Windows.Shapes;
      
      namespace Q1
      {
          /// <summary>
          /// Interaction logic for MainWindow.xaml
          /// </summary>
          public partial class MainWindow : Window
          {
              public MainWindow()
              {
                  InitializeComponent();
                  List<System.Object> myList = new List<object>();
                  myList.Add(1);
                  myList.Add("Alpha");
                  myList.Add(2);
                  myList.Add("Beta");
                  myList.Add(3);
                  myList.Add("Gamma");
                  myListBox.DataContext = myList;
              }
          }
      
      }
      

      数据模板选择器

      using System;
      using System.Collections.Generic;
      using System.Linq;
      using System.Text;
      using System.Threading.Tasks;
      
      namespace Q1
      {
          public class MyDataTemplateSelector : System.Windows.Controls.DataTemplateSelector
          {
              public System.Windows.DataTemplate IntDataTemplate { get; set; }
              public System.Windows.DataTemplate StringDataTemplate { get; set; }
              public MyDataTemplateSelector()
              {
                  IntDataTemplate = new System.Windows.DataTemplate();
                  StringDataTemplate = new System.Windows.DataTemplate();
              }
              public override System.Windows.DataTemplate SelectTemplate(object item, System.Windows.DependencyObject container)
              {
                  if (item is Int32)
                  {
                      return IntDataTemplate;
                  }
                  else
                  {
                      return StringDataTemplate;
                  }
              }
          }
      }
      

      【讨论】:

      • @Vivex Saurav “l”代表什么?
      • 这是您定义的命名空间 xmlns:l="clr-namespace:DataTemplates" 检查更新的答案
      • @Vivex Saurav DependencyPropertyInfo 找不到
      【解决方案4】:

      您可以使用 DataTemplateSelector 根据您的数据选择模板,这是一个示例。

      对于本例,我将使用消息、客户端消息和服务器消息:

      public abstract class Message
      {
          public string Content { get; set; }
      
          public override string ToString()
          {
              return Content;
          }
      }
      
      public class ServerMessage : Message
      {
      
      }
      
      public class ClientMessage : Message
      {
      
      }
      

      这样,我可以检查对象的类型并应用特定的模板。

      让我们定义我们的模板和选择器:

      XAML:

          <DataTemplate x:Key="clientTemplate" >
              <TextBlock Text="{Binding Content}"
                         Foreground="Red"/>
          </DataTemplate>
      
          <DataTemplate x:Key="serverClient">
              <TextBlock Text="{Binding Content}"
                         Foreground="Green"/>
          </DataTemplate>
      
          <local:MessageTemplateSelector x:Key="messageSelector" 
                                         ServerTemplate="{StaticResource serverClient}"
                                         ClientTemplate="{StaticResource clientTemplate}"/>
      

      数据模板选择器

      public class MessageTemplateSelector : DataTemplateSelector
      {
          public DataTemplate ClientTemplate { get; set; }
      
          public DataTemplate ServerTemplate { get; set; }
      
          public override System.Windows.DataTemplate SelectTemplate(object item, System.Windows.DependencyObject container)
          {
              if (item.GetType() == typeof(ClientMessage))
                  return ClientTemplate;
      
              return ServerTemplate;
          }
      }
      

      首先,如你所见,我在我的 Selector 上创建了两个 DataTemplate 属性,我通过 XAML 设置它,这样做很容易检索 DataTemplate,最后我只是比较参数接收到的项目,即绑定对象(消息),并检查其类型并返回模板。

      就是这样,它按预期工作。

      更新:假设您希望根据项目类型模板化您的项目,就像我的示例一样,您可以在不使用 TemplateSelector 的情况下进行上述相同操作,您可以定义模板的 DataType:

      <Window.Resources>
          <DataTemplate DataType="{x:Type local:ClientMessage}">
              <TextBlock Text="{Binding Content}"
                         Foreground="Red"/>
          </DataTemplate>
      
          <DataTemplate DataType="{x:Type  local:ServerMessage}">
              <TextBlock Text="{Binding Content}"
                         Foreground="Green"/>
          </DataTemplate>
      </Window.Resources>
      

      这样做会根据对象的类型自动选择模板。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-10-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多