First of all this is my first contact with Caliburn.Micro, C# and WPF. I have gone through the Calibur.Micro tutorial and stopped in the moment of "All about actions" and First View subsection. Author wrote the solution for Silverlight application as follow:
public class MefBootstrapper : BootstrapperBase
{
//same as before
protected override void OnStartup(object sender, StartupEventArgs e)
{
Application.RootVisual = new ShellView();
}
//same as before
}
So this is solution how to say bootstrapper which view use as base to show. About WPF I get only enigmatic information:
In this scenario, we simply override OnStartup, instantiate the view
ourselves and set it as the RootVisual (or call Show in the case of
WPF).
So the Silverlight example is very clear for me, we just manually instantiate the proper View to property Application.RootVisual. But is for me totally unclear what is the Show method, which member it is. How to call it.
Thanks for help!
Caliburn.Micro provides a BootstrapperBase class from which you can inherit your own bootstrapper class. It has a virtual method OnStartup which you can override to do the initialization of your shellview. It also provides a utility method DisplayRootViewFor which can be used for displaying the related view for a specified viewmodel type.
So a simple implementation would look like this,
protected override void OnStartup(object sender, StartupEventArgs e)
{
DisplayRootViewFor<TShellViewModel>();
}
where TShellViewModel is the type of your Shell ViewModel. Framework will resolve the view using convention and does the necessary groundwork to display the same. This link will provide a broader picture for a MEF based IOC supported bootstrapper implementation for WPF.
Related
I tried to implement Reactive UI Example using Avalonia with ReactiveUI. The search works, I can print on the console the elements resulting from it and there is a "slot" for each of them in the UI (the lines appear but are empty), but the NuggetDetailView does not show as the list's items.
I have activated View for ViewModel scan in the Initialize method of my Avalonia app :
public class App : Application
{
public override void Initialize()
{
AvaloniaXamlLoader.Load(this);
Locator.CurrentMutable.RegisterViewsForViewModels(Assembly.GetCallingAssembly());
}
....
}
I do not get any error so I'm a bit lost on what I did wrong.
Thank you in advance,
Turns out the reflection-based View scanning was not working.
I changed
Locator.CurrentMutable.RegisterViewsForViewModels(Assembly.GetCallingAssembly());
to
Locator.CurrentMutable.Register(() => new NugetDetailsView(), typeof(IViewFor<NugetDetailsViewModel>));
And it worked
Bellow you can see my bootstrapper. I want to register all the views from the bootstrapper.
When I start the application, WebView and EditView are created. GeneralView is a part of EditView and I have to navigate first to EditView in order to instantiate it.
How can I instantiate all the views when starting the executable?
class Bootstrapper : UnityBootstrapper
{
protected override DependencyObject CreateShell()
{
// Register views
IRegionManager regionManager = this.Container.Resolve<IRegionManager>();
regionManager.RegisterViewWithRegion("ContentRegion", typeof(WebView));
regionManager.RegisterViewWithRegion("ContentRegion", typeof(EditView));
// The following view is instantiated for the first time when I navigate to EditView
regionManager.RegisterViewWithRegion("GeneralRegion", typeof(GeneralView));
return Container.Resolve<MainWindow>();
}
protected override void InitializeShell()
{
Application.Current.MainWindow.Show();
}
protected override void InitializeModules()
{
base.InitializeModules();
}
}
A view shouldn't be instantiated before it is actually being displayed on the screen. Besides, a view should only define the user interface.
If you expect a specific view model to be alive when you are sending an event using the event aggregator from another view model, you are actually introducing an indirect coupling between these two view models. And this is exactly what you want to avoid by using an event aggregator in the first place.
So if you rely on all events being handled, you should probably consider using a shared service that you instantiate as a singleton in the bootstrapper. You could then inject your view models with this shared service and communicate between them through the service interface.
I'd like to add custom handling of method OnBackPressed in Xamarin Android with MvvmCross framework. I've tried something like this:
[Activity(Label = "Table", NoHistory = true)]
public class Table: MvxActivity
{
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
SetContentView(Resource.Layout.View_Table);
}
public override void OnBackPressed()
{
//base.OnBackPressed();
SetContentView(Resource.Layout.View_MainMenu);
}
}
and the app went to MainMenuView but one single button (which directs to TableView) inside this view was disabled.
I've been trying with something like:
protected override void OnResume()
{
SetContentView(Resource.Layout.View_MainMenu);
}
in MainMenuView but it doesn't work. Should I add some piece of code into ViewModels instead of in Views? Or bind somehow events in a layout? If it is possible to handle that kind of behavior, how to achieve that?
You are not using MvvmCross features if you write your code like this.
Just remove "History = true", remove your OnBackPressed() and OnResume() handlers and MvvmCross will handle your back to MainMenu as expected.
When using MvvmCross, you need to use your ViewModels and not your Views to navigate (at least, in a classic scenario).
I am using IRegionManager to load and navigate to views, I have no problem loading content to my main region in my main view which is loaded with my bootstrapper class but I cant load content to regions inside my loaded views, the region manager does not seem to be registering these regions.
my bootstrapper class:
protected override DependencyObject CreateShell()
{
return this.Container.Resolve<MainWindowView>();
}
protected override void InitializeShell()
{
Application.Current.MainWindow.Show();
}
protected override void ConfigureContainer()
{
base.ConfigureContainer();
this.Container.RegisterTypeForNavigation<DocumentView>();
this.Container.RegisterTypeForNavigation<EmailView>();
this.Container.RegisterTypeForNavigation<WorkTypeSelectionView>();
}
the DocumentView is user control with another region the method that runs when the command is triggered is this:
private void ViewEmailAction()
{
NavigationParameters parameters;
parameters = new NavigationParameters();
parameters.Add(nameof(this.CurrentEmail), this.CurrentEmail);
this.regionManager.Regions[this.EmailRegion].RequestNavigate(nameof(EmailView), parameters);
}
This throws and exception with the message "The region manager does not contain the EmailRegion region."
Thanks in advance!
There are two different things going on here:
UserControls:
This should work with not issues whatsoever. Chances are that you are trying to navigate to a region that is defined in a View that hasn't been loaded yet. Make sure you are navigating to a region after it has been loaded. Navigating inside of ViewModel constructors is one of the biggest sources of this problem. If you want to post your sample to GitHub, I can take a look.
ControlTemplates:
This is a known issue in Prism. Here is your fix:
http://southworks.com/blog/2011/11/10/regions-inside-datatemplates-in-prism-v4-using-a-region-behavior/
Can anyone please help me?
I want to use WndProc in WPF but I donĀ“t want to use it in the MainWindow.xaml.cs like this:
public MainWindow()
{
InitializeComponent();
}
protected override void OnSourceInitialized(EventArgs e)
{
base.OnSourceInitialized(e);
HwndSource source = PresentationSource.FromVisual(this) as HwndSource;
source.AddHook(WndProc);
_windowHandle = source.Handle.ToInt32();
}
I want to use it in a different class the reason is that the uEye camera communicates over messages and I need to "catch" them. And because I am using the Main View ViewModel Model I dont want to enter code to the MainWindow.xaml.cs.
MVVM do not say that you cannot write code in the View layer. It say that you have to write code to access Model in ViewModel and try to keep the connection between View and ViewModel as easy as possible (normally with a binding).
In this case you are writing in the view layer code to access to the WndProc that is part of View layer.
So in my opinion your code is perfectly MVVM compliant.