1

I have a simple MVVM WPF app with database-first EF dbContext (which is Global.Database in my app), which is long-living in my application. I have a window with a listbox with ItemsSource binded to viewmodel property called Clients which is an ObservableCollection of my dbmodel Client.

The SelectedItem of this listbox is binded to a viewmodel property called SelectedClient.

In Client entity class there is a field called last_status which is a simple int from my database.

So, in my view, when i select client from listbox, a label binded to SelectedClient's last_status should show the value of last_status.

I added a button and a refresh command into my viewmodel. All i want is: when i manually change last_status for the client in my database and press refresh button in my view, the content of label should change. But i have absolutely no idea how to achieve this. Here is the part of my viewmodel code (i use Catel, but it doesn't matter for this case):

public ClientManagerWindowViewModel()
    {

       RefreshClientInfoCommand = new Command(OnRefreshClientInfoCommandExecute);

       Clients = new ObservableCollection<Client>();
       RefreshClients();
    }

public ObservableCollection<Client> Clients
    {
        get { return GetValue<ObservableCollection<Client>>(ClientsProperty); }
        set { SetValue(ClientsProperty, value); }
    }

    public static readonly PropertyData ClientsProperty = RegisterProperty("Clients", typeof(ObservableCollection<Client>));

public Client SelectedClient
    {
        get
        {return GetValue<Client>(SelectedClientProperty);}
        set
        {
            SetValue(SelectedClientProperty, value);
        }
    }

    public static readonly PropertyData SelectedClientProperty = RegisterProperty("SelectedClient", typeof(Client));


//here is my refresh button command handler:

 public Command RefreshClientInfoCommand { get; private set; }

 private void OnRefreshClientInfoCommandExecute()
 {
     RefreshClientInfo(SelectedClient);
 }

//and here is my "logic" for working with dbcontext:

private void RefreshClients()
    {
        var qry = (from c in Global.Database.Clients where c.client_id != 1 select c).ToList();
        Clients = new ObservableCollection<Client>(qry);
    }

private void RefreshClientInfo(Client client)
    {
        Global.Database.Entry(client).Reload();
    }

My XAML for a listbox:

<ListBox
                    x:Name="ClientsListBox"
                    Grid.Row="1"
                    Margin="5"
                    DisplayMemberPath="fullDomainName"
                    IsSynchronizedWithCurrentItem="True"
                    ItemsSource="{Binding Clients}"
                    SelectedItem="{Binding SelectedClient}" />

My XAML for a label:

<Label Margin="5" Content="{Binding SelectedClient.last_status}" />

And for a button:

<Button Command="{Binding RefreshClientInfoCommand}" Content="↻"/>

For now, when i change a client's last_status value manually in database and press refresh button nothing happens. But when i select another client in a listbox and then return to needed client - label content updates correctly. I know, maybe i miss something very stupid and simple, but i cant' figure out what exactly. Maybe i need to force change SelectedClient in my button command handler, or call SelectedClients setter somehow... Please, help me. Thanks a lot.

rovnyart_
  • 161
  • 11

2 Answers2

2

Well, i figured out what was wrong with my code.

My databindig was set to SelectedClient.last_status. For some reason it didn't work as i expected. So i created a new viewmodel property called LastStatus and modified my RefreshClientInfo:

 private void RefreshClientInfo(Client client)
    {
        Global.Database.Entry(client).Reload();
        LastStatus = client.last_status;
        SetValue(SelectedClientProperty, client);
    }

and binded label to this new property. Now everything works correct.

rovnyart_
  • 161
  • 11
0

You need to set the SelectedClient property to the new Client object that you get back from the EF query.

You could do this by storing the client_id of the currently selected client before you query the database and then select the new Client object with this particular client_id.

Try this:

private void RefreshClients()
{
    int? currentlySelectedClientId = (SelectedClient != null) ? SelectedClient.client_id : default(int?);
    var qry = (from c in Global.Database.Clients where c.client_id != 1 select c).ToList();
    Clients = new ObservableCollection<Client>(qry);
    if (currentlySelectedClientId.HasValue)
        SelectedClient = Clients.FirstOrDefault(x => x.client_id = currentlySelectedClientId.Value);
}

Edit: Make sure that you fetch the updated records from the DB:

private void RefreshClientInfo(Client client)
{
    var newClient = (from c in Global.Database.Clients where c.client_id == client.client_id select c).ToList();
    SetValue(SelectedClientProperty, newClient[0]);
}
mm8
  • 163,881
  • 10
  • 57
  • 88
  • Sorry, i can't see how it may help me - i don't want to refresh all clients, i want to refresh only one. and the function i'm generally asking for is `RefreshClientInfo(Client client)`, not `RefreshClients()`. But maybe i don't understand something. – rovnyart_ Feb 24 '17 at 11:29
  • You need to re-fetch the client from the database after you have updated it. See my edit. – mm8 Feb 24 '17 at 11:31
  • still not refreshing when i press the button :( It refreshes when i change selected client in listbox and return back. – rovnyart_ Feb 24 '17 at 11:50
  • You need to make sure that you fetch the updated item from the database and you are setting the property and raise the PropertyChanged event for it. See my edit. – mm8 Feb 24 '17 at 11:58
  • well, now it stopped working at all and not refreshing nether by button, nor by selecting another client and returning back, when i commented out `Global.Database.Entry(client).Reload` and put your code from Edit. – rovnyart_ Feb 24 '17 at 12:21
  • Why are you calling the RefreshClientInfo method in setter of the property? – mm8 Feb 24 '17 at 12:49
  • removed it from setter. still nothing refreshes when use your code:( – rovnyart_ Feb 24 '17 at 14:05
  • Read this and update your question accordingly then: http://stackoverflow.com/help/mcve – mm8 Feb 24 '17 at 14:22