我昨天发布了一个问题,但我想我没有正确解释它。
让我再试一遍。
所以这是我的目标:

红色气泡代表传入消息,蓝色气泡代表传出消息。我可以使用以下 xaml 代码更准确地描述这一点。请注意,以下代码只是对我的实际 xaml 代码(带有一些 DataTemplates)编译时我期望得到的内容的解释(WPF 将使用 DataTemplates 为我自动填充数据)。:
<ListBox>
<ListBoxItem HorizontalAlignment="Right">
<Grid Background="Blue">
<TextBlock Text="Help me please!" FontSize="30"/>
</Grid>
</ListBoxItem>
<ListBoxItem HorizontalAlignment="Left">
<Grid Background="Red">
<TextBlock Text="What do you want?" FontSize="30"/>
</Grid>
</ListBoxItem>
<ListBoxItem HorizontalAlignment="Right">
<Grid Background="Blue">
<TextBlock Text="I want a ListBox" FontSize="30"/>
</Grid>
</ListBoxItem>
<ListBoxItem HorizontalAlignment="Left">
<Grid Background="Red">
<TextBlock Text="Then?" FontSize="30"/>
</Grid>
</ListBoxItem>
<ListBoxItem HorizontalAlignment="Right">
<Grid Background="Blue">
<TextBlock Text="But the Grid won't fill" FontSize="30"/>
</Grid>
</ListBoxItem>
</ListBox>
Run Code Online (Sandbox Code Playgroud)
为了实现这一目标,我写道:
<ListBox>
<ListBox.ItemTemplate>
<DataTemplate>
<ListBoxItem>
<Grid Background="{Binding Color}">
<TextBlock Text="{Binding Text}" FontSize="30"/>
</Grid>
</ListBoxItem>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Run Code Online (Sandbox Code Playgroud)
请注意,上面的代码中没有指定对齐方式,因为我真的不知道如何使用模板分别为 ListBoxItem 设置不同的对齐方式。因此,默认情况下,这将导致所有蓝色和红色网格都向左对齐的情况。
我的第一种方法包括一个数据模板选择器(省略了传入消息的模板):
<ListBox>
<ListBox>
<ListBox.ItemTemplate>
<!-- local:MessageBubbleTemplateSelector.OutgoingMessageTemplate -->
<DataTemplate>
<ListBoxItem>
<Grid>
<Grid Background="{Binding Color}" HorizontalAlignment="Right">
<TextBlock Text="{Binding Text}" FontSize="30"/>
</Grid>
</Grid>
</ListBoxItem>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</ListBox>
Run Code Online (Sandbox Code Playgroud)
但这不起作用。因为Grid包裹语音气泡的不会自动膨胀,所以Grid里面的对齐方式Grid没有关系(紧密贴合)。
然后我去寻找如何在 aGrid内部扩展a StackPanel,但没有走运。
经过数小时的谷歌搜索和反复试验,我决定为ItemsPanelTemplate自己定义模板。我的Message对象中有一个属性可以帮助我从传出消息中分辨传入消息。但我不知道如何创建ItemsPanelTemplate选择器(为了记录,谷歌告诉我Style.TriggerWindows Phone 8 不支持)。
所以我的问题是:如何为 设置不同的 HorizontalAlignment ListBoxItems?
顺便说一句,ItemsPabelTemplate看起来像这样:
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
Run Code Online (Sandbox Code Playgroud)
非常感谢您的耐心等待。我已经在这里绝望了......浪费了很多时间......
注意:我没有电话 SDK,所以只能使用普通的 WPF 应用程序。我没有使用触发器,因为你提到它们不起作用。
所以我敲了一个看起来像这样的简单应用程序

这是代码:
应用程序.xaml.cs
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
var mainvm = new MainWindowViewModel();
var window = new MainWindow
{
DataContext = mainvm
};
window.Show();
mainvm.Messages.Add(new OutgoingMessage{ MessageContent = "Help me please!"});
mainvm.Messages.Add(new IncomingMessage { MessageContent = "What do you want" });
mainvm.Messages.Add(new OutgoingMessage { MessageContent = "I want a ListBox" });
mainvm.Messages.Add(new IncomingMessage { MessageContent = "Then?" });
mainvm.Messages.Add(new OutgoingMessage { MessageContent = "But the Grid won't fill" });
}
}
Run Code Online (Sandbox Code Playgroud)
主窗口.xaml
<Window x:Class="ChatUI.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:ChatUI"
Title="MainWindow" Height="350" Width="200">
<Window.Resources>
<DataTemplate DataType="{x:Type local:IncomingMessage}">
<Grid Margin="0,10">
<Border CornerRadius="8" Background="Red" BorderBrush="Black" BorderThickness="1" />
<TextBlock Text="{Binding MessageContent}" HorizontalAlignment="Left" Margin="5" Foreground="White"/>
</Grid>
</DataTemplate>
<DataTemplate DataType="{x:Type local:OutgoingMessage}">
<Grid Margin="0,10">
<Border CornerRadius="8" Background="Blue" BorderBrush="Black" BorderThickness="1" />
<TextBlock Text="{Binding MessageContent}" HorizontalAlignment="Right" Margin="5" Foreground="White"/>
</Grid>
</DataTemplate>
</Window.Resources>
<Grid Background="Black">
<ItemsControl ItemsSource="{Binding Path=Messages}"/>
</Grid>
Run Code Online (Sandbox Code Playgroud)
视图模型库
public class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
this.OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
}
protected virtual void OnPropertyChanged(PropertyChangedEventArgs e)
{
var handler = this.PropertyChanged;
if (handler != null)
{
handler(this, e);
}
}
}
Run Code Online (Sandbox Code Playgroud)
主窗口视图模型:
public class MainWindowViewModel : ViewModelBase
{
public MainWindowViewModel()
{
Messages = new ObservableCollection<Message>();
}
public ObservableCollection<Message> Messages { get; protected set; }
}
Run Code Online (Sandbox Code Playgroud)
消息.cs:
public abstract class Message : ViewModelBase
{
private string _messageContent;
public string MessageContent
{
get
{
return this._messageContent;
}
set
{
this._messageContent = value;
this.OnPropertyChanged("MessageContent");
}
}
}
Run Code Online (Sandbox Code Playgroud)
传出消息.cs
public class OutgoingMessage : Message
{
}
Run Code Online (Sandbox Code Playgroud)
传入消息.cs
public class IncomingMessage : Message
{
}
Run Code Online (Sandbox Code Playgroud)
这是如何工作的 我覆盖了应用程序启动,这样我就可以创建视图模型来填充我的 UI。您可以在 App.xaml.cs 代码中看到我创建了窗口并显示它,然后添加消息。我打算使用计时器,但很懒惰。
如果您查看 MainWindow.xaml,您会注意到我定义了 2 个 DataTemplate。其中一个针对我的 IncomingMessageViewModel,另一个针对 OutogingMessageViewModel。本地前缀是我的应用程序命名空间的别名。我有一个 ItemsControl 可以包含基本类型 Message 类,这样我就可以在同一个集合中同时包含传入和传出消息。这绑定到我的 MainWindowViewModel 类上的 Messages 属性。将传入和传出消息作为 2 个独立的类非常重要,因为这是使这项工作发挥作用的魔法。
另一种技术是使用一个带有绑定到属性的样式选择器的属性,正如其他答案所建议的那样,但这意味着我必须在我的 ViewModel 中处理 UI 特定的逻辑(我不喜欢做)。
要更改任一消息类型的外观,只需更改相应 DataTemplate 中的 xaml 代码。
希望这可以帮助。
| 归档时间: |
|
| 查看次数: |
2423 次 |
| 最近记录: |