I am working on a WPF PRISM application that has the following structure (I have simplified to explain better without additional layers). I am using Unity as my DI/IOC
AppMain - Bootstrapper
Gui - Views and View Models
Data - Data using EF.
In Gui, I have views names as below:
Home
EmployeesView
OrdersView
Reports
I have three regions in the shell.
MainRegion - Main Content
TopRegion - Navigation Menu
BottomRegion - Status Bar
I am using the following method to register views to the regions
IRegion region = _regionManger.Regions[RegionNames.MainRegion];
var mainView = _container.Resolve<Home>();
region.Add(mainView, ViewNames.HomeViewName);
region.Activate(mainView);
The first of activation happens in the Module Initialize method for Top, Main and Bottom.
After this, I am activating other views when the button are clicked. It is just code behind for now. Sample code here:
IRegion region = _regionManger.Regions[RegionNames.MainRegion];
var reportView = region.GetView(ViewNames.ReportsViewName);
if (reportView == null)
{
reportView = _container.Resolve<ReportsView>();
region.Add(reportView, ViewNames.ReportsViewName);
region.Activate(reportView);
}
else
{
region.RequestNavigate(ViewNames.ReportsViewName);
}
PROBLEM1: Any advise on how this can be done or the way I am doing is fine.
The top menu has Home, Employees, Orders, Reports buttons.
In the home page I have recent orders by the employee in datagrid as readonly.
I would like to double click to navigate to the OrderView and pass the selected order to show to the user. PROBLEM2 I am not sure where to do the navigation for this.
PROBLEM3: Another issue was if set the RegionMemberLifeTime keepAlive false, INavigationAware methods don't fire. If I don't set the KeepAlive to false, the page does not get refreshed because, the view model does not get called.
I need the pages to refresh when it is navigated to and not be stale and also handle any confirm prompts to the user when the view is navigated away from it.
Your help is very much appreciated.
it's certainly too late but…
Problem 1/2: is there a particular reason why you add content to region in module initializer?
the common way is more like -> in xaml:
<ContentControl prism:RegionManager.RegionName="MainRegion" />
and in ModuleInit.cs -> Initialize()
_regionManager.RegisterViewWithRegion("MainRegion", () => _container.Resolve<MainView>());
Problem 3:
the view has to implements INavigationAware, IRegionMemberLifetime
and to swich region, in the viewModel you do:
_regionManager.RequestNavigate("RegionWhatever", new Uri("TestView", UriKind.Relative));
But to work you have to register it in ModulInit.cs as an object with viewName, like that:
_container.RegisterType<Object, TestView>("TestView");
and a contentControl with the correct RegionName define in xaml of course
Related
I'm currently developing a WPF application using the MVVM framework. And I have this functionality:
I have a main window which has a combo box and frame (where I put my pages) and a view model. One of the pages in that frame is where a user can add a data and these data are used to populate the combo box in the main window. My problem is how to automatically update the items in the combo box after adding a data from that page. Btw, this page has a different view model too.
Thanks.
You can establish an event in the page viewmodel for changed data. Then subscribe to those events within the window viewmodel and update the combobox items accordingly.
You have access to the parent window from iframe via window.top. You have to write this code in your page what you have loaded in iFrame.
window.top.document.getElementById("combobox_element_id").value='Your New Value';
best of luck
You can pass the Source DataContext of ComboBox (ObservableCollection) to page ViewModel so you can simply modify the collection from Page view model.
I started to use Prism (5.0) some days ago and now I run into a problem I cant solve myself.
I used the quickstart "viewswitchingnavigation".
So I have a shell with a navigation and a main panel/region.
Navigation region holds some radiobuttons to switch the views that are split into view and viewmodel with a service based model.
View A shows a collection of documents with a button each to open a new view B for this document's details.
A button in this detailview should start a part of code. This code moves some data what takes quite a while since the data need to be parsed. Since the user shouldnt wait for a nonreactiong window I want to show some information about the status of the running code. (Example: Getting data 1/3012, which is updated with each new got data piece). This code gets one piece of data at a time so I could send(?) some information to the view to update the status there (if I knew how)
So.
How to implement the button that starts the "external" code?
How to access the current view (e.g. to change the status shown in a loader or in a textbox like destribed above.
You could use a BackgroundWorker class which has built-in progress reporting functionality. Alternatively, you could create your own asynchronous data retreiving mechanism by using async / await and Tasks.
For your progress displaying view you could use the State-Based Navigation provided by Prism. You could display an on-top view with a progress bar or text box showing the progress. As usual, the UI elements of the view should be bound to the view model's properties. To update these UI properties you should use Dispatcher.Invoke(), or SynchronizationContext, or similar sync mechanism, because your progress reporting method (or event) will be called by a background thread.
If you could post your code, then my answer could be more specific.
Not exactly sure what you aim for, though here are two options:
Shall the data begin to be fetched when the View/Windows gets loaded? Then your ViewModels have to implement INavigationAware interface and INavigationAware.OnNavigatedTo (and From) Method). You can mark that method as async to be able to use await within it.
public async void INavigationAware.OnNavigatedTo(NavigationContext navigationContext)
{
await LongRunningTask();
}
public async Task LongRunningTask()
{
foreach(var dataChunk in allData)
{
// Status Text is a property which raises OnPropertyChanged when changed and which you databind to a textbox
StatusText = string.Format("Getting Data {0}", dataChunk.Description);
await ProcessDataChunk(dataChunk);
}
}
Or if you want it happen on an user action, you do it via an async ICommand.
private ICommand processCommand;
public ICommand ProcessCommand)
{
return processCommand??(processCommand = DelegateCommand.FromAsyncHandler(this.LongRunningTask));
}
I have regions within a TabControl that load fine when I click the tab headers but I cannot set a default view when the page initially loads.
Ex: If I have 3 tabs, I want the first one loaded by default. Easiest way to do this?
After InitializeComponent() in the constructor
TabControl.SelectedItem = TabControl.Items[0];
Did not test it though
I am developing a website that contains a number of "forms" for entering data, etc, and I plan on using Silverlight and RIA Services for managing the data within these forms. The rest of the site will be normal HTML/CSS/JavaScript.
The plan was to create a single Silverlight control with many pages and each page would represent a single form. A HTML page would display this control, but would display a specific page within the Silverlight control.
So, my questions are:
When embedding a Silverlight control within a HTML page how would have the control automatically navigate to a specific page?
After loading a HTML page, and display the Silverlight control, would it be possible to have some JavaScript tell the Silverlight control to navigate to another page?
1 - Silverlight uses URL bookmarks on the end of the URL to emulate navigation.
e.g. http://somesite.com/somepage.aspx#formname
You can also override the default behaviour of the navigation so that it can do cool things like use the bookmark parameter to dynamically specify the name of the Silverlight form you want to show.
2 - You would only need to ensure the bookmark part of your site URLs contain something the Silverlight application can interpret.
Lookup the INavigationContentLoader interface for examples of overriding the navigation with custom behaviour.I found a few articles on the subject quite easily. Try this one.
After a bit of searching I found that the "object" tag that defines the Silverlight control in HTML can have a "initParams" element within it.
So, my thought is each page that I create will only ever have one "form" therefore in the "object" tag I just set "initParams" to define which page the Silverlight control should set as the "RootVisual".
When the control loads the Application_Startup will look at the "initParams" and use that to determine what page it needs to create and assign it to the RootVisual property of the application.
James
1) One of the solutions (not the best one) would be like this:
private void Application_Startup(object sender, StartupEventArgs e)
{
var page = HtmlPage.Document.QueryString["Page"];
RootVisual = GetPage(page);
}
private UIElement GetPage(string page)
{
switch (page)
{
case "page1": return new Page1();
case "page2": return new Page2();
default: return new PageNotFound();
}
}
2) If you want to interact Silverlight control with HTML (JavaScript), then
this is called a 'Silverlight HTML bridge':
HTML Bridge: Interaction Between HTML and Managed Code
I have a navigation app with 5 pages. I also have a usercontrol with 3 radio buttons. This usercontrol is used by all 5 pages in my app. By default the first radio button is selected. However if the user clicks the 3rd radio button and I go to another page I want my usercontrol to still show that 3rd radio button as selected. How do I go about accomplishing this task?
There are several ways you could do this. Probably the most simple way is to create a class that has a property for the selected item of the radio buttons. Add an instance of this class as a resource to the application and then bind the radio buttons to this static resource.
public class MyState
{
public string SelectedRadioValue {get;set;}
}
In the App.xaml.cs in the Application_Startup add:
var state = new MyState()
Resources.Add("myState", state);
Then in the bindings you can set:
SelectedValue="{Binding Source={StaticResource myState},Path=SelectedRadioValue}"
There are other approaches you could take as well.
Is it possible to show this control outside of the View control? It sounds like it should be placed on the MainPage.xaml outside of the place where the views are displayed. This way the one control is used and its value can be made available to all of the views.
If you are just looking to save the state of the page as the user navigates between pages then the easiest way of accomplishing this is to set:
NavigationCacheMode="Required"
in the first element of the xaml for your page.