Reputation: 3109
I recently watched John Papa's Service Patterns with SL from SL Firestarter 2010, which described a service pattern in MVVM Light that I'm currently trying to implement. I'll describe the process below, but wanted to first state that I've been able to get my 'design time' data working no problem. What I can't figure out is my run-time data. Unfortunately my client is stuck using old-school .asmx web services, and my hands are tied on this one.
From my ViewModel, I call out IAccountService, an interface I've set up with my one method: GetAccounts. From here, I use a ServiceProviderBase class to determine if the call came from designtime or runtime. When I call this method from design time, I load a DesignAccountService which uses a DesignAccount Model to populate fake data to ultimately display in my Gridview. It works, I'm pretty stoked.
When I call the GetAccounts method from runtime, . The DB guy here has written and tested a web service that returns data into a data table, and is then converted into an ObservableCollection. This Web Service is running inside the web project of the solution. I'm attempting to call this web service from my SL project & grab the observable collection... Alright, so code:
In my ViewModel:
protected TSMVVM.Services.IAccountService AccountService { get; set; }
public AccountDefinitionViewModel(TSMVVM.Services.IAccountService accountService)
{
AccountService = accountService;
LoadData();
}
public void LoadData()
{
LoadAccounts();
}
public void LoadAccounts()
{
Accounts = null;
AccountService.GetAccounts(GetAccountsCallback);
}
private void GetAccountsCallback(ObservableCollection<TSMVVM.Model.P.P_ACCOUNTS> accounts)
{
if (accounts != null)
{
this._accounts = accounts;
if (_accounts.Count > 0)
{
SelectedAccount = Accounts[0];
}
}
}
private ObservableCollection<TSMVVM.Model.P.P_ACCOUNTS> _accounts;
public ObservableCollection<TSMVVM.Model.P.P_ACCOUNTS> Accounts
{
get { return _accounts; }
set
{
_accounts = value;
RaisePropertyChanged("Accounts");
}
}
Interface:
public interface IAccountService
{
void GetAccounts(Action<ObservableCollection<TSMVVM.Model.P.P_ACCOUNTS>> getAccountsCallback);
}
AccountService
private ObservableCollection<TSMVVMCommonSVC.TSAccount> _account = new ObservableCollection<TSMVVMCommonSVC.TSAccount>();
private TSMVVMCommonSVC.CommonSoapClient CommonService;
private Action<ObservableCollection<TSMVVMCommonSVC.TSAccount>> _getAccountsCallback;
public AccountService()
{
}
public void GetAccounts(Action<ObservableCollection<TSMVVM.Model.P.P_ACCOUNTS>> getAccountsCallback)
{
_getAccountsCallback = getAccountsCallback;
Uri iSilverlightServiceUriRelative = new Uri(App.Current.Host.Source, "../Services/Common.asmx");
EndpointAddress iSilverlightServiceEndpoint = new EndpointAddress(iSilverlightServiceUriRelative);
BasicHttpBinding iSilverlightServiceBinding = new BasicHttpBinding(BasicHttpSecurityMode.Transport);// Transport if it's HTTPS://
CommonService = new TSMVVMCommonSVC.CommonSoapClient(iSilverlightServiceBinding, iSilverlightServiceEndpoint);
CommonService.GetAccountCollectionCompleted +=new EventHandler<TSMVVMCommonSVC.GetAccountCollectionCompletedEventArgs>(CommonService_GetAccountCollectionCompleted);
CommonService.GetAccountCollectionAsync();
}
private void CommonService_GetAccountCollectionCompleted(object sender,TSMVVMCommonSVC.GetAccountCollectionCompletedEventArgs e)
{
if (e.Result.Length > 0)
{
foreach (TSMVVMCommonSVC.TSAccount item in e.Result) {
var acct = new TSMVVM.Model.P.P_ACCOUNTS() {
ACCOUNT_NUMBER = item.AccountNumber,
DESCRIPTION = item.AccountDescription
};
_account.Add(acct);
}
}
_getAccountsCallback(_account);
}
Now, if I put a breakpoint in my ViewModel on the GET for Accounts, (which is set to return _accounts), Accounts get set to a collection of items with 315 items in it. If I drill down into that collection, I can see that the data is successfully returned from my web service. In fact, at this breakpoint, if I head into my xaml (code functions virtually identically in a DataGrid instead of a telerik control),
<telerik:RadGridView ItemsSource="{Binding Accounts}"
SelectedItem="{Binding SelectedAccount, Mode=TwoWay}"
AutoGenerateColumns="False">
<telerik:RadGridView.Columns>
<telerik:GridViewDataColumn DataMemberBinding="{Binding Path=ACCOUNT_NUMBER}" Header="Account Number" />
<telerik:GridViewDataColumn DataMemberBinding="{Binding Path=DESCRIPTION}" Header="Description" />
</telerik:RadGridView.Columns>
</telerik:RadGridView>
With the breakpoint set, I can see that the Accounts variable, in my ItemsSource binding, is set to that collection of 315 items. However, the grid is empty. I Know my column bindings are bound to the correct items, but I can't figure out where to go from here.
Upvotes: 0
Views: 660
Reputation: 14037
Change this code:
if (accounts != null)
{
this._accounts = accounts;
with
if (accounts != null)
{
this.Accounts = accounts;
Because the event PropertyChanged isn't fired in the first code, and UI doesn't know anything about changes.
Upvotes: 2