0
votes

I have window "ClientsWindow" and it's view model class "ClientsViewModel". In ViewModel i defined property "Clients" and bound it to DataGrid's itemssource property:

private ObservableCollection<tblClient> clients;
public ObservableCollection<tblClient> Clients
{
    get { return clients; }
    set
    {
        clients = value;
        OnPropertyChanged("Clients");
    }
}

In my window's constructor I set this property to new value by calling the method from wcf service like this:

Clients = new ObservableCollection<tblClient>(wcf.FilterClients(PageIndex, PageSize));

And it works perfect, I get 10 records from wcf service as it should be and the list is shown in datagrid. I insert some usercontrol which I want to use for datagrid pagination. It has ChangedIndexCommand defined like this:

ChangedIndexCommandProperty =
        DependencyProperty.Register("ChangedIndexCommand", typeof(ICommand), typeof(GridPaging), new UIPropertyMetadata(null));


public ICommand ChangedIndexCommand
{
    get { return (ICommand)GetValue(ChangedIndexCommandProperty); }
    set { SetValue(ChangedIndexCommandProperty, value); }
}

I tried to bind command form my window's viewmodel to this command, so i did it this way:

private ICommand _cmdChangedIndex;
    public ICommand cmdChangedIndex
    {
        get
        {
            if (_cmdChangedIndex == null)
            {
                _cmdChangedIndex = new DelegateCommand(delegate()
                {
                    worker.DoWork += worker_FilterClientsList;
                    worker.RunWorkerCompleted += worker_FilterClientListCompleted;
                    worker.RunWorkerAsync();

                });
            }
            return _cmdChangedIndex;
        }
    }

    private void worker_FilterClientsList(object sender, DoWorkEventArgs e)
    {
        try
        {
            ServiceClient wcf = new ServiceClient();
            Clients = new ObservableCollection<tblClient>(wcf.FilterClients(PageIndex, PageSize));
            TotalCount = wcf.ReturnClientsCount();
        }
        catch (Exception ex)
        {

        }
    }

    private void worker_FilterClientListCompleted(object sender, RunWorkerCompletedEventArgs e) 
    {
        worker.DoWork -= worker_FilterClientsList;
    }

And here is the xaml:

<pc:GridPaging PageIndex="{Binding PageIndex, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
                       PageSize="{Binding PageSize, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
                       TotalCount="{Binding TotalCount, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
                       HorizontalAlignment="Center" x:Name="clientsPagingControl"
                       ChangedIndexCommand="{Binding cmdChangedIndex, UpdateSourceTrigger=PropertyChanged}"
                       Visibility="Visible" VerticalAlignment="Top"
                       />

So, while debugging everything works perfect! My command is fired when i click on the button of my userconrol, the method from wcf service is called properly and it returns new collection of items(count 2, as expected), my "Clients" property is set to new value BUT, UI still showing 10 items in my datagrid. I just cant figure out what is wrong?! Is this wrong way of binding commands to custom user controls?? Also let me note that, PageIndex, PageSize and TotalCount properties are of type int, and i bound them to my viewmodel properties, and they work perfect. But what is the problem with my command? I tried to be as clear as I could hope that you will understand what my problem is, and for any more info, please leave the comment.

OnPropertyChanged:

public event PropertyChangedEventHandler PropertyChanged;

protected void OnPropertyChanged(string propertyName)
{
    PropertyChangedEventHandler handler = PropertyChanged;

    if (handler != null)
    {
        handler(this, new PropertyChangedEventArgs(propertyName));
    }
} 

DataGrid binding:

<DataGrid IsReadOnly="True"  Name="dgClients" AutoGenerateColumns="False" ItemsSource="{Binding Path=Clients, UpdateSourceTrigger=PropertyChanged}">
     <DataGrid.Columns>
                ....
     </DataGrid.Columns>
</DataGrid>
2
Make sure that you implemented your OnPropertyChanged method correctly... can you show it please? - Sheridan
I updated the question with the code. - Stojdza
That code is in separate class which I inherit in my all view model classes. - Stojdza
That implementation seems fine too... you have a problem elsewhere. Tell me... what happens if you call Clients.Clear(); when the ICommand is called? If nothing happens in the UI, but the collection is emptied, then you have a problem with notifying the UI of the changes. - Sheridan
That's exactly what happens. My collection is empty and once again while debugging everything seems fine but UI remains the same. I thought maybe the problem is in my background worker so I tried to call OnPropertyChanged(); once more in RunWorkerCompleted event, but no success. Also tried the code withouth background worker at all but the effect is the same. - Stojdza

2 Answers

0
votes

Just a thought, but it looks like you are using a BackgroundWorker class in your ICommand? In the worker_FilterClientsList method, you are setting the "Clients" observable collection property. I don't think you are able to manipulate the UI from within DoWork (it's running on a different thread). Try removing the try..catch block to see if it's hiding such an error.

You normally have to update the UI from the RunWorkerCompleted delegate (your worker_FilterClientListCompleted method).

0
votes

Ok, so judging by your question, answers and the many comments, it would seem that your problem is un-reproducible. This means that you are on your own, as far as fixing your problem goes. However, this is not as bad as it sounds.

As there is no obvious problem with your displayed code, I cannot point out where your error lies. However, I can put you onto the right path to fix your own problem. It will take some time and effort on your part, but 'no pain... no gain', as they say.

One of the best ways that you find the problem in a complex project is to simplify it in a new, empty project. Normally when doing this, one of two things happens: either you find out what the problem was, or you create a concise working example that demonstrates your problem, which you can then post here (maybe as a new question, or instead of your current code). It's usually a win-win situation.

As it happens, the StackOverflow Help Center has a page to help with this. Please follow the advice in the How to create a Minimal, Complete, Tested and Readable example page to help you to simplify your problem.

One final point that I'd like to make is that normally in an application, the data access layer is separate from the UI. If you separate your different concerns like this, you will also find that it simplifies the situation further.