views:

1285

answers:

1

I'm having an issue with an ObservableCollection getting new items but not reflecting those changes in a ListView. I have enough quirks in the way I'm implementing this that I'm having a hard time determining what the problem is.

My ObservableCollection is implemented thusly:

public class MessageList : ObservableCollection<LobbyMessage>
{
    public MessageList(): base()
    {
        Add(new LobbyMessage() { Name = "System", Message = "Welcome!" });
    }
}

I store the collection in a static property (so that its easily accessible from multiple user controls):

static public MessageList LobbyMessages { get; set; }

In the OnLoad event of my main NavigationWindow I have the following line:

ChatHelper.LobbyMessages = new MessageList();

My XAML in the UserControl where the ListView is located reads as:

    <ListBox IsSynchronizedWithCurrentItem="True" 
         ItemsSource="{Binding Mode=OneWay}" 
         x:Name="ListBoxChatMessages" 
         d:UseSampleData="True" 
         ItemTemplate="{DynamicResource MessageListTemplate}" 
         IsEnabled="True">
      <ListBox.DataContext>
     <Magrathea_Words_Tools:MessageList/>
       </ListBox.DataContext>
    </ListBox>

The initial message that I added in the constructor appears in the UI just fine.

Now, the way I add new items to the collection is from a CallBack coming from a WCF service. I had this code working in a WinForms application and it was neccessary to marshall the callback to the UI thread so I left that code in place. Here is an abbreviated version of the method:

Helper.Context = SynchronizationContext.Current;

#region IServiceMessageCallback Members

/// <summary>
/// Callback handler for when the service has a message for 
/// this client
/// </summary>
/// <param name="serviceMessage"></param>
public void OnReceivedServiceMessage(ServiceMessage serviceMessage)
{
    // This is being called from the WCF service on it's own thread so
    //  we have to marshall the call back to this thread.
    SendOrPostCallback callback = delegate
    {
        switch (serviceMessage.MessageType)
        {
            case MessageType.ChatMessage:
                ChatHelper.LobbyMessages.Add(
                        new LobbyMessage()
                        {
                            Name = serviceMessage.OriginatingPlayer.Name,
                            Message = serviceMessage.Message
                        });
                break;

            default:
                break;
        }
    };

    Helper.Context.Post(callback, null);
}

While debugging I can see the collection getting updated with messages from the service but the UI is not reflecting those additions.

Any ideas about what I'm missing to get the ListView to reflect those new items in the collection?

+4  A: 

I resolved this issue.

Neither the static property or the context of the incoming data had anything to do with the issue (which seems obvious in hindsight).

The XAML which was generated from Expression Blend was not up to the task for some reason. All I did to get this to work was assign the ItemSource to the collection in C#.

ListBoxChatMessages.ItemsSource = ChatHelper.LobbyMessages.Messages;

My XAML is now more simplified.

<ListBox IsSynchronizedWithCurrentItem="True" 
       ItemsSource="{Binding Mode=OneWay}" Background="#FF1F1F1F" 
       Margin="223,18.084,15.957,67.787" x:Name="ListBoxChatMessages" 
       ItemTemplate="{DynamicResource MessageListTemplate}" 
       IsEnabled="True"/>

I'm a little confused as to why this works. I was reading the MSDN articles on how to bind data in WPF and they included several binding objects, referencing properties on object, etc. I don't understand why they went to all the trouble when one line of code in the UserControl's constructor does the trick just fine.

Sailing Judo
As I understand it, MS's intention in WPF was to make things like setting binding sources (like the ItemsSource property) a static data setting in the xaml, rather than in code. A more experienced developer remade my complex program with almost no C#, and only a little more xaml. xaml > code.
Phil H