C# : public observablecollection<ViewModel> instance pass items to protected observablecollection<ViewModel> - c#

I have the following class which work just fine
public class RemoteSource {
ObservableCollection<RemoteDataViewModel> remote;
string[] _servers = new string[] {
"server",
"server",
"server",
"server",
"server"
};
public RemoteSource() {
remote = CreateDataSource();
}
protected ObservableCollection<RemoteDataViewModel> CreateDataSource() {
ObservableCollection<RemoteDataViewModel> res = new ObservableCollection<RemoteDataViewModel>();
ITerminalServicesManager _manager = new TerminalServicesManager();
foreach (var host in _servers) {
using (ITerminalServer srv = _manager.GetRemoteServer(host)) {
try {
srv.Open();
foreach (ITerminalServicesSession session in srv.GetSessions()) {
res.Add(new RemoteDataViewModel() { Server = srv.ServerName, SessionID = session.SessionId, UserID = session.UserName, State = session.ConnectionState, ConnectedTime = session.ConnectTime, LogonTime = session.LoginTime, IdleTime = session.IdleTime, UserIP = session.ClientIPAddress, Workstation = session.WindowStationName });
}
srv.Close();
}
catch (Win32Exception) { }
catch (SystemException) { }
catch (Exception) { }
}
}
return res;
}
/// <summary>
/// Gets the data.
/// </summary>
/// <value>
/// The data.
/// </value>
public ObservableCollection<RemoteDataViewModel> Data { get { return remote; } }
public ObservableCollection<string> hosts { get; set; }
}
The RemoteSource is setup but a button event that does the following
DataContext = new RemoteSource();
I want to read through a text file that has the list of server names like so
Server1
Server2
Server3
etc
and load them into an ObservableCollection then be able to do the same thing I am currently doing on this line
foreach (var host in _servers) # but where _servers is the observablecollection initiated from the button event
I attempted doing something like this under the button event, but rs.hosts always returns as null
RemoteSource rs = new RemoteSource();
rs.hosts.Add(Environment.MachineName);

Your ObservableCollection<T> should be a property of your ViewModel. Then, in the View, you bind some ItemsControl.ItemsSource property to it.
For exemple (super simplified):
public class SessionViewModel : INotifyPropertyChanged
{
// ...
public ObservableCollection<String> ServerList { get; set; }
}
And in the View
<ListView x:Name="ServerList" ItemsSource="{Binding ServerList}"/>

Not sure if you're trying to let the user select a server, or edit the server. I'm answering both. Editing first, then selecting after.
Bindings can only update properties of a class. They cannot replace an instance of one type with a completely different instance of another type within a collection. That's just not how it works. Remember, this is Model View ViewModel. Your ViewModels must expose Models whose properties are bound to elements in the UI. These properties will be updated by the bindings.
So, create a Model for your server
public sealed class ServerInfo
{
public string Name {get;set;}
public string IP {get;set;}
public string Whatevs {get;set;}
}
In your VM, you would expose your list of servers from the ViewModel. If you're looking to do work on selected servers, you'd want to have a Selected property and do work on update.
public sealed class ViewModelLol : INotifyPropertyChanged
{
// init from ctor
public ObservableCollection<ServerInfo> Servers {get;private set;}
public ServerInfo SelectedServer {get;set;} // should be INPC impl, but yawn
// boring stuff goes here
}
In your UI, you'd bind an ItemsSource to the collection
<ListBox ItemsSource="{Binding Servers}" SelectedItem="{Binding SelectedServer}" >
<ListBox.ItemTemplate>
<DataTemplate>
<!-- If you wanted to edit the server name... -->
<TextBox Text="{Binding Name}"/>
<!-- If you only care about selection... -->
<Label Content="{Binding Name}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Not exactly sure if you want to be able to edit the server name, if so, use the first option. If you want to present to the user a list of servers and allow them to select one, then use the label option.
Once the user selects a server, SelectedServer in the ViewModel is updated. You can take that opportunity to do whatever work you need to.
ViewModels should be at the top of the logic food chain. They interpret actions of users of the system and convert them into API calls within. So if you need to connect to a server, then the VM should contain the logic to connect to the server. The VM shouldn't be a child of some business logic class. That requires some tricky spaghetti code and will be harder to implement.
VMs are supposed to sit between the UI and your core business logic, which shouldn't care about the UI at all. For instance, connecting to a server has nothing to do with the UI. Identifying which server to connect to does. Bridging that gap is the role of the VM.

Related

WPF Data Binding To Self Updating Model

Please can you advise if this is possible or what approach is best?
I will add my code afterwards but I am worried that it will add limited value to what I am trying to ask/explain.
The WPF examples that I have seen implement
A (poco) model e.g Customer.
Then they implement a view model (MVVM pattern). (The View Model needs to implement ObservableCollection and or implement INotifyPropertyChanged interface so that any changes in the model are reflected in the UI once the model changes.)
In the xaml code behind, in the page constructor, the ViewModel is passed to the DataContext.
The xaml can then bind to this View Model Data with a Mode of update e.g. TwoWay.
Here is what I need to understand.
I have implemented my own data model / class, which has async tasks constantly updating the status of different fields in this class.
My model resides in a separate class library that I would like to inject/supply it to a view model. However, since my object/class is 'self-updating', I can't simply copy across values into my view model - since they will change over time. I want my view model to be aware of changes that underlying values and show these changes in the UI as the async tasks update the model.
How do I go about this? So in my example, my Customer object will be self-updating, some background task would add/remove customers in a class library outside of my ViewModel.
I hope that I have managed to ask my question in a way that is clear to understand.
The XAML binding to the Customer View Model
<ListView Grid.Row="1" ItemsSource="{x:Bind ViewModel.Customers,Mode=OneWay}"
SelectedItem="{x:Bind ViewModel.SelectedCustomer,Mode=TwoWay}">
<ListView.ItemTemplate>
<DataTemplate x:DataType="model:Customer">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{x:Bind FirstName,Mode=OneWay}" FontWeight="Bold"/>
<TextBlock Text="{x:Bind LastName,Mode=OneWay}"
Margin="5 0 0 0"/>
<TextBlock Text="(Developer)" Margin="5 0 0 0" Opacity="0.5"
Visibility="{x:Bind IsDeveloper,Mode=OneWay}"/>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Reference for this sample code
public class MainViewModel : Observable
{
private ICustomerDataProvider _customerDataProvider;
private Customer _selectedCustomer;
public MainViewModel(ICustomerDataProvider customerDataProvider)
{
_customerDataProvider = customerDataProvider;
Customers = new ObservableCollection<Customer>();
}
public Customer SelectedCustomer
{
get { return _selectedCustomer; }
set
{
if (_selectedCustomer != value)
{
_selectedCustomer = value;
OnPropertyChanged();
OnPropertyChanged(nameof(IsCustomerSelected));
}
}
}
public bool IsCustomerSelected => SelectedCustomer != null;
public ObservableCollection<Customer> Customers { get; }
public async Task LoadAsync()
{
Customers.Clear();
var customers = await _customerDataProvider.LoadCustomersAsync();
foreach (var customer in customers)
{
Customers.Add(customer);
}
}
public async Task SaveAsync()
{
await _customerDataProvider.SaveCustomersAsync(Customers);
}
public void AddCustomer()
{
var customer = new Customer { FirstName = "New" };
Customers.Add(customer);
SelectedCustomer = customer;
}
public void DeleteCustomer()
{
var customer = SelectedCustomer;
if (customer != null)
{
Customers.Remove(customer);
SelectedCustomer = null;
}
}
}
The INotifyPropertyChanged is implemented here:
public class Observable : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName]string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
Thanks #Bandook for your comments. Sometimes the coding is the easy part, but the thought behind and the process of fitting the parts together in a simple and coherent way can be more difficult.
The solution I implemented was as follows:
As per the customer example, I had had to implement methods that updated my class properties that implemented the INotifyPropertyChanged interface. (This was almost identical to the Customer code.) The result of this is that any changes to the underlying model are reflected in the UI.
The kicker was this. I implemented a Publish Subscribe Design Pattern in my class library - that continually refreshed the data. My 'Customer' class had to then had to subscribe to change events published by the class library.
There was one problem, however, the thread for the Class Library code and that of the application thread was not the same, resulting in a clash.
The article here allowed me to solve this issue.
In summary, the solution was to implement a Publish Subscribe Design Pattern. My class library published updates and my View Model class (similar to the customer class) subscribed to the events it published.

Passing data between view models in MVVM C#

I'm currently trying to create a "log" text box that gets messages between multiple view models (tied to multiple views) that I have. I've tried the approach described by user Blachshma here (Multiple Data Contexts in View) but it does not seem to be working.
I have three classes. Class AViewModel, Class BViewModel and Class ABViewModel.
The view for A binds to AViewModel using the following code in its constructor:
this.InitializeComponent();
this.model = new AViewModel();
this.DataContext = this.model;
The view for B and AB follows the same pattern.
The class structures are as follows:
public class A : INotifyPropertyChanged
{
private string log = string.empty;
public class A()
{
}
public string ALog
{
get
{
return this.log;
}
set
{
this.log = value;
this.NotifyPropertyChanged("ALog");
}
}
private void NotifyPropertyChanged(string propertyName)
{
if (this.PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
/* Function that executes when relay command is clicked */
private void ExecuteCommand()
{
this.ALog += "here";
}
}
Class B is defined the same way with property BLog
Class ABViewModel has properties for each other view model
public class ABViewModel
{
public AViewModel AVM
{
get;
set;
}
public BViewModel BVM
{
get;
set;
}
}
In the xaml I simply have
<TextBox Text="{Binding ABViewModel.AVM}" />
My plan is to eventually using Multibinding to concatenate both logs together, but at the moment I can't even get the one View Model to update my string. It looks like my container view model ABViewModel isn't getting updated, but I don't really understand why, but I'm not entirely sure how to fix this.
Any suggestions are extremely appreciated!
Thanks!
Edit:
I debug my code and see that my string ALog is getting updated, but I don't see the change on the UI. For more information, I click a button that's connected to a RelayCommand in class A. This button invokes a method to connect to a COM port. I'm able to use the COM port from other view models successfully after opening it. The log is supposed to update saying that the com port was opened but I never see any text added to the log in the GUI even though the instance of ALog that I can debug through has the added text.
I can't use Prism or MVVM-light for this particular project.

How to bind data from View to UserControl with SoapBox

I have my SoapBox.Document 'Register'
[Export(SoapBox.Core.ExtensionPoints.Workbench.Documents, typeof(IDocument))]
[Export(CompositionPoints.Workbench.Documents.Register, typeof(Register))]
[Document(Name = DOC_NAME)]
class Register : AbstractDocument
{
public Receipt actualReceipt;
private const string DOC_NAME = "Register";
public Register()
{
Name = DOC_NAME;
Title = "Recipe Document Title";
SomeProperty = "Hello from the recipe document!";
}
}
In this Document I want to user UserControls witch are kind of a own "View"
Like a ListView for all ReceiptPositions
So now I got my Model Receipt and ReceiptPosition
Model Receipt
class Receipt
{
public int Id { get; set; }
public string Receiptnumber { get; set; }
public IList<ReceiptPositions> ReceiptPositions { get; set; }
and Model ReceiptPosition
class ReceiptPosition
{
public int Id { get; set; }
//public Receipt Receipt { get; set; } using for Database
public int Position { get; set; }
public string Article { get; set; }
}
So now I want to add a UserControl witch displays a List of all articles in ReceiptPositions.
But how do I bind the data so that when a new ReceiptPosition gets added to the IList in Receipt the UserControl get 'refreshed' automatically?
Here is a visual example of whatI need..
Host with Data and two PLugins wich each show the same Data but in a different way.
You can use an ItemsControl for this purpose.
xaml:
<ItemsControl ItemsSource="{Binding MyReceipt.ReceiptPositions}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<!-- Where you put your view -->
<TextBox Text="{Binding Article}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<!-- Can be whatever Panel type you want -->
<StackPanel />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
cs:
private Receipt _myReceipt;
public Receipt MyReceipt { get { return _myReceipt; } set { _myReceipt = value; OnPropertyChanged("MyReceipt"); } }
public MainWindow()
{
InitializeComponent();
DataContext = this;
MyReceipt = new Receipt { ReceiptPositions = new ObservableCollection<ReceiptPosition>() };
MyReceipt.ReceiptPositions.Add(new ReceiptPosition { Article = "Foo" });
MyReceipt.ReceiptPositions.Add(new ReceiptPosition { Article = "Bar" });
MyReceipt.ReceiptPositions.Add(new ReceiptPosition { Article = "Baz" });
MyReceipt.ReceiptPositions[0].Article = "Frabazamataz";
}
Explanation:
The ItemsControl allows you to bind a list to its ItemsSource Property to use as the DataContext to each view created by the DataTemplate.
The Observable Collection gives PropertyChange notifications automatically with each item added, removed, or changed.
This allows you to have a very flexible list of items based solely on your data.
Death's answer is correct, i.e. you use DataTemplates. If your views and data templates are in a MEF plugin then you need to import both the plugins and the data templates that map the view models to the views. In the other question you posted about this it was obvious that you're trying to export your plugin user controls...personally I think this is a bit misguided. If your main application is using MVVM then your plugins should as well. In this case your plugins should export an IPlugin class and also specify a DataTemplate that maps it to a view. As I indicated on the other page, the data template must be imported as well so that you can add it to the global resources.
I've created a project that shows this in action using the classes you provided in your uother question, you can download it here. The main points to look at are the data templates in the plugin project and the two places where things are imported in the main project.
Note that in my demo I'm requiring each plugin to explicitly specify a DataTemplate for its view and view model, but you may not want to do this so I've also added a chunk of commented-out code at the bottom of App.xaml.cs that shows how to avoid that (to make it work I had to add the view type to the IPlugData class, but that's only needed for this one example). If you choose to create the DataTemplates manually then the plugins don't need to specify the data templates and they also don't need the custom ResourceDictionary that holds them.
If you have an questions feel free to post back here in the comments.

WPF DataBinding ObservableCollection<T> to DataGrid

I'm trying to create DataGrid in a separate UserControl whose DataContext is a List of T.
In the code behind, I create a List, populate the list, then send it to the constructor for the UserControl on which I have the DataGrid I am trying to populate.
The UserControl class is as follows.
public partial class QuotePreview : UserControl
{
private static SelectionList previewList = new SelectionList();
public SelectionList PreviewList
{
get { return previewList; }
}
public QuotePreview()
{
InitializeComponent();
}
public QuotePreview(SelectionList selectedOptions)
{
InitializeComponent();
previewList = selectedOptions;
QuotePreviewDataGrid.DataContext = previewList;
}
}
And the Xaml looks like:
<DataGrid Name="QuotePreviewDataGrid"
AutoGenerateColumns="False"
ItemsSource="{Binding}">
<DataGrid.Columns>
<DataGridTextColumn Header="Model Number" Binding="{Binding ModelNumber}"/>
<DataGridTextColumn Header="Description" Binding="{Binding Description}"/>
<DataGridTextColumn Header="List Price per Unit" Binding="{Binding Price}"/>
</DataGrid.Columns>
</DataGrid>
I've tried setting the ItemSource as well using
QuotePreviewDataGrid.ItemsSource = PreviewList;
I've also tried setting both the data context and the itemsource as well as refreshing:
QuotePreviewDataGrid.Items.Refresh();
The databinding I have set to listboxes in the rest of my application works perfectly. In the list boxes I have the itemsource set to {Binding} and the ListItems binding set to {Binding Property}. The datacontext for the listboxes set in the code behind.
My datagrid here is setup in the same manner, yet for some reason nothing is being displayed inside the grid.
When I go through the debugger and watch the flow of information, I can see the List of T, SelectionsList being created and passed to the constructor for the user control where the data grid lies. I can see that the DataContext is indeed being set and shows the items in the list, but when I go back to my appication and try to view the data grid, it's blank.
Any help would be greatly appreciated. I've been trying to wrap my mind around this problem for the last day and a half. Thanks!
UPDATE
The SelectionList is setup like:
public class SelectionList : List<Selection>
{
public List<Selection> availableSelections = new List<Selection>();
public List<Selection> AvailableSelections
{
get { return availableSelections; }
}
}
and a Selection is then defined by:
public class Selection : DependencyObject
{
public bool IsChecked { get; set; }
public string ModelNumber { get; set; }
public string Description { get; set; }
public string Price { get; set; }
}
When the application starts, I build a catalog of existing products (Selections). On different tabs, one for each product family, the datacontext for the products list box is initialized with with available products that it grabs from the catalog. Then pending which product a user selects, the available options or child selections associated with that product are populated into the appropriate list boxes, accessories and warranties.
Once a user selects the options they want, a button is clicked to preview the selected items which is supposed to populate the data grid explained above.
I can build the list of selected options, however when I try to set the data context of the data grid, nothing appears. The Lists for available selections are built and set to the appropriate data context the same way I am trying to do it for the data grid, however the data grid doesn't want to display my information.
UPDATE
So after some more debugging, I've narrowed the problem down a bit. The data binding works as it should. I have no real problems there, I don't think. However, the issue I'm running into now is what I believe to be 2 different instances of my User Control, but only the original is being displayed, not the updated copy.
Here's a copy of the class from about with a couple lines I added to help debug the problem.
public partial class QuotePreview : UserControl
{
private SelectionList _selectionList;
private SelectionList temp;
public QuotePreview()
{
InitializeComponent();
_selectionList = (SelectionList)this.DataContext;
}
private void QuotePreview_Loaded(object sender, RoutedEventArgs e)
{
_selectionList.SelectedOptions.Add(
new Selection
{
ModelNumber = "this",
Description = "really",
Price = "sucks"
});
}
public QuotePreview(SelectionList selectedOptions)
{
InitializeComponent();
_selectionList = (SelectionList)this.DataContext;
temp = selectedOptions;
_selectionList.AddRange(selectedOptions);
QuotePreview_Loaded();
}
private void QuotePreview_Loaded()
{
foreach (var options in temp.SelectedOptions)
{
_selectionList.SelectedOptions.Add(options);
}
QuotePreviewDataGrid.ItemsSource = _selectionList.SelectedOptions;
}
}
The implementation of the default constructor, is called every time the user control / tab, is clicked on. When that happens, _selectionList is set to the data context of the user control, followed by the Loaded Event which adds a line to my data grid.
In another user control where I select the options I want to add to my data grid user control, I click a button that creates a list of the options I want to be added and calls the custom constructor I wrote. Once the constructor finishes, it calls a custom Loaded Event method that I created for shits and giggles, that adds the selected options to my _selectionList.
Now once I click on the data grid user control again, it goes through the whole default process, and adds another default line.
If I go back a tab and say I want these options again and go back to the data grid, it again goes through the default process and adds another default line.
Whats most intriguing though is that I can see both of the selectionLists build since I dont clear the in between processes. I see a list build of the options i want to display and a list build of the default options build...
Oh, also, SelectionList does implement ObservableCollection.
I finally came up with a solution to the problem.
public static class QuotePreview
{
public static ObservableCollection<PurchasableItem> LineItems { get; private set; }
static QuotePreview()
{
LineItems = new ObservableCollection<PurchasableItem>();
}
public static void Add(List<PurchasableItems> selections)
{
foreach (var selection in selections)
{
LineItems.Add(selection);
}
}
public static void Clear()
{
LineItems.Clear();
}
}
public class QuoteTab : TabItem
{
public ObservableCollection<PurchasableItem> PreviewItems { get; private set; }
public QuoteTab()
{
Initialize()
PreviewItems = QuotePreview.LineItems;
DataGrid.ItemSource = PreviewItems
}
}
Try changing:
QuotePreviewDataGrid.DataContext = previewList;
to
this.DataContext = previewList;
My suspicion is that the ItemsSource="{Binding}" in your xaml is overriding the DataContext code in your constructor.
By changing the previewList to be DataContext of the entire UserControl, then the binding of the DataGrid's ItemsSource can correctly evaluate.
On a side note, I would start looking into the use of ObservableCollection<T> and the MVVM design pattern. An issue you might end up with is that your DataGrid doesn't update when the underlying list changes, using the ObservableCollection<T> will fix this.
Using the MVVM design pattern will give you a good separation of your logic and data (in this case your list and how it's loaded) from the physical display (the DataGrid)

MVVM Web Service Data in both Design Time & Run Time

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.
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.

Categories