so I have inherited the development of a WPF application that uses Caliburn.Micro. I have been tasked to extend the application and include some AddIn functionality, I have coded the core logic for the AddIn feature which all works pretty well until I run the application and the shell view informs me that it "Cannot find view for TestViewModel"
Here is my Configure method in the bootstrapper
protected override void Configure()
{
this._log.Debug("-->AppBootstrapper.Configure[ENTER]");
try
{
SplashScreenForm.SplashScreen.Dispatcher.BeginInvoke(
(Action)(() => SplashScreenForm.SplashScreen.Message = "Initializing Container..."));
this._container = new CompositionContainer(new AggregateCatalog(new DirectoryCatalog(".", "*")));
var batch = new CompositionBatch();
SplashScreenForm.SplashScreen.Dispatcher.BeginInvoke(
(Action)(() => SplashScreenForm.SplashScreen.Message = "Initializing Dependencies..."));
batch.AddExportedValue<IWindowManager>(new WindowManager());
batch.AddExportedValue<IEventAggregator>(new EventAggregator());
batch.AddExportedValue(this._container);
this._container.Compose(batch);
}
catch (Exception ex)
{
this._log.ErrorFormat("-->AppBootstrapper.Configure - {0}\n{1}", ex.Message, ex);
throw new Exception(ex.Message, ex);
}
this._log.Debug("-->AppBootstrapper.Configure[EXIT]");
}
I then have two assemblies, AppMain which contains the main application logic (this has a ViewModels and Views folders and these all load fine), I also have an AppAddinTest assembly which contains a test addin, this also contains a ViewModels and Views folder.
My TestViewModel code is:
[Export(typeof(TestViewModel))]
public class TestViewModel : BaseViewModel, ITestViewModel
{
private readonly IEventAggregator _eventAggregator;
private readonly IWindowManager _windowManager;
[ImportingConstructor]
public TestViewModel(IEventAggregator eventAggregator, IWindowManager windowManager)
{
this._eventAggregator = eventAggregator;
this._windowManager = windowManager;
}
}
And the TestView.xaml is:
<UserControl x:Class="Cleo.Windows.Ui.Views.TestView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<TextBlock Text="This is a test view from a different assembly!!"></TextBlock>
</Grid>
</UserControl>
Could anyone shed any light on what I have done wrong please and also why the application is unable to find the view?
I bet you haven't added the assembly on the stage of bootstrapping where your ViewModel resides.
Override SelectAssemblies() in the bootstrapper:
protected override IEnumerable<Assembly> SelectAssemblies() {
var assemblies = new List<Assembly> {
//AddTheAssemblyWhereViewModelsReside
};
return assemblies;
}
Related
I have a Prism 7 / WPF / MVVM app that is configured with AutowireViewModel="True" in the views that have a viewmodel. Most of my view models have dependencies that I have configured in the Prism Unity container and these dependencies are injected into the viewmodel contructor. I do not explicitly create instances of views/viewmodels in the code behind anywhere. I also do not set the data context in XAML i.e. using DataContext element or d:DataContext). The only references in the XAML are to views (i.e. part of the HamburgerMenu control).
All is working fine except each view/viewmodel is ALWAYS constructed twice for some reason, whether this is the main window, or views within modules. I have placed breakpoints in the module managers (only gets hit once) - and also in the view constructors and viewmodel constructors which are both hit twice.
The following is some code for App class and also some code/view/viewmodel for a module named Messaging that is loaded at runtime not on demand. Due to wishing to use the MVVM pattern as much as possible, I have very little code in the code behind of the views. NOTE: I tried to see if this is just an issue with views for modules that are loaded on start up, but the same fate is present for the modules loaded on demand.
The App/PrismApplication class in full:
public partial class App : PrismApplication
{
private ILoggerFactory loggerFactory;
private TaskbarIcon _taskbarIcon;
protected override Window CreateShell()
{
// Register an instance of the Window (used by the dialog service to get a handle on the window when displaying dialogs)
Container.GetContainer().RegisterInstance(typeof(Window), "MainWindow", Container.Resolve<MainWindow>(), new ContainerControlledLifetimeManager());
return Container.Resolve<MainWindow>();
}
protected override void OnInitialized()
{
base.OnInitialized();
// Create the links to each module for the banner view to display
var menuService = Container.Resolve<IMenuService>();
var regionManager = Container.Resolve<IRegionManager>();
menuService.AddItem("Home", "Home", () => regionManager.RequestNavigate("MainRegion", "HomeMainView"));
menuService.AddItem("Messaging", "Messaging", () => regionManager.RequestNavigate("MainRegion", "MessagingMainView"));
menuService.AddItem("Charts", "Charts", () => regionManager.RequestNavigate("MainRegion", "ChartsMainView"));
menuService.AddItem("Admin", "Admin", () => regionManager.RequestNavigate("MainRegion", "AdminMainView"));
// Register banner view with region manager and display it
regionManager.RegisterViewWithRegion("BannerRegion", typeof(BannerView));
// Load the desired module into the main window on start up
Container.Resolve<IRegionManager>().RequestNavigate("MainRegion", "HomeMainView");
}
protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
var container = this.ConfigureLogging(containerRegistry);
// Register types
container.RegisterInstance<IDbConnectionFactory>(
new SqlConnectionFactory(
ConfigurationManager.ConnectionStrings["Messaging"].ConnectionString,
loggerFactory));
/************************************************************/
// TODO: Not sure if need singletons or not - to test......
/************************************************************/
containerRegistry.RegisterSingleton<IMetroMessageDisplayService, MetroMessageDisplayService>();
containerRegistry.RegisterSingleton<IUserService, UserService>();
containerRegistry.RegisterSingleton<IUserStore, UserStore>();
containerRegistry.RegisterSingleton<IMenuService, MenuService>();
containerRegistry.Register<ICustomerService, CustomerService>();
containerRegistry.Register<INotifyIconService, NotifyIconService>();
containerRegistry.RegisterDialog<DefaultDialog, DefaultDialogViewModel>("Default");
containerRegistry.RegisterDialog<HtmlDialog, HtmlDialogViewModel>("Html");
// Get the current user's details - prevent a deadlock in the way we use Task.Run(...).Result
// Then add to container as we will be injecting into VMs
var clientUser = Task.Run(GetCurrentUserDetails).Result;
containerRegistry.RegisterInstance(clientUser);
containerRegistry.RegisterSingleton<IClientUser, ClientUser>();
// Add the task bar icon
_taskbarIcon = (TaskbarIcon)FindResource("NotifyIcon");
containerRegistry.RegisterInstance(_taskbarIcon);
// Create a logger instance
var logger = loggerFactory.CreateLogger<App>();
logger.LogDebug("Finished registering types in App.xaml.cs");
}
private async Task<ClientUser> GetCurrentUserDetails()
{
var userService = Container.Resolve<IUserService>();
var data = await userService.GetClientUsersAsync(ConfigurationManager.AppSettings.Get("TempUserName")).ConfigureAwait(true);
if (!data.Any())
{
// log unable to load user from database then return as no point in loading messages for a user that cannot be found!!
return null;
}
return data.FirstOrDefault();
}
protected override IModuleCatalog CreateModuleCatalog()
{
// We are returning a type that reads the modules from the config file.
return new ConfigurationModuleCatalog();
}
protected override void OnExit(ExitEventArgs e)
{
// The icon would clean up automatically, but this is cleaner
_taskbarIcon.Dispose();
base.OnExit(e);
}
private IUnityContainer ConfigureLogging(IContainerRegistry containerRegistry)
{
// Configure logging - Needed Unity.Microsoft.Logging package
// see https://github.com/unitycontainer/microsoft-logging and https://github.com/unitycontainer/examples/tree/master/src/Logging/Microsoft.Logging
var serilogLogger = new LoggerConfiguration()
.ReadFrom.AppSettings()
.CreateLogger();
this.loggerFactory = new LoggerFactory().AddSerilog(serilogLogger);
var container = containerRegistry.GetContainer();
container.AddExtension(new LoggingExtension(loggerFactory));
return container;
}
}
The messaging module:
public class MessagingModule : IModule
{
public void OnInitialized(IContainerProvider containerProvider)
{
// Register main view with region manager
var regionManager = containerProvider.Resolve<IRegionManager>();
regionManager.RegisterViewWithRegion("MainRegion", typeof(MessagingMainView));
}
public void RegisterTypes(IContainerRegistry containerRegistry)
{
containerRegistry.RegisterSingleton<IMessageStore, MessageStore>();
containerRegistry.RegisterSingleton<IMessageService, MessageService>();
containerRegistry.RegisterSingleton<IChatService, ChatService>();
containerRegistry.RegisterSingleton<IFileDialogService, FileDialogService>();
containerRegistry.RegisterDialog<InboxMessageView, InboxMessageViewModel>("HtmlMessage");
// Here we are loading the config/settings from the app.config for this module so we
// can register a ChatServiceConfiguration type as it is injected into ChatService
var filename = Assembly.GetExecutingAssembly().Location;
var configuration = ConfigurationManager.OpenExeConfiguration(filename);
if (configuration != null)
{
var hubUrl = configuration.AppSettings.Settings["HubUrl"].Value;
if (string.IsNullOrEmpty(hubUrl))
{
throw new ArgumentException("The HubUrl app setting cannot ne null or whitespace.");
}
containerRegistry.RegisterInstance(new ChatServiceConfiguration(hubUrl));
containerRegistry.RegisterSingleton<IChatServiceConfiguration, ChatServiceConfiguration>();
}
}
}
The MessagingMainView:
<UserControl x:Class="Ascensos.Wpf.Modules.Messaging.Views.MessagingMainView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:Controls="http://metro.mahapps.com/winfx/xaml/controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:iconPacks="http://metro.mahapps.com/winfx/xaml/iconpacks"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:materialDesignConverters="clr-namespace:MaterialDesignThemes.Wpf.Converters;assembly=MaterialDesignThemes.Wpf"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:views="clr-namespace:Ascensos.Wpf.Modules.Messaging.Views"
xmlns:helpers="clr-namespace:Ascensos.Wpf.Modules.Messaging.Helpers"
xmlns:prism="http://prismlibrary.com/"
prism:ViewModelLocator.AutoWireViewModel="True"
d:DesignHeight="300"
d:DesignWidth="400"
mc:Ignorable="d">
</UserControl>
The code behind:
public sealed partial class MessagingMainView : UserControl
{
public MessagingMainView()
{
this.InitializeComponent();
}
}
The viewmodel (calls a base message view model class):
public sealed class MessagingMainViewModel
{
public MessagingMainViewModel()
{
}
}
UPDATE: I have removed code from my app, so that only the above code is within the view and viewmodel. The view constructor and viewmodel constructor is still being hit twice during the module initialization.
I do not explicitly create instances of views/viewmodels in the code behind anywhere (i.e. only in XAML).
This is a contradiction - creating a view model in xaml means creating one in the same way as in code behind or anywhere else.
As said before, just don't do it. Remove all references to your view models' constructors from xaml, too (like <DataContext><MyViewViewModel/></DataContext>). To get intellisense in xaml, use d:DataContext.
I have found the issue. It is the following line in App CreateShell() method:
Container.GetContainer().RegisterInstance(typeof(Window), "MainWindow", Container.Resolve<MainWindow>(), new ContainerControlledLifetimeManager());
Commenting this out has sorted the problem. Looking at it again I have been rather silly to not spot this, like the novice I am. This code was added so I could get access to the MainWindow/MetroWindow in a service class - but I will need to try this another way. Thanks for your time #Haukinger.
I'm developing my own application to learn something new. It's WPF .net Core 3.1 app using MVVM pattern.
Recently I've decided to include Microsoft DependencyInjection library.
I've removed StartupUri and modifiec app.xaml.cs:
public IServiceProvider ServiceProvider { get; private set; }
public IConfiguration Configuration { get; private set; }
protected override void OnStartup(StartupEventArgs e)
{
AppDomain.CurrentDomain.AssemblyResolve += OnAssemblyResolve;
InitializeCefSharp();
var builder = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true);
Configuration = builder.Build();
var serviceCollection = new ServiceCollection();
ConfigureServices(serviceCollection);
ServiceProvider = serviceCollection.BuildServiceProvider();
var mainWindow = ServiceProvider.GetRequiredService<MainWindow>();
mainWindow.Show();
}
private void ConfigureServices(IServiceCollection services)
{
services.Configure<AppSettings>
(Configuration.GetSection(nameof(AppSettings)));
// Views
services.AddSingleton<MainWindow>();
services.AddSingleton<SettingsView>();
services.AddSingleton<WwwView>();
services.AddSingleton<BuildingView>();
services.AddSingleton<TroopsMovementsView>();
// ViewModels
services.AddSingleton<MainWindowViewModel>();
services.AddSingleton<SettingsViewModel>();
services.AddSingleton<WwwViewModel>();
services.AddSingleton<DomainViewModel>();
services.AddSingleton<WorldViewModel>();
services.AddSingleton<RegisterViewModel>();
}
I'm setting DataContext inside Views' constructors. All views except MainWindow are UserControl type.
private readonly MainWindowViewModel _mainWindowViewModel;
public MainWindow(MainWindowViewModel mainWindowViewModel)
{
_mainWindowViewModel = mainWindowViewModel;
DataContext = _mainWindowViewModel;
InitializeComponent();
}
private readonly SettingsViewModel _settingsViewModel;
public SettingsView(SettingsViewModel settingsViewModel)
{
_settingsViewModel = settingsViewModel;
DataContext = settingsViewModel;
InitializeComponent();
}
All Views are embedded in MainWindow like this:
<dz:DockControl Grid.Row="3" Loaded="FrameworkElement_OnLoaded">
<dz:DockItem x:Name="Settings" TabText="Settings" ShowAction="{dz:ShowAsDockPositionAction DockPosition=RightAutoHide}">
<views:SettingsView/>
</dz:DockItem>
<dz:DockItem x:Name="WWW" TabText="WWW" ShowAction="{dz:ShowAsDockPositionAction DockPosition=Document}" DefaultDockPosition="Document" >
<views:WwwView/>
</dz:DockItem>
</dz:DockControl>
It's visual studio-like docking library.
The problem is that I got exception during startup, that there's no parameterless constructor. But I can not have any parameterless constructors as I need Views to get ViewModels injected. ViewModels to get repositories injected.
When I've created 2nd ocnstructor which is parameterless, there's strange things happening - Views doesn't load inside MainWindow or load, but doesn't use ViewModels.
If I'm setting DataContext in xaml file, Views got parameterless constructors, but then ViewModels must have parameterless constructors...
<UserControl.DataContext>
<vm:SettingsViewModel/>
</UserControl.DataContext>
How to correctly use Dependency injection in my case?
WPF requires objects which are instantiated in XAML to define a parameterless constructor.
There are many ways to accomplish Dependency Injection in WPF using MVVM. When searching the internet the most wide spread solution seems to be the ViewModelLocator, another Service Locator implementation which is considered widely an anti-pattern (like the infamous static Singleton IoC container).
A simple solution is to use composition. You create a main view model which is composed of other view models where each is dedicated to a certain view.
MainViewModel.cs
class MainViewModel
{
public MainViewModel(IFirstControlViewModel firstControlViewModel ,
ISecondControlViewModel secondControlViewModel)
{
this.FirstControlViewModel = firstControlViewModel;
this.SecondControlViewModel = secondControlViewModel;
}
public IFirstControlViewModel FirstControlViewModel { get; }
public ISecondControlViewModel SecondViewModel { get; }
}
FirstViewModel.cs
class FirstViewModel : IFirstViewModel
{
}
SecondViewModel.cs
class SecondViewModel : ISecondViewModel
{
public SecondVieModel(IThirdViewModel thirdViewModel) => this.ThirdViewModel = thirdViewModel;
public IThirdViewModel ThirdViewModel { get; }
}
MainWindow.xaml
<Window>
<StackPanel>
<FirstUserControl DataContext="{Binding FirstViewModel}" />
<SecondUserControl DataCOntext="{Binding SecondViewModel}" />
</StackPanel>
</Window>
SecondUserControlxaml
<UserControl>
<Grid>
<ThirdUserControl DataContext="{Binding ThirdViewModel}" />
</Grid>
</UserControl>
App.xaml.cs
private void Run(StartupEventArgs e)
{
IMainViewModel viewModel = container.GetExportedValue<IMainViewModel>();
var mainWindow = new MainWindow { DataContext = viewModel };
mainWindow.Show();
}
Or use only top-level composition:
MainViewModel.cs
class MainViewModel
{
public MainViewModel(IFirstControlViewModel firstControlViewModel ,
ISecondControlViewModel secondControlViewModel,
IThirdViewModel thirdViewModel)
{
this.FirstControlViewModel = firstControlViewModel;
this.SecondControlViewModel = secondControlViewModel;
this.ThirdViewModel = thirdViewModel;
}
public IFirstControlViewModel FirstControlViewModel { get; }
public ISecondControlViewModel SecondViewModel { get; }
public IThirdViewModel ThirdViewModel { get; }
}
App.xaml.cs
private void Run(StartupEventArgs e)
{
IMainViewModel viewModel = container.GetExportedValue<IMainViewModel>();
// For simplicity, you can add the view model to the globally accessible App.xaml ResourceDictionary
this.Resources.Add("MainViewModel", viewModel);
var mainWindow = new MainWindow { DataContext = viewModel };
mainWindow.Show();
}
SecondUserControlxaml
<UserControl>
<Grid>
<ThirdUserControl DataContext="{Binding Source="{StaticResource MainViewModel}", Path=ThirdViewModel}" />
</Grid>
</UserControl>
Composition is a very simple solution to use Dependency Injection with views. If performance e.g. classes with a big dependency tree is an issue many DI frameworks like MEF support Lazy<T> exports.
This really should be easy, but I could not establish it.
I have small WPF application with Prism 6
I have Main Window and two views inside it.
MainWindow with MainWindowViewModel view model class
ConfigurationView with ConfigurationViewModel view model class
SignInView with SignInViewModel view model class
Now when show the main window for the first time, I want to select which view to show according to some boolean condition
here is the snippet of the bootstrap class.
protected override void ConfigureViewModelLocator()
{
base.ConfigureViewModelLocator();
ViewModelLocationProvider.Register<MainWindow, MainWindowViewModel>();
ViewModelLocationProvider.Register<SignInView, SignInViewModel>();
ViewModelLocationProvider.Register<ConfigurationView, ConfigurationViewModel>();
Container.RegisterInstance(new SignInView());
Container.RegisterInstance(new ConfigurationView());
}
protected override DependencyObject CreateShell()
{
return Container.Resolve<MainWindow>();
}
protected override void InitializeShell()
{
Application.Current.MainWindow.Show();
IRegionManager _regionManager = Container.Resolve<IRegionManager>();
IRegion _region = _regionManager.Regions[RegionNames.MainRegion];
_region.Add(Container.Resolve<SignInView>());
_region.Add(Container.Resolve<ConfigurationView>());
}
Right now always the SignInView is displayed when the main window of the application is opened?
How can I select which view to show according to some condition which need to be brought from the MainWindowViewModel class ?
Update
public class MainWindowViewModel
{
private IAccountService _accountService;
public MainWindowViewModel(IUnityContainer container)
{
IRegionManager regionManager = Container.Resolve<IRegionManager>();
_accountService = container.Resolve<IAccountService>();
if (_accountService.IsSignedIn)
regionManager.RequestNavigate(RegionNames.MainRegion, new Uri(nameof(ConfigurationView), UriKind.Relative));
else
regionManager.RequestNavigate(RegionNames.MainRegion, new Uri(nameof(SignInView), UriKind.Relative));
}
}
Main Window View
<Window x:Class="Shell.Views.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:prism="http://prismlibrary.com/"
prism:ViewModelLocator.AutoWireViewModel="True">
this code is not working.
The region needs to be created before you can add a view to it. So you'd better create the MainViewModel yourself after the MainWindow has been created:
protected override void ConfigureViewModelLocator()
{
base.ConfigureViewModelLocator();
ViewModelLocationProvider.Register<SignInView, SignInViewModel>();
ViewModelLocationProvider.Register<ConfigurationView, ConfigurationViewModel>();
Container.RegisterInstance(new SignInView());
Container.RegisterInstance(new ConfigurationView());
}
protected override DependencyObject CreateShell()
{
return Container.Resolve<MainWindow>();
}
protected override void InitializeShell()
{
IRegionManager _regionManager = Container.Resolve<IRegionManager>();
IRegion _region = _regionManager.Regions[RegionNames.MainRegion];
_region.Add(Container.Resolve<SignInView>());
_region.Add(Container.Resolve<ConfigurationView>());
var mainWindowViewModel = Container.Resolve<MainWindowViewModel>();
Application.Current.MainWindow.DataContext = mainWindowViewModel;
Application.Current.MainWindow.Show();
}
Remove this from the MainWindow:
prism:ViewModelLocator.AutoWireViewModel="True">
First of all, register the types of your views for navigation, not view instances.
Secondly: conditions - or more general: data - rarely originates from a view model (unless it's user input), so you should have some IUserManagement service to pull the current user from.
But that being said, if you have your view registered, you should be able to navigate to it. Without a concrete exception, it's difficult to guess what's going wrong.
Container.RegisterTypeForNavigation<SignInView>();
...
_regionManager.RequestNavigate( RegionNames.MainRegion, typeof(SignInView).Name );
I have a Prism Shell with two modules. One module is supposed to be the main application mock, MainAppMock, and the other module is supposed to be whatever that main system is using as a region, ModuleOne. Could be one, could be a million module.
The issue is understanding how Prism works. The MainAppModule initializes properly unless I call it's namespace in the Bootstrapper MainWindow.xaml file.
My question: Is this because it is loading the module at run time when I am calling that namespace and therefore Prism doesn't load it because it is already loaded? What is actually happening behind the scenes?
Shell:
class Bootstrapper : NinjectBootstrapper
{
protected override DependencyObject CreateShell()
{
return Kernel.Get<MainWindow>();
}
protected override void InitializeShell()
{
Application.Current.MainWindow = (Window)Shell;
Application.Current.MainWindow.Show();
}
protected override IModuleCatalog CreateModuleCatalog()
{
return new DirectoryModuleCatalog
{
ModulePath = AppDomain.CurrentDomain.BaseDirectory
};
}
}
MainAppMock and ModuleOne are the same except for the name.
ModuleOne Class:
[Module(ModuleName = "ModuleOne.Module")]
public class Module : IModule
{
private readonly IRegionManager _regionManager;
private readonly IKernel _kernel;
public Module(IRegionManager regionManager, IKernel kernel)
{
_regionManager = regionManager;
_kernel = kernel;
}
public void Initialize()
{
}
}
The problem is here. In the Bootstrapper MainWindow:
<Window x:Class="PrismTest.MainWindow"
xmlns:mainAppMock="clr-namespace:MainAppMock;assembly=MainAppMock"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<mainAppMock:MainUserControl />
</Grid>
Note: It works fine if I remove the mainAppMock namespace as mentioned above.
Prism has Modules and Shell. Let's imagine that Shell is TV-Set, consequently, Modules will be channels in TV-Set. At start of program (you turn-on TV-Set) in the method protected override IModuleCatalog CreateModuleCatalog(), you are loading Modules(TV-Set loads your searched channels):
protected override IModuleCatalog CreateModuleCatalog()
{
ModuleCatalog catalog = new ModuleCatalog();
catalog.AddModule(typeof(ModuleZooModule));//Channel about Zoo
catalog.AddModule(typeof(ModuleSportModule));//Channel about Sport
catalog.AddModule(typeof(ModuleProgrammingModule));//Channel about Programming
return catalog;
}
And usually Shell should look like this:
<DockPanel >
<ContentControl Margin="5"
prism:RegionManager.RegionName="{x:Static inf:RegionNames.ContentRegion}"
prism:RegionManager.RegionManager="{Binding RegionManager}"/>
</DockPanel>
The row prism:RegionManager.RegionName="{x:Static inf:RegionNames.ContentRegion}" shows to Prism where Module(video stream of channel) should be injected in your Shell(TV-Set).
But in your case is not eligible to use such things:
<Grid>
<mainAppMock:MainUserControl />
</Grid>
As Prism does not know where Module(some channel) can be shown in your Shell(TV-Set).
After discussing this with a few people we've reached one conclusion.
We are loading the MainAppMock by calling it's namespace:MainUserControl in the Shell MainWindow. When Prism's bootstrapper runs it will go in the AppDomain.CurrentDomain.BaseDirectory and search through the DLLs for anything that inherits from IModule. It realizes that MainAppMock does that, but it is already loaded. It does not make sense to load a DLL that has already been loaded. Therefore, it won't reload it and the Module will never run.
It is worth mentioning that the MainAppMock initialization method is running when the DLL is loaded. We can actually do our Prism Module code there, but that is not recommended.
I have 'TypeNotRegisteredException' when I use 'IUICompositionService' interface in my WPF MVVM Catel application. Below I show how I try to use it. I'm in need of visualizing of 'CalibrationView' view in application MainWindow. To do it I've created a button 'btnShowCalibrationView' in MainWindow of my application, please see XAML below:
<catel:Window x:Class="FlowmeterConfigurator.Views.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:catel="http://catel.codeplex.com"
ResizeMode="CanResize">
<catel:StackGrid x:Name="LayoutRoot">
<catel:StackGrid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</catel:StackGrid.RowDefinitions>
<ToolBar>
<Button Name="btnShowCalibrationView" Content="Flowmeter Calibration" Command="{Binding ShowCalibrationView}"/>
</ToolBar>
</catel:StackGrid>
</catel:Window>
As you see from XAML above this button is binded to 'ShowCalibrationView' command. This command is in MainWindowViewModel.
public class MainWindowViewModel : ViewModelBase
{
public MainWindowViewModel()
{
// Create 'ShowCalibrationView' command.
ShowCalibrationView = new Command(ShowCalibrationViewExecute, ShowCalibrationViewCanExecute);
}
// Declare 'ShowCalibrationView' command.
public Command ShowCalibrationView { get; private set; }
// The command is always allowed to executing.
private bool ShowCalibrationViewCanExecute()
{
return true;
}
// Here is the command logic for visualizing CalibrationView in MainWindow.
private void ShowCalibrationViewExecute()
{
var viewModel = new CalibrationViewModel();
var dependencyResolver = this.GetDependencyResolver();
var uiCompositionService = dependencyResolver.Resolve<IUICompositionService>(); // The error is here!
uiCompositionService.Activate(viewModel, "MainRegion");
}
. . . . . .
}
CalibrationViewModel is in the same 'ViewModels' folder as MainWindowViewModel in the application and 'CalibrationView' is in the same 'Views' folder as MainWindow in application (MainWindow is catel:Window and CalibrationView is catel:UserControl). When I try to execute ShowCalibrationView command then in line of code
var uiCompositionService = dependencyResolver.Resolve<IUICompositionService>();
the following error has place:
The specified type 'Catel.Services.IUICompositionService' is not registered or could not be constructed. Please register type before using it. The type 'Catel.Services.IUICompositionService' is not registered. I have delay in development of my app due to this error. What I'm doing wrong? Please help me eliminate this error.
P.S. I've also tryed to add Bootstrapper class in my application and define the following code there as in https://catelproject.atlassian.net/wiki/display/CTL/Catel.Extensions.Prism#Catel.Extensions.Prism-Activatingaviewintoaspecificregion is shown:
public class Bootstrapper:BootstrapperBase<MainWindow>
{
protected override void ConfigureContainer()
{
base.ConfigureContainer();
if (ServiceLocator.Instance.IsExternalContainerSupported(this.Container))
{
ServiceLocator.Instance.RegisterExternalContainer(this.Container);
}
}
}
but ConfigureContainer method has following error: 'Service locator' does not contain definition for 'Instance'.
Catel automatically registers the types as soon as the assemblies get loaded. But for an assembly to load in .NET, you need to reference at least 1 (non-interface) type in your code, like this:
var name = typeof(UICompositionService).FullName;
Another way is to use the LoadAssembliesOnStartup Fody plugin, which does this automatically for you.