Мне задали задачу создать простой чат для Silverlight для двух человек. Мой контроль должен соответствовать следующим требованиямSilverlight Chat WrapPanel Crash/Bug
- Scrollable
- Текст должен завернуть, если это слишком долго
- Когда новый элемент/добавляется сообщение должно листать этот элемент в поле зрения
сейчас Я успешно сделал 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. По большей части он стабилен.