In my WPF C# project I have two frames in the MainWindow. The first frame has a page with a DataGrid (bound to an XML file) in which I select an object of interest.
<Grid.Resources>
<XmlDataProvider x:Key="XmlData" Source="/DB.xml"/>
</Grid.Resources>
<DataGrid Name="dg"
SelectionChanged="dg_SelectionChanged"
AutoGenerateColumns="False"
ItemsSource="{Binding Source={StaticResource XmlData}, XPath=Data/Object}">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding XPath=Type}"></DataGridTextColumn>
<DataGridTextColumn Binding="{Binding XPath=Number}"></DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
In the second frame I open different pages (one at a time) according to the calculations I am going to perform with the selected object. At every SelectionChanged event a custom method MySub() is called, that initiates all the necessary calculations on the loaded page.
public partial class pg_DB : Page
{
public pg_DB()
{
InitializeComponent();
}
public void dg_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
switch (Var._loadedPage) // This variable holds the name of the loaded page.
{
case "pg_SCT":
pg_SCT c1 = new pg_SCT();
c1.MySub(); // Initiates the calculation process on pg_SCT page.
break;
case "pg_OCT":
pg_OCT c2 = new pg_OCT();
c2.MySub(); // Initiates the calculation process on pg_OCT page.
break;
}
}
}
The problem is that everything works well except the data visualization. Thus, for instance, every time the MySub() is called the List<> is being updated and the ItemsSource has the necessary items, yet they are not displayed in the DataGrid. Moreover, even simple TextBox1.Text = "Test" is not working. At the same time the same code works perfectly from the Button_Click method.
public partial class pg_SCT : Page
{
public pg_SCT()
{
InitializeComponent();
//grid.ItemsSource = myList (); (This works).
}
private void Button_Click(object sender, RoutedEventArgs e)
{
//grid.ItemsSource = myList (); (This works).
//TextBox1.Text = "Test"; (This works).
}
public void MySub()
{
grid.ItemsSource = myList(); // Nothing happens (although debugging shows that List is updated and ItemsSource has necessary items).
TextBox1.Text = "Test"; // Textbox remains empty.
}
public class Author
{
public int ID { get; set; }
public string Name { get; set; }
}
private List<Author> myList()
{
List<Author> authors = new List<Author>();
authors.Add(new Author()
{
ID = Var._ID,
Name = Var._Name,
});
return authors;
}
}
I can’t find what is missing to populate DataGrid and TextBox from my custom method MySub().
Thank you for your time and consideration.
In your dg_SelectionChanged method, you're creating instances of your Page controls as local variables but not using them anywhere so they are just going out of scope. I'm guessing you probably have other instances you've created elsewhere that are the ones being displayed but based on the code here the ones calling MySub are never going to show up.
Related
This's my first question here, so hi everybody.
I'm working on the mobile app in Xamarin.Forms with Prism. I've created ListView where shown data from the database.
When the user clicks in the selected row app should navigate to a new view and pass the selected item from ListView.
<ListView x:Name="DefectsBase"
RowHeight="65"
ItemsSource="{Binding Defects}"
ItemSelected="ShowDetailsEvent"
IsPullToRefreshEnabled="true"
RefreshCommand="{Binding Refresh}"
IsRefreshing="{Binding IsRefreshing}">
Code backend:
async void ShowDetailsEvent(object sender, EventArgs e)
{
var myListView = (ListView)sender;
var myItem = myListView.SelectedItem;
var p = new NavigationParameters();
p.Add("selectedDefect", myItem);
await _navigationService.NavigateAsync("DefectDetailsView", p);
}
Unfortunately, the app doesn't respond to pressing the selected row in ListView.
As I can see you are already using Prism and you have a List page with Items and you want to navigate to some details page based on the selected/taped/chosen item which the user taps in the ListView.
The idea is to move as much code and logic as we can to the view model and keep our code-behind. This is pretty easy to solve using Prism and EventToCommand behaviour.
In the example and answer below, I will show you how to solve this with few lines of code, with a nice code approach.
First of all, I recommend you use EventToCommand behaviour, you can include it with prism xmlns, like this: xmlns:prism="http://prismlibrary.com", later on, you can use it with ListView.
Remove ItemSelected event from your ListView and move the markup about it to the <ListView.Behaviors> part. Here is my code sample for the ListView which binds to some ObserverableCollection of the Car models:
<ListView ItemsSource="{Binding Cars}">
<ListView.ItemTemplate>
<DataTemplate>
...
</DataTemplate>
</ListView.ItemTemplate>
<ListView.Behaviors>
<prism:EventToCommandBehavior EventName="ItemTapped"
Command="{Binding SelectedCarCommand}"
EventArgsParameterPath="Item" />
</ListView.Behaviors>
The main part here is <ListView.Behaviors>, where you can see that I am binding to the SelectedCarCommand which will be invoked when the user taps on some of the items from the list. I am using the ItemTapped event for this and passing the current "taped" item from the list as a parameter.
In order to follow this XAML part in my view model of this page, I have declared the DelegateCommand and method which will be called when the command is invoked. The view model part looks like this:
This is my CarListPageViewModel, take a look at DelegateCommand and SelectedCar method.
public class CarListPageViewModel
{
private readonly INavigationService _navigationService;
public ObservableCollection<Car> Cars { get; set; }
public DelegateCommand<Car> SelectedCarCommand { get; private set; }
public CarListPageViewModel(INavigationService navigationService, IDataProvider dataProvider)
{
_navigationService = navigationService;
// Insert test data into collection of Cars
Cars = new ObservableCollection<Car>(dataProvider.GetData());
SelectedCarCommand = new DelegateCommand<Car>(SelectedCar);
}
private async void SelectedCar(Car selectedCar)
{
NavigationParameters navigationParameters = new NavigationParameters
{
{ "selectedCar", selectedCar }
};
await _navigationService.NavigateAsync(nameof(CarDetailsPage), navigationParameters);
}
}
As you can see we have DelegateCommand defined with the type of parameter which will be passed, in my case, this is the Car class, the same class as our items in the ListView.
In the constructor, I did my initialization and defined the method which will be called, that method has a parameter of the type Car.
When the user taps on one of the items in the ListView, SelectedCar (method) will be called and we can pass the data to the next view using NavigationParameters and NavigationService.
In order to retrieve the passed data we can use INavigationAware in the details view model and with the OnNavigatedTo method, access the data which is being passed.
This is my CarDetailsPageViewModel, take a look at OnNavigatedTo method.
public class CarDetailsPageViewModel : BindableBase, INavigationAware
{
private string carTitle;
public string CarTitle
{
get { return carTitle; }
set { SetProperty(ref carTitle, value); }
}
private string photoUrl;
public string PhotoUrl
{
get { return photoUrl; }
set { SetProperty(ref photoUrl, value); }
}
public CarDetailsPageViewModel() { }
public void OnNavigatedTo(INavigationParameters parameters)
{
if (parameters.ContainsKey("selectedCar"))
{
Car car = parameters.GetValue<Car>("selectedCar");
if (car != null)
{
CarTitle = $"{car.Make} {car.Model}";
PhotoUrl = car.PhotoUrl;
}
}
}
public void OnNavigatedFrom(INavigationParameters parameters) { }
}
From this answer and example, you can see:
How to, use EventToCommand behaviour with ListView
Define and use DelegateCommand with passing parameter
How to navigate to another view and pass navigation parameter and
... finally how to access the passed data.
Code and this sample you can find on my GitHub profile here.
Hope this answer was helpful for you!
Wishing you lots of luck with coding! 👋
I have a problem with sorting DataGrid items using SortDescriptions.
I had a static ObservableCollection that stored my data and after binding that collection to the DataGrid I was able to sort the items ascendingly by using SortDescription.
After a while I needed to change my code - a static instance of that collection was no longer sensible. After making those changes I've built the same DataGrid view but sorting the items was no longer working.
I need to create a DataGrid on WPF that would store my application's history records.
For that, I created some classes to be used as history records and then I bound that data to my DataGrid. Becuase those are historical records, I would like them to be shown to the user in an ascending order. Meaning the last item I've added will be shown at the very top.
This is my HistoryRecord class:
public class HistoryRecord {
public TransactionSender Sender { get; set; }
public string Description { get; set; }
public DateTime Timestamp { get; set; }
}
I've created a History class with an observable collection, as follows:
public static class History {
public static ObservableCollection<HistoryRecord> UserHistory { get; set; } =
new ObservableCollection<HistoryRecord>();
}
I chose to use an observable collection because that way I will be able to update the DataGrid more easily.
This is my xaml code for the DataGrid at my history tab:
<DataGrid x:Name="HistoryGrid" HorizontalAlignment="Left" AutoGenerateColumns="False" IsReadOnly="True" >
<DataGrid.Columns>
<DataGridTextColumn Header="Sender" Binding="{Binding Sender}"/>
<DataGridTextColumn Header="Description" Binding="{Binding Description}"/>
<DataGridTextColumn Header="Timestamp" Binding="{Binding Timestamp}"/>
</DataGrid.Columns>
</DataGrid>
This is my C# code for the history tab:
public partial class HistoryTab : UserControl {
public HistoryTab() {
InitializeComponent();
HistoryGrid.ItemsSource = History.UserHistory;
HistoryGrid.Items.SortDescriptions.Add(new SortDescription("Timestamp", ListSortDirection.Ascending));
HistoryGrid.Items.Refresh();
}
}
The code above works just fine. It does sort my items ascendingly.
Last week I needed to change my code a little bit.
Up until now, it was fine to have a static History class but now I need to create multiple instances of that History class for several things.
That being said, the app as a whole still has a unified history record.
In order to save that unified history record I created a new class named HistoryUtil:
public static class HistoryUtil {
public static HistoryStorage AppHistory = new HistoryStorage();
}
The History class is now called HistoryStorage and it contains the observable collection just as before:
public class HistoryStorage {
public ObservableCollection<HistoryRecord> UserHistory { get; set; } =
new ObservableCollection<HistoryRecord>();
}
The xaml code from before stayed the same.
I updated the C# code for the tab as follows:
public partial class HistoryTab : UserControl {
public HistoryTab() {
InitializeComponent();
HistoryGrid.ItemsSource = HistoryUtil.AppHistory.UserHistory;
HistoryGrid.Items.SortDescriptions.Add(new SortDescription("Timestamp", ListSortDirection.Ascending));
HistoryGrid.Items.Refresh();
}
}
This updated code does not sort the items.
This code shows the items but without the ascending order of the timestamp.
I can't figure out how and why the view is not sorted ascendingly according to the timestamp.
This is basically the same code, there are only a few changes to the structure and the fact that I've changed the static instance to be non-static.
Here are some sample data that demonstrates the issue:
HistoryRecord action1 = new HistoryRecord() {
Sender = TransactionSender.User,
Timestamp = DateTime.Now,
Description="First record, should appear last"
};
action1.StoreRecord();
//After few seconds...
HistoryRecord action2 = new HistoryRecord() {
Sender = TransactionSender.User,
Timestamp = DateTime.Now,
Description="Second record, should appear first"
};
action2.StoreRecord();
Where the StoreRecord method is set like this:
//For the static class:
public void StoreRecord() {
History.UserHistory.Add(this);
}
//For the non-static class:
public void StoreRecord() {
HistoryUtil.AppHistory.UserHistory.Add(this);
}
This is the History DataGrid:
Please note this isn't about ascending or descending - I tried them both.
It just doesn't seem to sort the items anymore.
I added a breakpoint at HistoryGrid.Items.SortDescriptions and it doesn't seem to get there.
I would appreciate your help figuring out the problem.
I started a new WPF project and on main Window I have a button. When I click it, I show a new window that displays as follows:
1 textBox (named tbTax)
1 Add Button
1 DataGrid (named dbGrid)
I obtained the DataGrid, by going to DataSources tab, and DRAG/DROP from there a table on the form/window.
When I run the app, it all works as planned. In the second window I see in the grid all my records from the database table.
NOW:
I did the Adding code for the "Add button". So when the user enters some text in the textBox (tbTax) and clicks on the Add button, the following code follows:
using (MyEntities context = new MyEntities())
{
TAX tax = new TAX();
tax.TAX1 = decimal.Parse(tbTax.Text);
context.TAXs.Add(tva);
context.SaveChanges();
tbTax.Text = "";
dbGrid.Items.Refresh();
}
So it should be obvious: I add an item to the database table through the entity framework.
But even if I added the refresh part at the end of the code... the grid does not refresh. So only if I exit the window and re-show it, only then I can see the new item I just Added.
EDIT
Following the drag/drop I ended up with this:
--XAML--
<DataGrid x:Name="tAXDataGrid" AutoGenerateColumns="False" EnableRowVirtualization="True" ItemsSource="{Binding}" Margin="10,157,10,35" RowDetailsVisibilityMode="VisibleWhenSelected">
<DataGrid.Columns>
<DataGridTextColumn x:Name="tAXColumn1" Binding="{Binding TAX}" Header="TAX" Width="SizeToHeader"/>
</DataGrid.Columns>
</DataGrid>
--XAML.cs--
private void Window_Loaded(object sender, RoutedEventArgs e)
{
TestXXX.ArtDataSet artDataSet = ((TestXXX.ArtDataSet)(this.FindResource("artDataSet")));
// Load data into the table TAX. You can modify this code as needed.
TestXXX.ArtDataSetTableAdapters.TAXTableAdapter artDataSetTAXTableAdapter = new TestXXX.ArtDataSetTableAdapters.TAXTableAdapter();
artDataSetTAXTableAdapter.Fill(artDataSet.TAX);
System.Windows.Data.CollectionViewSource tAXViewSource = ((System.Windows.Data.CollectionViewSource)(this.FindResource("tAXViewSource")));
tAXViewSource.View.MoveCurrentToFirst();
}
Also, my Context is declared separately
namespace TestXXX
{
using System;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
public partial class ArtEntities : DbContext
{
public ArtEntities()
: base("name=ArtEntities")
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
throw new UnintentionalCodeFirstException();
}
public DbSet<BOOK> BOOKs { get; set; }
public DbSet<TAX> TAXs { get; set; }
}
}
and the TAX class is
namespace TestXXX
{
using System;
using System.Collections.Generic;
public partial class TAX
{
public TAX()
{
this.BOOKs = new HashSet<BOOK>();
}
public int ID { get; set; }
public Nullable<decimal> TAX1 { get; set; }
public virtual ICollection<BOOK> BOOKs { get; set; }
}
}
What is wrong with this? How can I fix it?
First of all, I assume you are only in a learning stage, as putting all layers into UI control is not a good idea. Data layer (communication with database) should be separated from model and model should be separated from view. There is of course many other designs, but separation is a core issue in all of them.
As you are using WPF, you should know the ObservableCollection contained in System.Collection.ObjectModel. This collection notifies data user (mostly UI controls in wpf) about changes in collection as adding, removing etc.
So what you need to do is set ItemSource of DataGrid with ObservableCollection. All you need to do next is only add tax item into this collection and save it to the database. Nothing more.
The solution seems to be simple after all...
In the CS file of the Window
public partial class NewTAX : Window
{
ArtEntities db;
private void Window_Loaded(object sender, RoutedEventArgs e)
{
db = new ArtEntities();
dbgrid.ItemsSource = db.TAXs.ToList();
}
... then after adding a new item, just set the ItemSource AGAIN like:
using (MyEntities context = new MyEntities())
{
TAX tax = new TAX();
tax.TAX1 = decimal.Parse(tbTax.Text);
context.TAXs.Add(tva);
context.SaveChanges();
tbTax.Text = "";
dbgrid.ItemsSource = db.TAXs.ToList();
}
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)
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.