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

时间:2013-03-14 03:18:54

标签: c# wpf windows-phone

我昨天发布了a question,但我认为我未能正确解释。

让我再试一次。

所以这是我的目标:

enter image description here

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

为了实现这个目标,我写道:

<ListBox>
    <ListBox.ItemTemplate>
        <DataTemplate>
            <ListBoxItem>
                <Grid Background="{Binding Color}">
                    <TextBlock Text="{Binding Text}" FontSize="30"/>
                </Grid>
            </ListBoxItem>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

请注意,上面的代码中没有指定对齐,因为我真的不知道如何使用模板分别为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>

但是这没用。因为包装语音气泡的Grid不会自动展开,所以此GridGrid的对齐无关紧要(紧密配合)。

然后我去寻找如何在Grid内扩展StackPanel,但没有运气。

经过数小时的谷歌搜索,试验和错误后,我决定自己为ItemsPanelTemplate定义模板。我的Message对象中有一个属性可以帮助我告诉传出消息。但我不知道如何创建ItemsPanelTemplate选择器(据记录,谷歌告诉我,Windows Phone 8不支持Style.Trigger)。

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

BTW,ItemsPabelTemplate看起来像这样:

<ListBox.ItemsPanel>
    <ItemsPanelTemplate>
        <StackPanel />
    </ItemsPanelTemplate>
</ListBox.ItemsPanel>

非常感谢你的耐心等待。我已经在这里疯狂地绝望......这么多时间浪费在这上面......

5 个答案:

答案 0 :(得分:4)

注意:我没有Phone SDK,所以不得不使用普通的WPF应用程序。我没有使用触发器,因为你提到它们不起作用。

所以我敲了一个看起来像这个的简单应用

enter image description here

以下是代码:

App.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" });
    }
}

MainWindow.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>

ViewModelBase.cs

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);
        }
    }
}

MainWindowViewModel:

public class MainWindowViewModel : ViewModelBase
{
    public MainWindowViewModel()
    {
        Messages = new ObservableCollection<Message>();
    }
    public ObservableCollection<Message> Messages { get; protected set; }
}

Message.cs:

public abstract class Message : ViewModelBase
{
    private string _messageContent;

    public string MessageContent 
    {
        get
        {
            return this._messageContent;
        }
        set
        {
            this._messageContent = value;
            this.OnPropertyChanged("MessageContent");
        }
    }   
}

OutgoingMessage.cs

public class OutgoingMessage : Message
{
}

IncomingMessage.cs

public class IncomingMessage : Message
{
}

如何运作 我重写了应用程序启动,因此我可以创建viewmodels来填充我的UI。您可以在App.xaml.cs代码中看到我创建窗口并显示它,然后添加消息。我打算使用计时器,但是很懒。

如果查看MainWindow.xaml,您会注意到我定义了2个DataTemplates。其中一个目标是我的IncomingMessageViewModel,另一个目标是OutogingMessageViewModel。本地前缀是我的应用程序命名空间的别名。我有一个ItemsControl,可以包含基类型Message类,这样我就可以在同一个集合中同时拥有Incoming和Outgoing消息。这绑定到MainWindowViewModel类的Messages属性。将传入和传出消息作为两个单独的类很重要,因为这是使这项工作成为可能的魔力。

另一种技术是使用一个带有样式选择器绑定到属性的属性作为其他答案建议之一,但这意味着我必须处理我的ViewModel中的UI特定逻辑(我不会# 39;不喜欢这样做。

要更改任一消息类型的外观,只需更改相应DataTemplate中的xaml代码。

希望这有帮助。

答案 1 :(得分:1)

在WPF中,您需要添加

    <ListBox.ItemContainerStyle>
        <Style>
            <Setter Property="HorizontalAlignment" Value="{Binding WHATEVER}" />
        </Style>
    </ListBox.ItemContainerStyle>

到你的ListBox并将“WHATEVER”设置为具有指定对齐的项目的属性...我不知道这是否适用于Windows Phone但是它似乎值得一试,因为你没有提到ItemContainerStyle ...

答案 2 :(得分:1)

不使用Grid,而是使用DockPanel和Horizo​​ntalAlignment =“Stretch”。

对于数据对齐,假设您正在使用ItemsSource,那么有一些解决方法。

首先,最简单的方法是将Horizo​​ntalAlignment WPF属性添加到邮件类中。消息类将确定Horizo​​ntalAlignment是左还是右。但是,这会使UI的依赖性更高。

代码将是这样的:

<TextBlock Text="{Binding Text}" HorizontalAlignment="{Binding MessageHAlign}" />

其次,更好(或干净)的方法是使用转换器(IValueConverter)进行Horizo​​ntalAlignment绑定。它更难,你必须定义自己的转换器,但你的代码将更整洁。然后您的消息有一个收入或结果消息的枚举,名为MessageType。然后在您的转换器中定义它:

public object Convert(object value, Type targetType, 
  object parameter, CultureInfo culture)
{
  if(parameter is MessageType){
    if(((MessageType)parameter) == MessageType.Income){
      return HorizontalAlignment.Left;
    }
    else{
      return HorizontalAlignment.Right;
    }
  }
}

上面的代码未经过测试,因此请考虑错误。 有关Converter的实现,请在某些地方搜索。没有帮助源我仍然无法生成Converter绑定:)

答案 3 :(得分:0)

尝试此操作并根据传入设置属性为左和外传为右

<DataTemplate>

<ListBoxItem>

 <Grid>
 <Grid Background="{Binding Color}" HorizontalAlignment="{Binding Property}">
  <TextBlock Text="{Binding Text}" FontSize="30"/>
 </Grid>
 </Grid>
 </ListBoxItem>
 </DataTemplate>

答案 4 :(得分:0)

这将是我肮脏的工作示例

代码隐藏

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();

        var l = new List<lItem>();

        for(int i=0;i<5;i++)
        {
        l.Add(new lItem(true,"aaa"+i));
        l.Add(new lItem(false,"bbb"+i));
        }

        sads.ItemsSource = l;

    }
}


public class lItem
{
    public string Text { get; set; }
    public Brush Color { get; set; }
    public HorizontalAlignment alig { get; set; }

    public lItem(bool ss, string str)
    {
        Text = str;
        Color = Brushes.Blue;
        alig = HorizontalAlignment.Right;

        if (ss)
        {
            Color = Brushes.Red;
            alig = HorizontalAlignment.Left;
        }
    }
}

的Xaml

<ListBox Name="sads" Width="230">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <ListBoxItem>
                        <Grid Width="200">
                            <Label Background="{Binding Color}" VerticalAlignment="Top" HorizontalAlignment="{Binding alig}" >
                                <TextBlock Text="{Binding Text}" FontSize="30"/>
                            </Label>
                        </Grid>
                    </ListBoxItem>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>

我建议使用触发器而不是在ViewModel中定义视觉部件