Search code examples
wpfwcfdata-bindingobservable

How to Bind a Listview to an observallable collection in a WCF service?


I'm Hosting a WCF service in a WPF application. The WCF service has an Observablecollection which I'm trying to bind to the listview in WPF but i keep getting nullreference exception since the list is empty at the time of intialisation. It only gets elements added when the client connects to the Service. My XAML is below

<ListView HorizontalAlignment="Left" Height="341" Margin="42,35,0,0" VerticalAlignment="Top" Width="621" x:Name="listView">
        <ListView.View>
            <GridView>
                <GridViewColumn Header=" Time" Width="100" DisplayMemberBinding="{Binding Time}"/>
                <GridViewColumn Header="Blade Name" Width="200" DisplayMemberBinding="{Binding Name}"/>
            </GridView>
        </ListView.View>
    </ListView>

The Simplified version of the code behind file is below

using System.ServiceModel.Description;
using SomeNameSpace.WCFService;

namespace SomeNameSpace.WPFHost
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
    ServiceHost host;
    MyClass SingleTonService;
    MyClass  srvc;
    public MainWindow()
    {

        try
        {             
            SingleTonService = new MyClass();
            host = new ServiceHost(SingleTonService, baseAddresses);             
            host.Open();

            var obj = host.SingletonInstance;

            srvc = (SomeNameSpace.WCFService.MyClass)obj;
            //WPF Section
            *** Getting null reference exception here since the list is emtpy ***
            listView.ItemsSource = srvc.__clientList;
            //Refresh();

        }
        catch(NullReferenceException e)
        {

        }
        catch (Exception e)
        {
            host.Abort();
        }
    }

The simplified WCFService class is as below

using System.Collections.ObjectModel;


namespace SomeNameSpace.WCFService
{
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single,
                    ConcurrencyMode = ConcurrencyMode.Multiple,
                    UseSynchronizationContext = false)]
public class MyClass : IMyClass
{
    public ObservableCollection<Client> __clientList = new ObservableCollection<Client>();

    public ObservableCollection<Client> clientList
    { get { return __clientList; } }
    public ICallback Callback
    {
        get
        {
            return OperationContext.Current.GetCallbackChannel<ICallback>();

        }
    }

    public bool Connect(Client client)
    {
        if (!clients.ContainsValue(CurrentCallback) && !SearchByName(client.Name))
        {
                __clientList.Add(client);
            }
            return true;
        }
        return false;
    }
 }

Client Class

[DataContract]
public class Client
{
    private string _name;
    private DateTime _time;

    [DataMember]
    public string Name
    {
        get { return _name; }
        set { _name = value; }
    }

    [DataMember]
    public DateTime Time
    {
        get { return _time; }
        set { _time = value; }
    }
}

Also, If i bind the observablecollection to the listview after the connect method is called, everything works since the list isn't empty but i can't do this at run time since i tested this using buttonclick event and setting listview.itemsource in the event after the connect method is called. There will not be any buttons in the final code.


Solution

  • i replaced the line below

    listView.ItemsSource = srvc.__clientList;
    

    with

    srvc.__clientList.CollectionChanged += OnCollectionChanged;
    

    and in the event handler i used the code below to manually update the list

    this.Dispatcher.Invoke((Action)(() =>
                {
                    listView.Items.Clear();
                    //update listview here
                }));