Pergunta

Recebi a tarefa de criar uma caixa de bate -papo simples de Silverlight para duas pessoas. Meu controle deve aderir aos seguintes requisitos

  1. Rolável
  2. O texto deve envolver se for muito tempo
  3. Quando um novo item / mensagem é adicionado, ele deve rolar esse item em exibição

Agora, criei com sucesso um UserControl para atender a esses requisitos, mas encontrei um possível bug / falha que não posso para a vida de mim consertar. Estou procurando uma correção para o bug ou uma abordagem diferente para criar um controle de bate -papo rolável.

Aqui está o código que tenho usado. Começaremos com meu xaml para a janela de bate -papo

<ListBox x:Name="lbChatHistory" Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" ScrollViewer.VerticalScrollBarVisibility="Visible" ScrollViewer.HorizontalScrollBarVisibility="Disabled" >
    <ListBox.ItemTemplate>
    <DataTemplate>
        <Grid Background="Beige">
        <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="70"></ColumnDefinition>
        <ColumnDefinition Width="Auto"></ColumnDefinition>
        </Grid.ColumnDefinitions>
        <TextBlock x:Name="lblPlayer" Foreground="{Binding ForeColor}"  Text="{Binding Player}" Grid.Column="0"></TextBlock>
        <ContentPresenter Grid.Column="1" Width="200" Content="{Binding Message}" />
    </Grid>
    </DataTemplate>
</ListBox.ItemTemplate>
</ListBox>

A idéia é adicionar um novo item à caixa de listagem. O item (conforme estabelecido no XAML) é uma grade simples de 2 coluna. Uma coluna para o nome de usuário e uma coluna para a mensagem.

Agora, os "itens" que eu adiciono ao ListBox são uma classe personalizada. Possui três propriedades (jogador, integridade e mensagem) em que eu uso a ligação dentro do meu xaml

Jogador é uma sequência do usuário atual a ser exibido.

ECOLOR é apenas uma preferência de cor de primeiro plano. Ajuda a distinguir a diferença entre as mensagens.

Mensagem é um Wrappanel. Eu quebro programaticamente a corda fornecida no espaço branco para cada palavra. Então, para cada palavra, eu adiciono um novo Textblock elemento para o Wrappanel

Aqui está a classe personalizada.

public class ChatMessage :DependencyObject, INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    public static DependencyProperty PlayerProperty = DependencyProperty.Register( "Player", typeof( string ), typeof( ChatMessage ),
                                                                                         new PropertyMetadata(
                                                                                            new PropertyChangedCallback( OnPlayerPropertyChanged ) ) );

    public static DependencyProperty MessageProperty = DependencyProperty.Register( "Message", typeof( WrapPanel ), typeof( ChatMessage ),
                                                                                         new PropertyMetadata(
                                                                                            new PropertyChangedCallback( OnMessagePropertyChanged ) ) );

    public static DependencyProperty ForeColorProperty = DependencyProperty.Register( "ForeColor", typeof( SolidColorBrush ), typeof( ChatMessage ),
                                                                                         new PropertyMetadata(
                                                                                            new PropertyChangedCallback( OnForeColorPropertyChanged ) ) );

    private static void OnForeColorPropertyChanged( DependencyObject d, DependencyPropertyChangedEventArgs e )
    {
        ChatMessage c = d as ChatMessage;
        c.ForeColor = ( SolidColorBrush ) e.NewValue;
    }

    public ChatMessage()
    {
        Message = new WrapPanel();
        ForeColor = new SolidColorBrush( Colors.White );
    }

    private static void OnMessagePropertyChanged( DependencyObject d, DependencyPropertyChangedEventArgs e )
    {
        ChatMessage c = d as ChatMessage;
        c.Message = ( WrapPanel ) e.NewValue;
    }

    private static void OnPlayerPropertyChanged( DependencyObject d, DependencyPropertyChangedEventArgs e )
    {
        ChatMessage c = d as ChatMessage;
        c.Player = e.NewValue.ToString();
    }

    public SolidColorBrush ForeColor
    {
        get { return ( SolidColorBrush ) GetValue( ForeColorProperty ); }
        set
        {
            SetValue( ForeColorProperty, value );
            if(PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs( "ForeColor" ));
        }
    }

    public string Player
    {
        get { return ( string ) GetValue( PlayerProperty ); }
        set
        {
            SetValue( PlayerProperty, value );
            if ( PropertyChanged != null )
                PropertyChanged( this, new PropertyChangedEventArgs( "Player" ) );
        }
    }

    public WrapPanel Message
    {
        get { return ( WrapPanel ) GetValue( MessageProperty ); }
        set
        {
            SetValue( MessageProperty, value );
            if ( PropertyChanged != null )
                PropertyChanged( this, new PropertyChangedEventArgs( "Message" ) );
        }
    }
}

Por fim, adiciono meus itens à caixa de listagem. Aqui está o método simples. É preciso a aula de chatmessage acima como um parâmetro

public void AddChatItem( ChatMessage msg )
    {
        lbChatHistory.Items.Add( msg );
        lbChatHistory.ScrollIntoView( msg );
    }

Agora eu testei isso e tudo funciona. O problema que estou recebendo é quando uso a barra de rolagem. Você pode rolar para baixo usando a barra de rolagem lateral ou as teclas de seta, mas quando você rola as falhas do Silverlight. Firebug retorna a ManagedRuntimeError #4004 com um XamlparseException.

Estou tão perto de ter esse trabalho de controle, posso provar! Alguma ideia do que devo fazer ou mudar? Existe uma abordagem melhor do que a que eu adotei?

Desde já, obrigado.

ATUALIZAR

Encontrei uma solução alternativa usando um scrollViewer e um itemsControl em vez de um controle da caixa de listagem. Na maioria das vezes, é estável.

Foi útil?

Solução

Encontrei uma solução alternativa usando um scrollViewer e um itemsControl em vez de um controle da caixa de listagem. Na maioria das vezes, é estável.

Aqui está o xaml que eu uso agora.

<ScrollViewer x:Name="lbChatHistoryScroller">
                    <ItemsControl x:Name="lbChatHistory" Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" ScrollViewer.VerticalScrollBarVisibility="Visible" ScrollViewer.HorizontalScrollBarVisibility="Disabled">
                        <ItemsControl.ItemTemplate>
                            <DataTemplate>
                                <Grid Background="Beige">
                                    <Grid.ColumnDefinitions>
                                        <ColumnDefinition Width="70"></ColumnDefinition>
                                        <ColumnDefinition Width="Auto"></ColumnDefinition>
                                    </Grid.ColumnDefinitions>
                                    <TextBlock x:Name="lblPlayer" Foreground="{Binding ForeColor}" Text="{Binding Player}" Grid.Column="0"></TextBlock>
                                    <ContentPresenter Grid.Column="1" Width="1750" Content="{Binding Message}">
                                    </ContentPresenter>
                                </Grid>
                            </DataTemplate>
                        </ItemsControl.ItemTemplate>
                    </ItemsControl>
                </ScrollViewer>
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top