如何为 ListBoxItems 设置不同的 Horizo​​ntalAlignment

3 c# wpf windows-phone

我昨天发布了一个问题,但我想我没有正确解释它。

让我再试一遍。

所以这是我的目标:

在此处输入图片说明

红色气泡代表传入消息,蓝色气泡代表传出消息。我可以使用以下 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 不支持)。

所以我的问题是:如何为 设置不同的 Horizo​​ntalAlignment ListBoxItems

顺便说一句,ItemsPabelTemplate看起来像这样:

<ListBox.ItemsPanel>
    <ItemsPanelTemplate>
        <StackPanel />
    </ItemsPanelTemplate>
</ListBox.ItemsPanel>
Run Code Online (Sandbox Code Playgroud)

非常感谢您的耐心等待。我已经在这里绝望了......浪费了很多时间......

fai*_*ing 5

注意:我没有电话 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 代码。

希望这可以帮助。