2人用のシンプルなSilverlightチャットボックスを作成するタスクが与えられました。私のコントロールは、次の要件に準拠する必要があります
- スクロール可能
- 長すぎる場合はテキストを折り返す必要があります
- 新しいアイテム/メッセージが追加されると、そのアイテムをスクロールして表示する必要があります
これで、これらの要件を満たすためのユーザーコントロールを正常に作成できましたが、修正できないバグ/クラッシュが発生する可能性があります。バグの修正、またはスクロール可能なチャットコントロールを作成するための別のアプローチを探しています。
これが私が使っているコードです。チャットウィンドウ用の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を使用する代替ソリューションを見つけました。ほとんどの場合、それは安定しています。