不同的Horizo​​ntalAlignment以ListBox

不同的Horizo​​ntalAlignment以ListBox

本文介绍了如何设置不同的Horizo​​ntalAlignment以ListBoxItems的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我张贴昨天一个问题,但我想我未能正确解释。



让我再试一次。



这就是我的目标:





红色的讲话泡沫表示传入消息,蓝色的气泡传出消息。我可以用下面的XAML代码更精确地描述了这一点。请注意,下面的代码仅仅是我所期望得到时,我的实际XAML代码(有一些的DataTemplates)编译的解释(WPF将自动填充数据对我来说,使用的DataTemplates)。



 <&ListBox中的GT; 
<一个ListBoxItem的Horizo​​ntalAlignment =右>
<网格背景=蓝>
< TextBlock的文本=请帮助我!字号=30/>
< /网格和GT;
< / ListBoxItem的>
<一个ListBoxItem的Horizo​​ntalAlignment =左>
<网格背景=红>
< TextBlock的文本=你想干什么?字号=30/>
< /网格和GT;
< / ListBoxItem的>
<一个ListBoxItem的Horizo​​ntalAlignment =右>
<网格背景=蓝>
< TextBlock的文字=我希望有一个列表框字号=30/>
< /网格和GT;
< / ListBoxItem的>
<一个ListBoxItem的Horizo​​ntalAlignment =左>
<网格背景=红>
< TextBlock的文本=?如果字号=30/>
< /网格和GT;
< / ListBoxItem的>
<一个ListBoxItem的Horizo​​ntalAlignment =右>
<网格背景=蓝>
< TextBlock的文本=但电网将不填字号=30/>
< /网格和GT;
< / ListBoxItem的>
< /列表框>

为了才达到这一点,我写的:

 <&ListBox中的GT; 
< ListBox.ItemTemplate>
<&DataTemplate的GT;
<&ListBoxItem的GT;
<网格背景={结合颜色}>
< TextBlock的文本={结合文字}字号=30/>
< /网格和GT;
< / ListBoxItem的>
< / DataTemplate中>
< /ListBox.ItemTemplate>
< /列表框>

请注意该路线是不是在上面的代码中指定,监守我真的不知道怎么设置不同alignement对ListBoxItem的单独使用模板。因此,这将导致在那里所有的蓝色和红色栅格都左对齐,默认情况下的状况。



我的第一种方法包括数据模板选择器(用于接收消息的模板省略):

 <&ListBox中的GT; 
<&ListBox中的GT;
< ListBox.ItemTemplate> !
< - 地方:MessageBubbleTemplateSelector.OutgoingMessageTemplate - >
<&DataTemplate的GT;
<&ListBoxItem的GT;
<网格和GT;
<网格背景={结合颜色}的Horizo​​ntalAlignment =右>
< TextBlock的文本={结合文字}字号=30/>
< /网格和GT;
< /网格和GT;
< / ListBoxItem的>
< / DataTemplate中>
< /ListBox.ItemTemplate>
< /列表框>
< /列表框>



但这并没有工作。因为电网它包装讲话泡沫不会自动展开,因此电网这里面电网并不重要(紧密配合)。



然后我去寻找如何展开电网的StackPanel ,找来没有运气。



很多时间和谷歌搜索的试验和错误之后,我决定以定义 ItemsPanelTemplate 自己的模板。我在我的消息对象,可以帮助我从传出人告诉传入消息的属性。但我不知道如何创建一个 ItemsPanelTemplate 选择(根据记录,谷歌告诉我, Style.Trigger 在Windows Phone 8的不支持)。



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



BTW, ItemsPabelTemplate 是这样的:

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

感谢你这么多的耐心。我疯狂地不顾一切在这里已经...这个...浪费


解决方案

注意那么多的时间:我做的没有手机的SDK所以只好凑合着正常的WPF应用程序。正如你所说,他们没有工作,我没有用触发器。



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





下面的代码:



App.xaml.cs

 公共部分类应用:应用
{
保护覆盖无效OnStartup(StartupEventArgs E)
{
base.OnStartup(E);

变种mainvm =新MainWindowViewModel();
变种窗口=新的主窗口
{
的DataContext = mainvm
};
window.Show();

mainvm.Messages.Add(新OutgoingMessage的messageContent {=请帮助我!});

mainvm.Messages.Add(新IncomingMessage的messageContent {=你想干什么});

mainvm.Messages.Add(新OutgoingMessage {= messageContent的我想要一个列表框});

mainvm.Messages.Add(新IncomingMessage {= messageContent的然后呢?});

mainvm.Messages.Add(新OutgoingMessage的messageContent {=但电网将不填});
}
}



MainWindow.xaml

 <窗​​口x:类=ChatUI.MainWindow
的xmlns =htt​​p://schemas.microsoft.com/winfx/2006/xaml /演示
的xmlns:X =http://schemas.microsoft.com/winfx/2006/xaml
的xmlns:地方=CLR的命名空间:ChatUI
标题=主窗口HEIGHT =350WIDTH =200>
< Window.Resources>
<数据类型的DataTemplate ={X:类型本地:IncomingMessage}>
<电网保证金=0,10>
< BORDER = CornerRadius8的背景=红BorderBrush =黑了borderThickness =1/>
< TextBlock的文本={结合}的messageContent的Horizo​​ntalAlignment =左保证金=5前景=白/>
< /网格和GT;
< / DataTemplate中>

<数据类型的DataTemplate ={X:类型本地:OutgoingMessage}>
<电网保证金=0,10>
< BORDER = CornerRadius8的背景=蓝BorderBrush =黑了borderThickness =1/>
< TextBlock的文本={结合}的messageContent的Horizo​​ntalAlignment =右保证金=5前景=白/>
< /网格和GT;
< / DataTemplate中>
< /Window.Resources>
<网格背景=黑>
<的ItemsControl的ItemsSource ={绑定路径=消息}/>
< /网格和GT;





ViewModelBase.cs

 公共类ViewModelBase:INotifyPropertyChanged的
{
公共事件PropertyChangedEventHandler的PropertyChanged;

保护无效OnPropertyChanged(字符串propertyName的)
{
this.OnPropertyChanged(新PropertyChangedEventArgs(propertyName的));
}

受保护的虚拟无效OnPropertyChanged(PropertyChangedEventArgs E)
{
VAR处理器= this.PropertyChanged;
如果(处理!= NULL)
{
处理器(这一点,E);
}
}
}



MainWindowViewModel:



 公共类MainWindowViewModel:ViewModelBase 
{
公共MainWindowViewModel()
{
消息=新的ObservableCollection<消息>();
}
公众的ObservableCollection<消息>消息{搞定;保护套; }
}



Message.cs:

 公共抽象类消息:ViewModelBase 
{
私人字符串_messageContent;

公共字符串在messageContent
{
得到
{
返回this._messageContent;
}

{
this._messageContent =价值;
this.OnPropertyChanged(在messageContent);
}
}
}



OutgoingMessage.cs {
}


  p $ p> 

IncomingMessage.cs

 公共类IncomingMessage:消息
{
}

如何这部作品
我重写应用程序启动,所以我可以创造的ViewModels来填充我的UI。您可以在App.xaml.cs代码中,我创建的窗口,并显示它看,然后添加的消息。我打算用一个计时器,但偷懒。



如果你看一下MainWindow.xaml,你会发现,我已经定义2的DataTemplates。其中一个目标我IncomingMessageViewModel和其他目标的OutogingMessageViewModel。当地的前缀是我的应用程序的命名空间的别名。我有一个可以包含基本类型Message类,只是让我可以在同一个集合中有传入和传出消息的一个ItemsControl。这势必对我MainWindowViewModel类的消息属性。这是有传入和传出消息的2个独立的职业都很重要,因为这是使这项工作的法宝。



这是另一种技术是使用一个属性与绑定属性作为其他的答案中的一个建议一个风格选择,但是这将意味着我将不得不应对在我的ViewModel UI特定逻辑(我不喜欢做的事)。



要改变任何消息类型的出现,只是改变了XAML代码在各自的DataTemplate的。



希望这有助于。


I posted a question yesterday but I think I failed to explain it correctly.

Let me try again.

So this is my goal:

The red speech bubble represents an incoming message, and the blue bubble an outgoing message. I can describe this more precisely with the following xaml code. Note that the following code is only an explanation of what I expect to get when my actual xaml code (with some DataTemplates) compiles (WPF will populates the data automatically for me, using the 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>

In order to achive this, I wrote:

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

Note that alignment is not specified in the code above, becuase I really don't know how to set different alignement for ListBoxItem separately using templates. So this would result in the situation where all the blue and red grids are all aligned to the left, by default.

My first approach includes a Data Template selector (The template for incoming messages is omitted):

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

But this did not work. Because the Grid which wraps the speech bubble won't expand automatically, so the alignment of the Grid inside this Grid did not matter (tightly fitted).

And then I went for searching how to expand a Grid inside a StackPanel, and got no luck.

After many hours of googling and trials and errors, I decided to define the template for the ItemsPanelTemplate myself. I have a property in my Message object that can help me tell an incoming message from an outgoing one. But I don't know how to create an ItemsPanelTemplate selector (For the record, Google told me that Style.Trigger is not supported in Windows Phone 8).

So my question is: how to set different HorizontalAlignment for ListBoxItems?

BTW, ItemsPabelTemplate looks like this:

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

Thank you so much for your patience. I am madly desperate here already... So many hours wasted on this...

解决方案

Note: I do not have Phone SDK so had to make do with normal WPF app. I have not used triggers as you mentioned they do not work.

So I knocked up a simple app that looks like this

Here's the code:

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
{
}

How this worksI override the application startup so I can create viewmodels to populate my UI. You can see in the App.xaml.cs code I create the Window and show it, and then add the messages. I was going to use a timer but got lazy.

If you look at the MainWindow.xaml, you will notice that I have 2 DataTemplates defined. One of them targets my IncomingMessageViewModel and the other targets the OutogingMessageViewModel. The local prefix is an alias for my application namespace. I have an ItemsControl that can contain the base type Message class, just so that I can have both Incoming and Outgoing messages in the same collection. This is bound to the Messages property on my MainWindowViewModel class. It is important to have incoming and outgoing messages as 2 separate classes as this is the magic that makes this work.

An alternative technique would be to use a property with a style selector bound to the property as one of the other answers suggest, but this would mean that I would have to deal with UI specific logic in my ViewModel (which I don't like to do).

To change the appearance of either Message type, just change the xaml code in the respective DataTemplate.

Hope this helps.

这篇关于如何设置不同的Horizo​​ntalAlignment以ListBoxItems的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-31 00:37