I have a MainWindow which only contains the region for displaying other Views:
<ContentControl Grid.Row="1" prism:RegionManager.RegionName="ContentRegion"/>
What I am trying to do, is to immediately when my MainWindowViewModel loads, to navigate to MainPageViewModel.
I have tried to implement interface INavigationAware such as following:
public void OnNavigatedTo(NavigationContext navigationContext)
{
_regionManager.RequestNavigate("ContentRegion", App.Experiences.DetailPage.ToString());
}
public bool IsNavigationTarget(NavigationContext navigationContext)
{
return true;
}
public void OnNavigatedFrom(NavigationContext navigationContext)
{
_regionManager.RequestNavigate("ContentRegion", App.Experiences.DetailPage.ToString());
}
But even when I set my breakpoints over these, they are never executed.
What am I doing wrong?
EDIT
Maybe I need to change my Bootstrapper logic? Here is how it looks like:
public class Bootstrapper: UnityBootstrapper
{
protected override System.Windows.DependencyObject CreateShell()
{
return Container.TryResolve<MainWindow>();
}
protected override void InitializeShell()
{
Application.Current.MainWindow.Show();
}
protected override void ConfigureContainer()
{
base.ConfigureContainer();
Container.RegisterType(typeof(IDataRepository), typeof(DataRepository), null,new Microsoft.Practices.Unity.ContainerControlledLifetimeManager());
Container.RegisterTypeForNavigation<MainPage>(App.Experiences.MainPage.ToString());
Container.RegisterTypeForNavigation<DetailPage>(App.Experiences.DetailPage.ToString());
}
}
I had to edit my Bootstrapper logic such as following:
protected override void InitializeShell()
{
Application.Current.MainWindow.Show();
Prism.Regions.IRegionManager newRegion = Container.TryResolve<Prism.Regions.IRegionManager>();
newRegion.RequestNavigate("ContentRegion", App.Experiences.MainPage.ToString());
}
Related
My code looks like this:
Bootstrapper.cs
public class Bootstrapper : BootstrapperBase
{
private SimpleContainer _container = new SimpleContainer();
public Bootstrapper()
{
Initialize();
}
protected override void OnStartup(object sender, StartupEventArgs e)
{
base.OnStartup(sender, e);
DisplayRootViewFor<ShellViewModel>();
}
protected override void Configure()
{
_container.Singleton<IEventAggregator, EventAggregator>();
_container.Singleton<IWindowManager, WindowManager>();
_container.RegisterPerRequest(typeof(ShellViewModel), null, typeof(ShellViewModel));
}
protected override object GetInstance(Type service, string key)
{
return _container.GetInstance(service, key);
}
protected override IEnumerable<object> GetAllInstances(Type serviceType)
{
return _container.GetAllInstances(serviceType);
}
protected override void BuildUp(object instance)
{
_container.BuildUp(instance);
}
}
And my ShellViewModel looks like this:
ShellViewModel.cs
public class ShellViewModel : Conductor<Screen>
{
public ShellViewModel
{
var aViewModel = IoC.Get<AViewModel>();
ActivateItem(aViewModel);
}
}
But whenever I run the program, a blank screen is shown. When I debug it, it said that the aViewModel is null.
Is there anything wrong with the Bootstrapper?
Based on the code provided, AViewModel is not registered with the container in the Bootstrapper so IoC does not know it exists, thus it will return null when requested to Get that type
For example
_container.RegisterPerRequest(typeof(AViewModel), null, typeof(AViewModel));
All types that need to be resolved by IoC should first be registered with the backing container.
This should be easy, but its not working for me. I have a view called MainWindowView that contains a view called ChildView. The MainWindowView has a corresponding ViewModel called MainWindowViewModel and the ChildView has a ViewModel called ChildViewModel:
MainWindowView:
<Grid>
<views:ChildView x:Name="ChildView"/>
</Grid>
MainWindowViewModel:
public MainWindowViewModel()
{
ChildView = new ChildViewModel();
}
ChildView:
<Grid>
<Button Content="Edit" x:Name="Edit"/>
</Grid>
ChildViewModel:
public class ChildViewModel
{
public void Edit()
{
}
public ChildViewModel()
{
}
EDIT:
AppBootstrapper:
public class AppBootstrapper : BootstrapperBase
{
private SimpleContainer container;
public AppBootstrapper()
{
Initialize();
}
protected override void Configure()
{
container = new SimpleContainer();
container.Instance(container);
container
.Singleton<IWindowManager, WindowManager>()
.Singleton<IEventAggregator, EventAggregator>();
container.PerRequest<MainWindowViewModel>();
}
protected override void OnStartup(object sender, StartupEventArgs e)
{
DisplayRootViewFor<MainWindowViewModel>();
}
protected override object GetInstance(Type service, string key)
{
return container.GetInstance(service, key);
}
protected override IEnumerable<object> GetAllInstances(Type service)
{
return container.GetAllInstances(service);
}
protected override void BuildUp(object instance)
{
container.BuildUp(instance);
}
protected override void OnUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
{
e.Handled = true;
MessageBox.Show(e.Exception.Message, "An error as occurred", MessageBoxButton.OK);
}
}
and I might add that the views are in a root level Views folder and the view models are in a root level ViewModels folder. Why won't the Edit command fire?
well I am gonna go our on a limb and say that from my experience with CM and say that from what you have a shown there is probably a binding error. What is supposed to happen? Keep in mind CM is not view first out of the box with WPF. Can you show us your bootstrapper?
I was able to fix this by changing the MainWindowView to
<Grid>
<ContentControl x:Name="ChildView" />
</Grid>
Somehow Caliburn.Micro was not able to bind the ChildView to its ViewModel properly. I was confused because the ChildViewModel constructor was being called. I guess that Caliburn.Micro knows how to bind the ContentControl, but not my custom view.
I'm encountering difficulties using Caliburn.Micro in my wpf project: any view's model's code is executed, but the window never shows up. Thus, the OnViewLoaded can show a MessageBox while the window remains invisible.
This is my bootstrapper:
public class Bootstrapper : BootstrapperBase
{
/// <summary>
/// IoC container for dependency injection
/// </summary>
private readonly SimpleContainer _container = new SimpleContainer();
private static Bootstrapper bootstrapper;
public Bootstrapper()
{
Initialize();
ConventionManager.AddElementConvention<PasswordBox>(ZBMS.PasswordHelper.BoundPasswordBox.BoundPasswordProperty, "Password",
"PasswordChanged");
}
protected override void Configure()
{
//Callback for redirecting pressed keys to the corresponding viewmodel
MessageBinder.SpecialValues.Add("$pressedkey", (context) =>
{
var keyArgs = context.EventArgs as KeyEventArgs;
return keyArgs?.Key;
});
// reset settings when debugger is attached (vs obviously)
if (Debugger.IsAttached)
Settings.Default.Reset();
_container.Singleton<IEventAggregator, EventAggregator>();
_container.Singleton<IWindowManager, WindowManager>();
//_Container.Singleton<ISettingsManager, NETSettingsManager>();
_container.PerRequest<LoadingScreenViewModel>();
}
protected override void OnStartup(object sender, StartupEventArgs e)
=> DisplayRootViewFor<LoadingScreenViewModel>();
protected override object GetInstance(Type service, string key)
{
var instance = _container.GetInstance(service, key);
if (instance != null)
return instance;
throw new InvalidOperationException("Could not locate any instances.");
}
protected override IEnumerable<Assembly> SelectAssemblies()
{
return new[]
{
Assembly.GetExecutingAssembly()
};
}
protected override IEnumerable<object> GetAllInstances(Type service)
{
return _container.GetAllInstances(service);
}
protected override void BuildUp(object instance)
{
_container.BuildUp(instance);
}
}
I want to choose which user control to load but my MainWindowView is not even loaded yet so the region manager does not know any regions, How can I achieve this?
my bootstrapper looks like this:
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<WorkTypeSelectionView>();
}
and my viewmodel:
public MainWindowViewModel(IEventAggregator eventAggregator, IRegionManager regionManager)
{
this.eventAggregator = eventAggregator;
this.regionManager = regionManager;
this.AuthenticateUser();
if (this.LoggedUser.AvailableWorkTypes.Count > 1)
{
this.Navigate(nameof(WorkTypeSelectionView));
}
}
private void Navigate(string obj)
{
this.regionManager.RequestNavigate(DefaultContentRegion, obj);
}
thanks in advance!
EDIT:
Guess i was asking the wrong question, found this https://stackoverflow.com/a/7887936/171136 still want to explore other options. Thanks!
You can use View Discovery with regionManager.RegisterViewWithRegion("RegionName", typeof(View));. When the region is created, it will automatically inject the view.
Recently I took an interest in developing PRISM WPF applications. Now I'm trying to load my modules from a DLL I make after building the Modules Project (Wpf User Control Library). During the build of the modules project I copy the DLL in the debug folder (copy: xcopy /y "$(TargetPath)" "$(SolutionDir)FooBar\$(OutDir)Modules\"). Next I configure the bootstrapper and I think there is were I lost it.
I'll attach my code below.
Bootstrapper
public class Bootstrapper : UnityBootstrapper
{
protected override DependencyObject CreateShell()
{
var shell = ServiceLocator.Current.GetInstance<Shell>();
return shell;
}
protected override void InitializeShell()
{
base.InitializeShell();
App.Current.MainWindow = (Window)this.Shell;
App.Current.MainWindow.Show();
}
protected override IModuleCatalog CreateModuleCatalog()
{
return base.CreateModuleCatalog();
}
protected override void ConfigureModuleCatalog()
{
var moduleCatalog = new DirectoryModuleCatalog();
moduleCatalog.ModulePath = Environment.CurrentDirectory + #"\Modules";
ModuleCatalog = moduleCatalog;
}
protected override void InitializeModules()
{
base.InitializeModules();
}
protected override ILoggerFacade CreateLogger()
{
return base.CreateLogger();
}
}
Shell.xaml.cs
protected readonly IModuleCatalog _moduleCatalog;
public Shell(IModuleCatalog moduleCatalog)
{
this._moduleCatalog = moduleCatalog;
InitializeComponent();
}
App.xaml.cs
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
var bootstrapper = new Bootstrapper();
bootstrapper.Run();
}
ViewModelBase
public abstract class ViewModelBase : INotifyPropertyChanging, INotifyPropertyChanged,IModule
{
//Implementation INotify etc..
public void Initialize()
{
}
}
So I'm wondering why my ModuleCatalog.Modules is always 0. Can someone help me out ?
Is your module catalog null? or contains no module?
check that Environment.CurrentDirectory + #"\Modules"; returns the correct path and all DLL are in.
Do you really need to load them from dir? Don't you know which modules will be loaded?
I usualy do that:
public partial class Bootstrapper: UnityBootstrapper
{
protected override void ConfigureContainer()
{
base.ConfigureContainer();
}
protected override IModuleCatalog CreateModuleCatalog()
{
// Create the module catalog from a XAML file.
return Microsoft.Practices.Prism.Modularity.ModuleCatalog.CreateFromXaml(new Uri("/Shell;component/ModuleCatalog.xaml", UriKind.Relative));
}
protected override DependencyObject CreateShell()
{
// Use the container to create an instance of the shell.
ShellView view = Container.TryResolve<ShellView>();
// Display the shell's root visual.
//view.ShowActivated = false;
view.Show();
return view;
}
}
and my modulecatalog
<prism:ModuleCatalog xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:prism="clr-namespace:Microsoft.Practices.Prism.Modularity;assembly=Microsoft.Practices.Prism">
<prism:ModuleInfo Ref="Connexion.dll"
ModuleName="Connexion"
ModuleType="Connexion.ModuleInit, Connexion, Version=1.0.0.0" />
<prism:ModuleInfo Ref="Tools.dll"
ModuleName="Tools"
ModuleType="Tools.ModuleInit, Tools, Version=1.0.0.0" />
<prism:ModuleInfo Ref="DrawingModule.dll"
ModuleName="DrawingModule"
ModuleType="DrawingModule.ModuleInit, DrawingModule, Version=1.0.0.0"
InitializationMode="WhenAvailable">
<prism:ModuleInfo.DependsOn>
<sys:String>Connexion</sys:String>
<sys:String>Tools</sys:String>
</prism:ModuleInfo.DependsOn>
</prism:ModuleInfo>
<prism:ModuleInfo Ref="Sis.dll"
ModuleName="Sis"
ModuleType="Sis.ModuleInit, Sis, Version=1.0.0.0"
InitializationMode="WhenAvailable">
<prism:ModuleInfo.DependsOn>
<sys:String>Connexion</sys:String>
<sys:String>Tools</sys:String>
<sys:String>DrawingModule</sys:String>
</prism:ModuleInfo.DependsOn>
</prism:ModuleInfo>
and all modules have the buildAction: copy "$(TargetPath)" "$(SolutionDir)Shell\$(OutDir)"