0

2人用のシンプルなSilverlightチャットボックスを作成するタスクが与えられました。私のコントロールは、次の要件に準拠する必要があります

  1. スクロール可能
  2. 長すぎる場合はテキストを折り返す必要があります
  3. 新しいアイテム/メッセージが追加されると、そのアイテムをスクロールして表示する必要があります

これで、これらの要件を満たすためのユーザーコントロールを正常に作成できましたが、修正できないバグ/クラッシュが発生する可能性があります。バグの修正、またはスクロール可能なチャットコントロールを作成するための別のアプローチを探しています。

これが私が使っているコードです。チャットウィンドウ用のXAMLから始めます

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

アイデアは、リストボックスに新しいアイテムを追加することです。アイテム(XAMLにレイアウトされている)は、単純な2列のグリッドです。ユーザー名用に1列、メッセージ用に1列。

これで、リストボックスに追加する「アイテム」はカスタムクラスになりました。XAML内でバインディングを使用する3つのプロパティ(Player、ForeColor、およびMessage)があります

Playerは、表示する現在のユーザーの文字列です。

ForeColorは、単なる前景色の設定です。メッセージ間の違いを区別するのに役立ちます。

メッセージWrapPanelです。プログラムで、各単語の空白で指定された文字列を分割します。次に、単語ごとに、新しいTextBlock要素をWrapPanelに追加します

これがカスタムクラスです。

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

最後に、リストボックスにアイテムを追加します。これが簡単な方法です。上記のChatMessageクラスをパラメータとして取ります

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

今、私はこれをテストしました、そしてそれはすべてうまくいきます。私が得ている問題は、スクロールバーを使用するときです。サイドスクロールバーまたは矢印キーを使用して下にスクロールできますが、上にスクロールするとSilverlightがクラッシュします。FireBugは、 XamlParseExceptionを含むManagedRuntimeError #4004を返します。

私はこのコントロール作業にとても近いです、私はそれを味わうことができます!私が何をすべきか、何を変えるべきかについて何か考えはありますか?私が取ったものよりも良いアプローチはありますか?

前もって感謝します。

アップデート

ListBoxコントロールの代わりにScrollViewerとItemsControlを使用する代替ソリューションを見つけました。ほとんどの場合、それは安定しています。

4

1 に答える 1

0

ListBoxコントロールの代わりにScrollViewerとItemsControlを使用する代替ソリューションを見つけました。ほとんどの場合、それは安定しています。

代わりに、現在使用しているXAMLを次に示します。

<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>
于 2010-03-30T19:14:04.497 に答える