2010-03-30 3 views
0

Мне задали задачу создать простой чат для Silverlight для двух человек. Мой контроль должен соответствовать следующим требованиямSilverlight Chat WrapPanel Crash/Bug

  1. Scrollable
  2. Текст должен завернуть, если это слишком долго
  3. Когда новый элемент/добавляется сообщение должно листать этот элемент в поле зрения

сейчас Я успешно сделал usercontrol для удовлетворения этих требований, но я столкнулся с возможной ошибкой/сбоем, которую я не могу исправить. Я ищу либо исправление ошибки, либо другой подход к созданию прокручиваемого управления чатом.

Вот код, который я использовал. Мы начнем с моего 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) представляет собой простую сетку из двух столбцов. Один столбец для имени пользователя и один столбец для сообщения.

Теперь «элементы», которые я добавить в ListBox это пользовательский класс. Он имеет три свойства (Player, ForeColor и Message), которые я использую в моем XAML

Игрок - это строка текущего пользователя для отображения.

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 возвращает ManagedRuntimeError # 4004 с XamlParseException.

Я Су близок к тому, этому контролю работы, я могу попробовать его! Любые мысли о том, что я должен делать или менять? Есть ли лучший подход, чем тот, который я взял?

Заранее спасибо.

UPDATE

Я нашел альтернативное решение, используя ScrollViewer и ItemsControl вместо элемента управления ListBox. По большей части он стабилен.

ответ

0

Я нашел альтернативное решение, использующее ScrollViewer и ItemsControl вместо элемента управления ListBox. По большей части он стабилен.

Вот 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> 
Смежные вопросы