首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何创建上下文感知的ListBoxItem模板?

如何创建上下文感知的ListBoxItem模板?
EN

Stack Overflow用户
提问于 2011-07-10 09:40:40
回答 4查看 400关注 0票数 1

我想要创建XAML聊天接口,它将根据邻居的不同显示不同的消息。下面是一个例子:

我认为ListBox控件最适合这种情况。我也在考虑不同的控件,如FlowDocumentReader,但我从未使用过它们。另外,我需要提到消息的文本应该是可选择的(跨多个消息),我不知道如何使用ListBox实现这一点。

更新:这里的要点是,如果一方(在本例中是viking)在一行中发送一些消息,则接口应该将这些消息连接起来(使用瘦消息头而不是完整消息头)。因此,消息头的外观取决于先前的消息是否由同一个人发送。

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2011-07-15 00:44:15

如果您只是对标头的格式(完整的还是小的)感兴趣,那么在ListBox/ListView/ItemsControl绑定中使用PreviousData就可以了(正如anivas所指出的)。

但是,由于您添加了支持跨多个消息进行选择的功能,因此,据我所知,这基本上排除了ItemsControl及其派生的类。您将不得不使用类似于FlowDocument的东西。

不幸的是,FlowDocument没有ItemsSource属性。有一些解决方法的例子,比如使用流文档和数据绑定创建灵活的UI,但是这个实现很大程度上使我的VS2010崩溃(我没有调查原因,可能是一个简单的修复)。

,这是我怎么做的,

首先,在设计器中设计FlowDocument块,当您满意时,将它们移动到设置x:Shared="False"的资源中。这将使您能够创建资源的多个实例,而不是反复使用相同的实例。然后,使用ObservableCollection作为FlowDocument的“源”,并订阅CollectionChanged事件,在均衡器中,您将获得资源的一个新实例,检查是否需要完整的或小的标题,然后将这些块添加到FlowDocument中。您还可以添加删除等的逻辑。

示例实现

代码语言:javascript
复制
<!-- xmlns:Collections="clr-namespace:System.Collections;assembly=mscorlib" -->

<Window.Resources>
    <Collections:ArrayList x:Key="blocksTemplate" x:Shared="False">
        <!-- Full Header -->
        <Paragraph Name="fullHeader" Margin="5" BorderBrush="LightGray" BorderThickness="1" TextAlignment="Right">
            <Figure HorizontalAnchor="ColumnLeft" BaselineAlignment="Center" Padding="0" Margin="0">
                <Paragraph>
                    <Run Text="{Binding Sender}"/>
                </Paragraph>
            </Figure>
            <Run Text="{Binding TimeSent, StringFormat={}{0:HH:mm:ss}}"/>
        </Paragraph>
        <!-- Small Header -->
        <Paragraph Name="smallHeader" Margin="5" TextAlignment="Right">
            <Run Text="{Binding TimeSent, StringFormat={}{0:HH:mm:ss}}"/>          
        </Paragraph>
        <!-- Message -->
        <Paragraph Margin="5">
            <Run Text="{Binding Message}"/>
        </Paragraph>
    </Collections:ArrayList>
</Window.Resources>
<Grid>
    <FlowDocumentScrollViewer>
        <FlowDocument Name="flowDocument"
                      FontSize="14" FontFamily="Georgia"/>
    </FlowDocumentScrollViewer>
</Grid>

后面的代码可以是以下代码

代码语言:javascript
复制
public ObservableCollection<ChatMessage> ChatMessages
{
    get;
    set;
}

public MainWindow()
{
    InitializeComponent();
    ChatMessages = new ObservableCollection<ChatMessage>();
    ChatMessages.CollectionChanged += ChatMessages_CollectionChanged;
}

void ChatMessages_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
    ArrayList itemTemplate = flowDocument.TryFindResource("blocksTemplate") as ArrayList;
    if (e.Action == NotifyCollectionChangedAction.Add)
    {
        foreach (ChatMessage chatMessage in e.NewItems)
        {
            foreach (Block block in itemTemplate)
            {
                bool addBlock = true;
                int index = ChatMessages.IndexOf(chatMessage);
                if (block.Name == "fullHeader" &&
                    (index > 0 && ChatMessages[index].Sender == ChatMessages[index - 1].Sender))
                {
                    addBlock = false;
                }
                else if (block.Name == "smallHeader" &&
                         (index == 0 || ChatMessages[index].Sender != ChatMessages[index - 1].Sender))
                {
                    addBlock = false;
                }
                if (addBlock == true)
                {
                    block.DataContext = chatMessage;
                    flowDocument.Blocks.Add(block);
                }
            }
        }
    }
}

在我的样本中,ChatMessage只是

代码语言:javascript
复制
public class ChatMessage
{
    public string Sender
    {
        get;
        set;
    }
    public string Message
    {
        get;
        set;
    }
    public DateTime TimeSent
    {
        get;
        set;
    }
}

这将使您能够在消息中选择您喜欢的文本。

如果您使用的是MVVM,您可以创建附加行为,而不是后面的代码,我在这里做了一个类似场景的示例实现:

另外,用于FlowDocument的MSDN页面非常有用:http://msdn.microsoft.com/en-us/library/aa970909.aspx

票数 1
EN

Stack Overflow用户

发布于 2011-07-13 17:31:42

假设您的ItemTemplateStackPanel of TextBlock头和TextBlock消息,您可以使用MultiBinding可见性Converter将标题隐藏为:

代码语言:javascript
复制
<TextBlock Text="{Binding UserName}">  
   <TextBlock.Visibility> 
       <MultiBinding Converter="{StaticResource headerVisibilityConverter}"> 
       <Binding RelativeSource="{RelativeSource PreviousData}"/> 
       <Binding/> 
    </MultiBinding>                             
   </TextBlock.Visibility> 
</TextBlock> 

IMultiValueConverter逻辑是这样的:

代码语言:javascript
复制
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) 
    { 
        var previousMessage = values[0] as MessageItem; 
        var currentMessage = values[1] as MessageItem; 
        if ((previousMessage != null) && (currentMessage != null)) 
        { 
            return previousMessage.UserName.Equals(currentMessage.UserName) ? Visibility.Hidden : Visibility.Visible; 
        }           

        return Visibility.Visible; 
    } 
票数 1
EN

Stack Overflow用户

发布于 2011-07-10 10:21:09

尝试给出一个提示--伪代码,如

代码语言:javascript
复制
public abstract class Message {/*Implementation*/

      public enum MessageTypeEnum {Client, Viking, None};          

      public abstract MessageTypeEnum MessageType {get;}   
}

public class ClientMessage : Message {

      /*Client message concrete implementation.*/
       public override MessageTypeEnum MessageType 
       {
           get { 
               return MessageTypeEnum.Client;
           } 
       }
}

public class VikingMessage : Message 
{     
       / *Viking message concrete implementation*/
       public override MessageTypeEnum MessageType 
       {
           get { 
               return MessageTypeEnum.Viking;
           } 
       }

}

之后,在reference代码中,在绑定控件上使用XAML属性Converter,您可以在其中分配一个实现IValueConverter的类引用。以下是链接

网上资源:

转换器

在那里,您可以在UI/ModelView之间转换类型。

希望这能有所帮助。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/6640338

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档