WPF Prism set usercontrol as Shell - wpf

I'm new to WPF Prism, I have seen many online article about Prism and I found all of example code are using windows application as shell, so I have a question, can i let UserControl as a shell? if not why?

The shell is supposed to be a window since a WPF application always has a top-level window (unless hosted in a broswer as an XBAP) but you could set the Content of the window to a user control in the InitializeShell() method of your bootstrapper:
protected override DependencyObject CreateShell()
{
return Container.Resolve<MainWindow>();
}
protected override void InitializeShell()
{
Application.Current.MainWindow.Content = new UserControl();
Application.Current.MainWindow.Show();
}
A UserControl must be hosted in a window or page. It is not a top-level control.

The Window can be opened alone; while the UserControl can’t. That is why the top-level window must be a Window.
The UserControl can also contains Regions. This allows you to nest a UserControl in another UserControl using Regions.

Related

Caliburn.Micro - why uses UserControl instead of Window

My question is exactly like in the title.
I'm starting with Caliburn.Micro for MVVM approach (which also is new for me) and in every tutorial the first step is to remove the default MainWindow.xaml file and create a new UserControl file. Why is that? UserControl does not even accept a Title. Isn't it possible to build application using normal Windows? I already tried that, but with every launch I get error "Cannot find view for ViewModel", although both MainView.xaml and MainViewModel.cs are present. When I created a pair of USerControl and ViewModel for it, everything started to work as expected. So again, why Windows don't work?
It wouldn't really be a problem, but I'm thinking that some additions like Modern UI themes for WPF might not work without a window. I'm not sure of that.
Probably one solution would be to display a defined UserControl View inside of a Window, but it's just a workaround.
You could create your own custom shell window by creating a custom WindowManager:
public class CustomWindowManager : WindowManager
{
protected override Window CreateWindow(object rootModel, bool isDialog, object context, IDictionary<string, object> settings)
{
Window window = new Window();
window.Title = "custom...";
return window;
}
}
...that you register in your bootstrapper:
public class HelloBootstrapper : BootstrapperBase
{
...
protected override void Configure()
{
_container.Singleton<IWindowManager, CustomWindowManager>();
...
}
}

WPF & MVVM, right way to do it

So I am doing my first WPF MVVM app. Just learning the right principle of MVVM, but there are some things that I don't understand ...
I already have several user controls defined.
First question is what is better to use, UserControl or DataTemplates to change content of the MainWindow?
And how to make "Binding" in the "MainWindow.xaml" to change UserControl/DataTemplates when button is pressed?
For example, When "next" button is pressed then contents of main window disappear and content of user control comes on the screen of "MainWindow.xaml".
Maybe with "" binding, to disable it and enable it?
I found some example which function on DataTemplate A Simple MVVM Example. It helped me to implement some things, but I see some discussions over "UserControl" vs. "DataTemplate" and how to do it? So now I am confused :)
I recently made a WPF application with the MVVM pattern, and I did the following:
I have one 'Window', the mainwindow, and in this window all UserControls are loaded.
Every UserControl has a different Viewmodel, for examples a "GeneralSettingsUserControl" has a GeneralSettingsViewModel for validation and databinding.
Every UserControl has its own codebehind where data is bound to its ViewModel
The following code I found on the internet (I don't know the url anymore) but for me it did the trick to change de ContentControl in the mainwindow.
Switcher.cs:
public static mainWindow mainWindow;
public static void switchPage(UserControl p_objNewPage)
{
mainWindow.navigate(p_objNewPage);
}
mainWindow.xaml.cs
public void navigate(UserControl nextPage)
{
PageContent.Children.Clear();
PageContent.Children.Add(nextPage);
PageContent.LastChildFill = true;
}
PageContent is the name of the Grid where the main content is located. In every UserControl you can call the Switcher.switchPage(new UserControl) to change the content of the window. So when you click a button you can call this method.
Hope it helps and good luck.

opening a prism module on new window on a registered region

I have an application with various modules.
I have divided my main shell (xaml) into different regions and now I can load modules on those regions.
But I have requirement where in on click of some button I have to open a new window and then a new module will load on the new window.
I created a new window and I am opening that window , but the window is having a region which the RegionManager of main application does not recognize.
How do I load a module on a region which is not on main window but on child window ?
You can find a quick sample solution for your problem in the following SkyDrive public folder as "RegionInChildWindowWithNavigation":
RegionInChildWindowWithNavigation
Based on my understanding, the problem you mentioned would be related on setting the RegionManager property on the ChildWindow View that cause the defined ModalWindowRegion be reachable from the RegionManager. Below is the ModalDialog ChildWindow view constructor from the aforemention sample. Notice that it also adds an event handler to properly remove all the views in the ChildWindow when closed.
[ImportingConstructor]
public ModalDialog(IRegionManager rm)
{
this.rm = rm;
this.SetValue(RegionManager.RegionManagerProperty, rm);
InitializeComponent();
this.Closed += new EventHandler(WindowsView_Closed);
}
void WindowsView_Closed(object sender, EventArgs e)
{
while (rm.Regions["ModalWindowRegion"].Views.Count() > 0)
{
rm.Regions["ModalWindowRegion"].Remove(rm.Regions["ModalWindowRegion"].Views.FirstOrDefault());
}
}
Then, you would just need to RequestNavigate() to the specified Region which is defined in the ChildWindow view from the RegionManager as follows:
ModalDialogWindow.Show();
rm.RequestNavigate("ModalWindowRegion", new Uri("HelloWorldView", UriKind.Relative));
In addition, you may find useful the following CodePlex threads:
Define Region(s) in Childwindows using Prism + MVVM
Display Child window WPF
I hope this helps.

Should I create separate Bootstrapper for each WPF window?

I am new in WPF and Prism. I'd like to know if I should create new bootstrapper for each new window? For Example I have "Window1" where I select element from ListBox and click button "ShowDetails" and in the new window "Window2" I should see the details of my selection. I have windows and modules for them, but I'd like to know how and where I can register the module "Module2" for "Window2"?
Example of my Bootstrapper.
class Bootstrapper : UnityBootstrapper
{
protected override DependencyObject CreateShell()
{
var mainWindow = new Window1();
mainWindow.Show();
return mainWindow;
}
protected override IModuleCatalog GetModuleCatalog()
{
var moduleCatalog = new ModuleCatalog();
moduleCatalog.AddModule(typeof(Module1));
return moduleCatalog;
}
}
"App.xaml.cs"
public partial class App : Application
{
public App()
{
var bootstrapper = new Bootstrapper();
bootstrapper.Run();
}
}
The Bootstrapper is used usually in the startup class of a WPF Application. Usually this will be the file App.xaml.cs in the standard template, which is the code-behind class of the App.xaml file. You override the method OnStartup and instantiate your Bootstrapper and call its run method. You can delay the startup of the bootstrapper until the override of OnStartup instead of writing this in the constructor of the App.xaml.cs class. You will then use the RegionManager in Prism and define regions in your XAML. If you have multiple independent Windows this is a bit different from the way Prism is intended to be used. There is the concept of a MainWindow or Shell which you define in the CreateShell method of the Bootstrapper class which is available in the Prism source code. Instead, have a main window and define regions and perhaps consider creating a mechanism for displaying additional windows in dialogs. It is possible partition up the MainWindow into multiple regions and inject user controls via the RegionManager. This is done via the activate method of the RegionManager.
Start up by reading the Patterns And Practices Guide and perhaps consider watching the videos of Mike Taulty upon Prism. The first video is here:
Prism & Silverlight: Part 1 - Taking Sketched Code Towards Unity
There are many videos in the video series (10 in total) that will help you get started with PRISM.
An example of how to define a region in XAML is shown next:
<ItemsControl Regions:RegionManager.RegionName="MainRegion" />
A PRISM region can be activated, e.g. through a DelegateCommand or ICommand bound to a button is the following code:
var viewA = new ViewA();
var regionA = (new RegionManager()).Regions["RegionA"];
regionA.Activate(viewA);
You will have to define multiple modules that implement the IModule Interface and add these to your ModuleCatalog as you already have done with ModuleA.

WPF & WinForms Integration and Application Class

I am planning to create a WPF application with a main window which would launch various WinForms. Some of the WinForms use the System.Windows.Forms.Application class (DoEvents, Application.Path, etc). Do you think that there will be a problem in doing this?
Can I still use System.Windows.Forms.Application.DoEvents() from a WinForm that is launched from a WPF application?
The main problem will the ability to instantiate the Windows Forms window and set it's owner to that of the WPF window. The Winforms will want a IWin32Window which a WPF window isn't. To get around this, you need to make a custom class.
I found this code on Mark Rendle's blog (I've copied it here as I had to use the Google Cache to access the page).
LINK - WARNING: May not work
class Shim : IWin32Window
{
public Shim(System.Windows.Window owner)
{
// Create a WindowInteropHelper for the WPF Window
interopHelper = new WindowInteropHelper(owner);
}
private WindowInteropHelper interopHelper;
#region IWin32Window Members
public IntPtr Handle
{
get
{
// Return the surrogate handle
return interopHelper.Handle;
}
}
#endregion
}
and it's method of use:
namespace System.Windows.Forms
{
public static class WPFInteropExtensions
{
public static DialogResult ShowDialog(
this System.Windows.Forms.Form form,
System.Windows.Window owner)
{
Shim shim = new Shim(owner);
return form.ShowDialog(shim);
}
}
}
I haven't tested this code, but reading around the internet, it appears that you can host Winforms windows inside of a WPF app.
I just found this link on MSDN that has a very detailed description of how to interop a Win32 control/window in a WPF application.
Hope these help you out.
I've been doing this sometimes and didn't encounter any problem.
However i don't really recommend it, you should prefer WPF when you are in a WPF Application.
for exemple if you want application path use this :
System.Reflection.Assembly.GetExecutingAssembly().Location

Resources