Skip to main content
Home Forums Silverlight Programming Silverlight Controls and Silverlight Toolkit Communication between Page and Detail Views -- Data Awareness Issues
10 replies. Latest Post by JesWang on July 2, 2009.
(0)
Burstaholic
Member
13 points
33 Posts
02-11-2009 12:38 PM |
I have a master/detail Silverlight application based on the Scott Guthrie tutorial. It consists of three list boxes, Customers, Markets and Phone Numbers. My current issue: the detail views to add and edit Markets need to be aware of whether or not there are any other markets belonging to the currently selected Customer that are Spanish markets, and to make use of a list of these if there are.
I need to find the best way to make those detail views aware of this. Since it seems, for instance, that EditMarket.xaml.cs cannot access any information of Page.xaml(.cs), it seems the only way to pass this info is to include it in the DataContext, which entails a fair bit of programming and state-maintenance (changing some object composition, etc.).
My question for here: is there any way to directly acess the list being maintained by the main page from inside the details view, or am I just going to have to pass all this information in DataContext? The first would be much simpler, but it appears impossible. Thanks in advance for your help.
fullsail...
Contributor
3699 points
829 Posts
02-11-2009 1:09 PM |
Hrmm ... Can't you just go App.Current.RootVisual.CustomerList? RootVisual being my main canvas. CustomerList being whichever list you want access.
02-11-2009 3:16 PM |
App.Current.RootVisual. gives me an Intellisense list, but it includes only the members of a RootVisual object, not any of the elements of my main page. Is there a way to access them from here?
sladapter
All-Star
17441 points
3,172 Posts
02-11-2009 3:26 PM |
How did you set the DataContext on the Detail view? If you have a List of Object that populate a Main listbox or DataGrid, When user Select a Item from the main list, you can set that selected DataItem as DataContext to the Detail View. So basically you only have one copy of data shared by two controls. Anything you changed in the Detail View should be reflected in the MainList and vise verse. The detail view shouldn't have to known anything about List page control.
You need to use ObservableCollection to hold your list of data so that adding/removing item from the list will be reflected in the main list. And you need to implement INofitifyProperty for your DataObject and set two-way data binding on all the editable fields in your Detail View.
02-11-2009 4:20 PM |
Ok, a couple of things. This is a database frontend driving/driven by a postgreSQL server through WCF, so any changes made must be saved to the DB, not in the Silverlight app. My understanding is that two-way binding and INotify is handled automatically (mostly) by Service Reference.
you can set that selected DataItem as DataContext to the Detail View.
Exactly. Currently, the selected Customer is the DataContext for AddMarket, and the selected Market is the DataContext for EditMarket. The problem is, currently, neither a Customer object nor a Market object is aware of whether or not this Customer has any Spanish markets, and that is important for both of these things.
I can solve this problem by making the objects aware of this, but that will be a bit complicated and it would be much easier if I could simply make the detail view User Control be the thing which is aware of that.
The detail view shouldn't have to know anything about the List page control
Well, here it does, or at least must appear to. I need to know if there is any way to make this happen directly, or must hack around a Silverlight limitation to create the appearance thereof. Thanks in advance.
02-11-2009 5:26 PM |
It does not matter how you save your data back to DB. You can either send the whole list of data from your List Page or one item back from your DetailView. But you only retain one copy of Data in Silverlight, shared by the List and DatailView.
I don't know how you get your Data. There are more than one way of doing this. If Customer has list of Markets, you can either get the Market list back for each customer when you first retrieve the Customers list (that means you get all the data in one shot), or you can retrieve the Market List for that particular customer only when you select that customer and open the Detail View for that customer.
Depending what you want do, there is a solution (or more than one) for each case.
02-12-2009 2:52 PM |
Ok, it sounds like my initial assumption is correct, that any data needed by the detail view MUST be passed to it using DataContext, and there is no other way for it to communicate with the main page. Is this correct?
02-12-2009 3:04 PM |
No, that is not the only way, but probably a more efficient way. As I said there are a lot of ways of doing List/Detail View, depending on how you want to do it. What do you mean by "or it to communicate with the main page"? You can commnucate from any UserControl to another UserControl within your Silverlight application. Also depending on what you do, there are more answers than one.
For example, you could put your detail view control in the RowDetailsTemplate in the main DataGrid. So you only need to put most of your code(retriving/saving etc.) in the Main page, instead in the DetailView control. You only need to set the binding in the DetailView.
<data:DataGrid x:Name="theGrid" RowDetailsVisibilityMode="VisibleWhenSelected" > <data:DataGrid.RowDetailsTemplate> <DataTemplate> <ScrollViewer Height="200" HorizontalScrollBarVisibility="Auto" HorizontalAlignment="Stretch" > <my:DetailView /> </ScrollViewer> </DataTemplate> </data:DataGrid.RowDetailsTemplate> </data:DataGrid>
If the detail View only display a sublist of the main item (say you want to display MarketList for the customer), you could use a nested DataGrid for this and not even need another DatailView control.
02-13-2009 11:09 AM |
You can commnucate from any UserControl to another UserControl within your Silverlight application.
Could you elaborate on the code to do this? My structure, currently, is like this: Page.xaml is the main page. EditMarket.xaml, etc, are separate User Controls. At the bottom of Page.xaml are a series of entries like this: <PA:EditMarket x:Name="EditMarketView" Visibility="Collapsed" LostFocus="EditMarketView_LostFocus"/>
There are buttons whose action is to change vis from collapsed to visible. That's how I'm implementing master/detail.
You seem to be saying that I CAN programatically access, for instance, the MarketBox listbox that is part of Page.xaml from within EditMarket.xaml.cs. What would this code look like?
02-13-2009 11:59 AM |
Yes, you can access controls in another control as long as that control is in the VisualTree. There are more ways to do this.
Say your Page.xaml control is the Application RootVisual (see App.Xaml.cs Application_Startup function), and you have EditMarket on the Page control. If you really want to access another control on the Page.xaml from EditMarket, you can first find the Page control which is the Application.RootVisual, then you can access other controls on the Page:
Page p = Application.RootVisual as Page;
p.MarketBox // Do something with the MarketBox;
Or you can use VisualTreeHelper.GetParent(this) to find the Parent control of the current control, you can also use VisualTreeHelper.GetChild function to find any child controls for giving control.
But I would not recommand people doing things this way. A good practice for wringing a control is that the control should not have to depend other controls in the page. We should always try to write the control in more generic way so the control can be used anywhere in the application regardless where you put it.
A better way of doing this is to use a public event. Other controls can always subscribe to the event and the respond to the event.
For example if you are saving data to DB on the EditMarket control and you want to tell Page after the saving is done and to refresh other controls on the Page, add a public Event called DataSaved in your EditMarket control.
public event EventHandler DataSaved;
After you saved your data (on the WebServiceCall_Complete event handler) you do this:
void WebServiceCall_Complete(...)
{
...
// Make sure your data is saved
if(DataSaved != null) // if this event is subsribed
DataSaved(this, null);
}
On the Page.XAML whare you use this EditMarket control, hook an event handler to the EditMarket.DataSaved event. Put code in that event handler instead putting the code in the EditMarket control to access Page's other control.
JesWang
4 points
2 Posts
07-02-2009 3:25 AM |
Your Page p = Application.RootVisual as Page; should actually be Page p = Application.Current.RootVisual as Page; Your mistake made me stuck here for so long.