I'm using Prism Unity, I have an abstract RecordViewModel : BindableBase, RecordListViewModel : RecordViewModel, and RecordUpdateViewModel: RecordViewModel, INavigationAware. There is also a separate Navigation Module and my MainWindow has 2 regions, NavigationRegion and ContentRegion. All RecordViews reside in ContentRegion. For whatever reason, whether I make a GoBack button or click on a button in the NavigationRegion, I cannot leave the Update view. I have narrowed down that the problem is in the ViewModel and that I'm missing something for INavigationAware. Please tell me what I'm missing or did wrong, thank you.
public class RecordUpdateViewModel : RecordViewModel, INavigationAware
{
private IRegionNavigationJournal navigationJournal;
public RecordUpdateViewModel(IRecordService context) : base(context)
{
}
public bool IsNavigationTarget(NavigationContext navigationContext)
{
return false;
}
public void OnNavigatedFrom(NavigationContext navigationContext)
{
throw new NotImplementedException();
}
public void OnNavigatedTo(NavigationContext navigationContext)
{
//irrelevant to problem logic to bring in Record.Id
navigationJournal = navigationContext.NavigationService.Journal;
}
}
Edit
Just incase I screwed up elsewhere here's my registrations in the module.cs
container.RegisterType<IRecordService, RecordService>();
container.RegisterTypeForNavigation<RecordListView>();
container.RegisterTypeForNavigation<RecordUpdateView>();
regionManager.RegisterViewWithRegion("ContentRegion", typeof(RecordListView));
regionManager.RegisterViewWithRegion("ContentRegion", typeof(RecordUpdateView));
I navigate to the views with regionManager.RequestNavigate("ContentRegion", "RecordUpdateView", parameter) and if I don't use INavigationAware on the UpdateView, all buttons work, but when I put it back on I can't navigate away.
Edit2
Here is the XAML for the ListView that navigates to the UpdateView and the bound command
<UserControl x:Class="App.Record.Views.RecordListView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:prism="http://prismlibrary.com/"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300"
prism:ViewModelLocator.AutoWireViewModel="True">
<DockPanel>
<WrapPanel>
<Button Content="Edit"
Command="{Binding EditCommand}"/>
</WrapPanel>
<DataGrid>
<--Irrelevant-->
</DataGrid>
</DockPanel>
</UserControl>
Command
private DelegateCommand editCommand;
public DelegateCommand EditCommand => editCommand ?? (editCommand = new DelegateCommand(EditRecord));
private const string RecordID = "RecordID";
void EditCommand()
{
var parameter = new NavigationParameters();
parameter.Add("RecordID", SelectedRecord.ID);
regionManager.RequestNavigate("ContentRegion", "RecordUpdateView", parameter);
}
Commands for the Navigation menu buttons work the same, and any view not using INavigationAware can be navigated away from.
INavigationAware has nothing to do with navigating from view to view. It simply give you an easy way to pass parameters between the view. I think what you're looking for is something called IRegionManager then you can do somehting like regionManager.NavigateTo(regionName,viewName) you will have to register the view with your container. Something like container.RegisterType<object,Views.View>(ViewNames.ViewName); and of course ViewNames.ViewName is a constant string with the name of the view.
I shall hang my head in shame... look to the OnNavigatedFrom... and all 3 INavigationAware Members for anyone else that looks to this... and remove the NotImplementedExceptions that are auto generated. If you don't need that void, it has to be there so INavigationAware doesn't yell at you for not fully implementing it, but there doesn't have to be any logic in those voids if you don't need them.
Related
I'm new to Prism and trying to make a simple modular app with it (see the full code).
I'm actually trying to pass a parameter to a view, so in the ModuleAViewViewModel of the ModuleAView I'm implementing INavigationAware, this way:
public class ModuleAViewViewModel : BindableBase, INavigationAware
{
private int passedId;
public int PassedId
{
get => passedId;
set => SetProperty(ref passedId, value);
}
// In the following 3 methods, a breakpoint never gets hit.
public bool IsNavigationTarget(NavigationContext navigationContext)
{
return true;
}
public void OnNavigatedFrom(NavigationContext navigationContext)
{
}
public void OnNavigatedTo(NavigationContext navigationContext)
{
PassedId = (int)navigationContext.Parameters["Id"];
}
}
This is the corresponding ModuleAView.
<UserControl x:Class="ModularSample1.Modules.ModuleA.Views.ModuleAView"
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"
xmlns:local="clr-namespace:ModularSample1.Modules.ModuleA.Views"
xmlns:viewmodels="clr-namespace:ModularSample1.Modules.ModuleA.ViewModels"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<UserControl.Resources>
<viewmodels:ModuleAViewViewModel x:Key="moduleAViewModel"/>
</UserControl.Resources>
<Grid DataContext="{StaticResource moduleAViewModel}">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<TextBlock
Grid.Row="1"
Text="{Binding PassedId, StringFormat='Passed Id: {0}'}"
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontSize="34"/>
</Grid>
</UserControl>
And the ViewModel that actually navigates to that view looks like this:
public class MainWindowViewModel : BindableBase
{
private readonly IRegionManager regionManager;
public MainWindowViewModel(IRegionManager regionManager, IModuleManager moduleManager)
{
this.regionManager = regionManager;
moduleManager.Run();
Modules = moduleManager.Modules.ToList();
}
private List<IModuleInfo> modules;
private IModuleInfo selectedModule;
public List<IModuleInfo> Modules
{
get => modules;
set => SetProperty(ref modules, value);
}
public IModuleInfo SelectedModule
{
get => selectedModule;
set
{
if (SetProperty(ref selectedModule, value))
{
var Id = new Random().Next(1, 12);
var navigationParameters = new NavigationParameters
{
{ "Id", Id }
};
regionManager.RequestNavigate(
"SelectedModuleRegion",
$"{selectedModule.ModuleName}View",
navigationParameters);
}
}
}
}
What I'm missing here?
You define the view model for your ModuleAView in its Resources and set it on a child Grid via reference. Prism looks for the DataContext on the view itself to call a view model that implements INavigationAware, not a child control, so it does not find your view model. From the documentation:
During navigation, Prism checks to see whether the view implements the INavigationAware interface; if it does, it calls the required methods during navigation. Prism also checks to see whether the object set as the view's DataContext implements this interface; if it does, it calls the required methods during navigation.
In order to make it work, set the data context directly on the ModuleAView and remove it from Grid.
<UserControl x:Class="ModularSample1.Modules.ModuleA.Views.ModuleAView"
...>
<UserControl.DataContext>
<viewmodels:ModuleAViewViewModel/>
</UserControl.DataContext>
<Grid>
<!-- ...grid definitions. -->
</Grid>
</UserControl>
A better alternative is to remove setting the data context manually completely from your ModuleAView and register your ModuleAView directly with ModuleAViewViewModel. Prism's navigation service will automatically resolve the view model during navigation and assign it as data context.
containerRegistry.RegisterForNavigation<ModuleAView, ModuleAViewViewModel>();
You can even simplify this, by following the naming conventions for views and view models regarding the ViewModelLocator, which will be used in navigation to resolve view models for views.
ViewModels are in the same assembly as the view types
ViewModels are in a .ViewModels child namespace
Views are in a .Views child namespace
ViewModel names correspond with view names and end with "ViewModel.
You violate the last rule, so renaming ModuleAViewViewModel to ModuleAViewModel and just removing the manual setting of the data context will enable Prism to automatically find the corresponding view model for the view that you registered with RegisterForNavigation.
containerRegistry.RegisterForNavigation<ModuleAView>();
Folder structure -
Project Named 'Home'
|> Views > HomeView.xaml
|> ViewModels > HomeViewModel.cs
|> HomeModule.cs (an IModule class)
HomeView.XAML (Note: AutoWireViewModel is set to FALSE)
<UserControl
x:Class="Tally.Sync.Home.Views.HomeView"
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:local="clr-namespace:Tally.Sync.Home.Views"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:prism="http://prismlibrary.com/"
d:DesignHeight="450"
d:DesignWidth="800"
prism:ViewModelLocator.AutoWireViewModel="False"
mc:Ignorable="d">
<Grid>
<TextBlock
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontSize="28"
Text="{Binding Message}" />
</Grid>
</UserControl>
HomeViewModel.cs
public class HomeViewModel : BindableBase
{
private string _message = "Hi There!";
public string Message
{
get { return _message; }
set { SetProperty(ref _message, value); }
}
public HomeViewModel()
{
}
}
HomeModule.cs
public class HomeModule : IModule
{
private readonly IRegionManager _regionManager;
public HomeModule(IRegionManager regionManager)
{
_regionManager = regionManager;
}
public void OnInitialized(IContainerProvider containerProvider)
{
_regionManager.RegisterViewWithRegion("ContentRegion", typeof(HomeView));
}
public void RegisterTypes(IContainerRegistry containerRegistry)
{
ViewModelLocationProvider.Register<HomeView, HomeViewModel>();
}
}
As you can see I am registering the HomeView & HomeViewModel with the ViewModelLocationProvider. But this doesn't work. My code is running as expected when the AutoWireViewModel is set to True
What am I doing wrong? I know I can auto wire it, but I am trying to learn Prism and one of videos by Brian Lagunas mentions wiring manually is faster as reflection won't be required.
When you register views and view models manually to the view model locator, you still have to enable auto-wiring in the view model, it will just change how the ViewModelLocator resolves the view and its view model. Setting False will disable it, so it does not resolve anything.
prism:ViewModelLocator.AutoWireViewModel="True"
As you can see from the reference source for ViewModelLocationProvider, registered views will be checked first when resolving the view model. If there are no registrations, the fallback to resolving with the naming convention via reflection will be used.
public static void AutoWireViewModelChanged(object view, Action<object, object> setDataContextCallback)
{
object viewModel = GetViewModelForView(view);
if (viewModel == null)
{
// Try to resolve the view model via regsitrations
var viewModelType = GetViewModelTypeForView(view.GetType());
// If views and view models are not registerd, fallback to reflection
if (viewModelType == null)
viewModelType = _defaultViewTypeToViewModelTypeResolver(view.GetType());
//...
}
// ...
}
As the ViewModelLocator will resolve the view both via registration or the naming convention fallback, you did not notice a difference. If you rename your HomeViewModel to HomeFooBar or anything else that does not fit the naming convention, the fallback will fail and you will see that it works as described above.
[...] wiring manually is faster as reflection won't be required.
I think that there are many misunderstandings concerning reflection. In this case with a few views you will not even notice any difference and it is much more convenient. Do not optimize prematurely.
I'm very new to WPF but quite experienced with .NET and C#. I am trying to create (what I though would be) a fairly simple CRUD admin desktop application for a website I plan on building.
WPF seems to be way more complicated than I expected it to be and after lots of Googling I've basically realised that everyone uses the MVVM pattern - fine. Now, with my existing .NET experience, I know I definitely want to to be using dependency injection. I've discovered that everything seems to be done within the ViewModel in WPF, including all the services and everything - fine again.
Now, onto my problem. I have set up a basic tab control and I'm binding the tab values to an enum using Enum.GetValues(). I want the view to change when I select a tab and the view will depend on which tab is selected. The problem is, I can't seem to get the view to show - it just shows a blank screen. The view is a custom UserControl I've created and defined as a resource and contains a grid and a bunch of buttons and stuff. I've omitted this from below as it doesn't seem relevant.
My MainWindow.xaml is pretty simple and looks like this:
<Window x:Class="Stc.Admin.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:viewmodels="clr-namespace:Stc.Admin.ViewModels"
xmlns:views="clr-namespace:Stc.Admin.Views"
xmlns:local="clr-namespace:Stc.Admin"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<TabControl ItemsSource="{Binding Tabs}" SelectedItem="{Binding CurrentTab}">
<TabControl.Resources>
<DataTemplate DataType="{x:Type viewmodels:GamesViewModel}">
<views:Games />
</DataTemplate>
</TabControl.Resources>
<TabControl.ContentTemplate>
<DataTemplate>
<ContentControl Content="{Binding DataContext.CurrentViewModel, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type TabControl}}}" />
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
</Grid>
</Window>
Here's my MainViewModel.cs:
public class MainViewModel
{
private readonly IViewModelFactory<GamesViewModel> _gamesViewModelFactory;
private ViewType _currentTab;
public ViewType CurrentTab
{
get
{
return _currentTab;
}
set
{
_currentTab = value;
ChangeView(_currentTab);
}
}
public ObservableCollection<ViewType> Tabs { get; }
public ViewModelBase CurrentViewModel { get; set; }
public MainViewModel(IViewModelFactory<GamesViewModel> gamesViewModelFactory)
{
_gamesViewModelFactory = gamesViewModelFactory;
Tabs = new ObservableCollection<ViewType>(Enum.GetValues(typeof(ViewType)).Cast<ViewType>().ToArray());
}
private void ChangeView(ViewType viewType)
{
switch (viewType)
{
case ViewType.Games:
CurrentViewModel = _gamesViewModelFactory.CreateViewModel();
break;
case ViewType.Listings:
break;
case ViewType.Users:
break;
case ViewType.Languages:
break;
case ViewType.Currencies:
break;
default:
break;
}
}
}
public enum ViewType
{
Games,
Listings,
Users,
Languages,
Currencies
}
GamesViewModel has service dependencies so it needs to be created using the factory.
And my DI setup in App.xaml.cs:
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
IServiceProvider serviceProvider = this.createServiceProvider();
Window window = new MainWindow();
window.DataContext = serviceProvider.GetRequiredService<MainViewModel>();
window.Show();
base.OnStartup(e);
}
private IServiceProvider createServiceProvider()
{
IServiceCollection services = new ServiceCollection();
services.AddDbContext<StcContext>(options =>
options.UseSqlServer(#"Server=(localdb)\mssqllocaldb;Database=Stc;Integrated Security=True"));
services.AddSingleton<ICrudService<Game>, CrudService<Game>>();
services.AddSingleton<IViewModelFactory<GamesViewModel>, GamesViewModelFactory>();
services.AddScoped<MainViewModel>();
return services.BuildServiceProvider();
}
}
I have sorted this issue now. Being new to WPF, I didn't realise that I have to use INotifyPropertyChanged to get the UI to update after changing a property value on my ViewModel. I'd seen this used in a lot of the articles and tutorials I was seeing but didn't really understand what it was or how to apply it to my application.
The change I made was to implement this interface on my base ViewModel like so:
public class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
I then change my MainViewModel to inherit from the base class and changed the setter of the CurrentTab property to call OnPropertyChanged (with the name of the property) after I've changed the view/viewmodel property:
private ViewType _currentTab;
public ViewType CurrentTab
{
get
{
return _currentTab;
}
set
{
_currentTab = value;
ChangeView(_currentTab);
OnPropertyChanged(nameof(CurrentViewModel));
}
}
I believe this is telling the UI that something has changed and it needs to redraw itself. Correct me if I'm wrong or if that's an oversimplification.
Answer
OK so adding the suggested code given by E-Bat didn't have any affect until I started a new project and copied all the code across verbatim. I can only assume there must be some background code within the ViewModelLocator on http://prismlibrary.com/ which did not update to take the parameterless constructor into account. Hope this helps anyone else with the same issue
Original Question
I have set up a MVVM project using prism. I have a MainWindow.xaml and 5 Views; ButtonsView, HeaderView, ProcessInputView, ProcessLogView and ProcessSelectionView which I am using, each View has an associated ViewModel.
MainWindow.xaml
<Window x:Class="TransactionAutomationTool.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:local="clr-namespace:TransactionAutomationTool"
xmlns:views="clr-namespace:TransactionAutomationTool.Views"
xmlns:prism="http://prismlibrary.com/"
prism:ViewModelLocator.AutoWireViewModel="True"
mc:Ignorable="d"
Title="MainWindow" Height="600" Width="800">
<Grid>
<views:HeaderView x:Name="HeaderViewControl" Margin="20,21,0,0" />
<views:ProcessSelectionView x:Name="ProcessSelectionViewControl" Margin="20,119,0,0" />
<views:ProcessInputView x:Name="ProcessInputViewControl" Margin="20,280,0,0" />
<views:ProcessLogView x:Name="ProcessLogView" Margin="298,105,0,0" />
<views:ButtonsView x:Name="ButtonViewControl" Margin="0,513,0,0" />
</Grid>
MainWindowViewModel
public class MainWindowViewModel: BindableBase
{
public IEventAggregator _events;
private UserPrincipal userPrincipal;
public MainWindowViewModel(IEventAggregator events)
{
_events = events;
userPrincipal = UserPrincipal.Current;
_events.GetEvent<HeaderLoaded>().Subscribe(HeaderHasBeenLoaded);
}
private void HeaderHasBeenLoaded()
{
_events.GetEvent<UserNameUpdate>().Publish(string.Format("{0} {1}", userPrincipal.GivenName, userPrincipal.Surname));
}
}
When I try to view the MainWindow in design mode I get the following Error
Screenshot of MainWindow In design Mode
No Parameterless constructor found for this object - This Highlights the HeaderView and the ButtonsView
Both the HeaderViewModel and ButtonsViewModel take IEventAggregator as a parameter within their constructor where as the rest of the ViewModels do not. I am assuming this is where the errors are coming from.
HeaderViewModel
public class HeaderViewModel: BindableBase
{
private string userName;
private string runTime;
public string UserName
{
get { return userName; }
set { SetProperty(ref userName, value); }
}
public string RunTime
{
get { return runTime; }
set { SetProperty(ref runTime, value); }
}
public HeaderViewModel(IEventAggregator events)
{
events.GetEvent<RunTimeUpdate>().Subscribe(RunTimeUpdated);
events.GetEvent<UserNameUpdate>().Subscribe(UserNameUpdated);
events.GetEvent<HeaderLoaded>().Publish();
}
private void RunTimeUpdated(string newRunTime)
{
RunTime = newRunTime;
}
private void UserNameUpdated(string userName)
{
UserName = userName;
}
}
So how can I get round this error if I need to subscribe to these events and hence need the IEventAggregator passed into my ViewModels?
Do I need to register this within the Bootstrap via an override of the ConfigureContainer method? If so I'm not entirely sure how to do this.
Bootstrap
class Bootstraper: UnityBootstrapper
{
protected override DependencyObject CreateShell()
{
return Container.Resolve<MainWindow>();
}
protected override void InitializeShell()
{
Application.Current.MainWindow.Show();
}
}
The application builds successfully and runs successfully but it is just when trying to view the MainWindow in the designer that I get this message.
Any help would be greatly appreciated.
EDIT
All my view constructors just have the initalizeComponent methods and take no parameters
The answer marked as accepted addresses the exception, but doesn't answer the question about why. Also, that approach will make unit testing quite difficult as you will be setting the datacontext to a specific object instead of passing in a dependency.
The reason you are getting the exception is because the HeaderView is not being instantiated by the container(by default it's UnityContainer).
You are constructing the entirety of MainWindow at design time instead of individual pieces. Try the following in MainWindow
<Grid>
<Grid.RowDefinitions>
<RowDefinitions />
<RowDefinitions />
<RowDefinitions />
<RowDefinitions />
<RowDefinitions />
</Grid.RowDefinitions>
<ContentControl Grid.Row="0" prism.RegionManager.RegionName="Row0Region" />
<ContentControl Grid.Row="1" prism.RegionManager.RegionName="Row1Region" />
<ContentControl Grid.Row="2" prism.RegionManager.RegionName="Row2Region" />
<ContentControl Grid.Row="3" prism.RegionManager.RegionName="Row3Region" />
<ContentControl Grid.Row="4" prism.RegionManager.RegionName="Row4Region" />
</Grid>
Then you can either use View Discovery or View Injection. For View Discovery, you can do something like
this.RegionManager.RegisterViewWithRegion("Row0Region", HeaderView()) and so on for rest of the views.
You can register views with regions in initialize method of modules or somewhere else. Upto you as to where you do that. You could override the Run method of the bootstrapper. Once the base run method has finished, you can register your views.
When the main window is displayed, all the regions will be discovered and RegionManager will populate the regions with the views that have been registered with each of the regions.
The regionmanager will instantiate the views using the container. When the container constructs each of the views, their viewmodels will be auto wired up. Also the IEventAggregator will be provided to the HeaderView's viewmodel.
This article is based on prism 4 - https://www.codeproject.com/Articles/165376/A-Prism-Application-Checklist but it talks about how to construct views.
Your view is trying to execute logic that only make sense at runtime, so you need to make sure that you are not in design mode:
public HeaderView()
{
if (!System.ComponentModel.DesignerProperties.GetIsInDesignMode(this))
{
var svc = ServiceLocator.Current;
var eventAggregator = svc.GetInstance<IEventAggregator>();
this.DataContext = new HeaderViewModel(eventAggregator);
}
InitializeComponent();
}
EDIT:
For support of designtime view model have a look here
Basically you need to provide a parameterless constructor for you ViewModel to support design mode.
I can't get the navigation in Prism to work. When I click on the buttons to go to respective views, nothing happens.
This is the Man View (Shell) XAML:
<Window x:Class="MVVMPractice2.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:prism="http://prismlibrary.com/"
prism:ViewModelLocator.AutoWireViewModel="True"
xmlns:Views="clr-namespace:MVVMPractice2.Views"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Button Margin="108,130,331.4,152.8" Content="View A" Command="{Binding NavigateCommand}" CommandParameter="ViewA"/>
<Button Margin="254,130,185.4,152.8" Content="View B" Command="{Binding NavigateCommand}" CommandParameter="ViewB"/>
<ContentControl prism:RegionManager.RegionName="ContentRegion"/> <!--PRISM POWER-->
</Grid>
</Window>
and its ViewModel:
public class MainWindowViewModel : BindableBase
{
private readonly IRegionManager regionManager; //PRISM POWER
public DelegateCommand<string> NavigateCommand { get; set; }
public MainWindowViewModel(IRegionManager regionManager)
{
this.regionManager = regionManager;
NavigateCommand = new DelegateCommand<string>(Navigate);
}
private void Navigate(string uri)
{
regionManager.RequestNavigate("ContentRegion", uri);
}
}
and Bootstrapper:
public class Bootstrapper : UnityBootstrapper
{
protected override DependencyObject CreateShell()
{
return Container.Resolve<MainWindow>();
}
protected override void InitializeShell()
{
Application.Current.MainWindow.Show();
}
protected override void ConfigureContainer()
{
base.ConfigureContainer();
Container.RegisterType(typeof(object), typeof(ViewA), "ViewA");
Container.RegisterType(typeof(object), typeof(ViewB), "ViewB");
Container.RegisterType<ICustomer, Customer>();
}
}
I would appreciate some help.
I got mine to work by using the prism:ViewModelLocator.AutoWireViewModel="True" on UserControls only and not the window. I am assuming that you are using prism 6.
So what I did is, I first created the MainWindow that is going to house all my UserControls, I then created a MainUserControl that would house all the other UserControls. All this I achieved following this blog post (http://brianlagunas.com/getting-started-prisms-new-viewmodellocator/). Remember to create your MVVM folders (View and ViewModel) folders with their respective contents as the blog highlights.
Hope this helps.
First of all you should expose ICommand to button's command property , not delegate command which is concrete implementation of ICommand.
You can get rid of conventions of view model locator by implementing
ViewModelLocationProvider.SetDefaultViewTypeToViewModelTypeResolver((viewType) in application class startup overriden method.
For more info please search Brian Lagunas viewmodellocator blog