如何添加不同的列表框项目 WPF
How to add different ListBox items WPF
我正在实现一个像下图这样的聊天应用程序:
我首先创建了一个 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。
也许这会给你一个想法
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;
}
}
}
DataTemplateSelector
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;
}
}
}
}
如果您的消息相同 class,您可以像 http://codingbandit.com/blog/?p=8
那样使用 itemsTemplateSelector
如果有不同的 classes,您应该只使用数据模板数据类型 属性,如 Conditional List itemtemplate or datatemplate in WPF
另一种选择是简单地使用数据触发器:
<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>
您可以使用 DataTemplateSelector select 模板根据您的数据,这里是一个例子。
对于此示例,我将使用消息、客户端消息和服务器消息:
public abstract class Message
{
public string Content { get; set; }
public override string ToString()
{
return Content;
}
}
public class ServerMessage : Message
{
}
public class ClientMessage : Message
{
}
通过这种方式,我可以检查对象的类型并应用特定的模板。
让我们定义模板,然后select或:
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}"/>
DataTemplateSelector
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;
}
}
首先,如您所见,我在我的选择器上创建了两个 DataTemplate 属性,我通过 XAML 设置了它,这样做很容易检索 DataTemplate,最后我只是比较收到的项目通过参数,这是绑定对象(消息),并检查其类型和return模板。
就是这样,它按预期工作。
更新: 假设您希望根据项目的类型对项目进行模板化,就像我的示例一样,您可以在不使用 TemplateSelector 的情况下进行上述操作,您可以定义您的模板的数据类型:
<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>
这样做,模板将根据对象的类型自动 selected。
我正在实现一个像下图这样的聊天应用程序:
我首先创建了一个 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。
也许这会给你一个想法
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;
}
}
}
DataTemplateSelector
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;
}
}
}
}
如果您的消息相同 class,您可以像 http://codingbandit.com/blog/?p=8
那样使用 itemsTemplateSelector如果有不同的 classes,您应该只使用数据模板数据类型 属性,如 Conditional List itemtemplate or datatemplate in WPF
另一种选择是简单地使用数据触发器:
<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>
您可以使用 DataTemplateSelector select 模板根据您的数据,这里是一个例子。
对于此示例,我将使用消息、客户端消息和服务器消息:
public abstract class Message
{
public string Content { get; set; }
public override string ToString()
{
return Content;
}
}
public class ServerMessage : Message
{
}
public class ClientMessage : Message
{
}
通过这种方式,我可以检查对象的类型并应用特定的模板。
让我们定义模板,然后select或:
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}"/>
DataTemplateSelector
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;
}
}
首先,如您所见,我在我的选择器上创建了两个 DataTemplate 属性,我通过 XAML 设置了它,这样做很容易检索 DataTemplate,最后我只是比较收到的项目通过参数,这是绑定对象(消息),并检查其类型和return模板。
就是这样,它按预期工作。
更新: 假设您希望根据项目的类型对项目进行模板化,就像我的示例一样,您可以在不使用 TemplateSelector 的情况下进行上述操作,您可以定义您的模板的数据类型:
<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>
这样做,模板将根据对象的类型自动 selected。