I need to add some features to a WPF Project a retired colleague of mine made. Tried to copy the Navigation Features but they won´t work like they should.
I want to open my own XAML File in the Main Window but all I get is System.Object.
Here I register the Views as:
public override void Initialize()
{
UnityContainer.RegisterType<RelationView>();
UnityContainer.RegisterType<RelationNavigationItemView>();
UnityContainer.RegisterTypeForNavigation<RelationView>();
RegionManager.RegisterViewWithRegion(RegionNames.NavigationRegion, typeof(RelationNavigationItemView));//this works out fine appears in the Navigation Part
}
The RelationNavigationItemView is simply a button which should open the RelationView in the MainWindow.
Which should happen here as:
private static Uri RelationViewUri = new Uri("/RelationView", UriKind.Relative);
private IRegionManager _regionManager;
private DelegateCommand _navigateCommand;
public RelationNavigationViewModel(IRegionManager regionManager)
{
_regionManager = regionManager;
}
public ICommand NavigateCommand
{
get
{
return _navigateCommand ?? (_navigateCommand = new DelegateCommand(NavigateCommandExecute, NavigateCommandCanExecute));
}
}
private bool NavigateCommandCanExecute()
{
return true;
}
private void NavigateCommandExecute()
{
_regionManager.RequestNavigate(RegionNames.MainContentRegion, RelationViewUri); //Here should the new window appears and the ViewModel Constructor should be called but nothing happens, I only get System.Object in the MainContentRegion
}
The Project runs with Prism Version 6.3.
I hope, someone can help me.
Thanks and Best Regards, Max.
You should just navigate to ´"RelationView"`. No need for uri here, it just adds potential for errors.
Thanks Guys it works now. The Constructor was Wrong.
I expected an UnityContainer instead of a IUnityContainer.
Related
In order to use WebGL in UWP WebView , I looked for this.
How do I enable WebGL in Xamarin.Forms WebView on UWP?
But a new problem comes. When navigating to another page and go back for a few times, the application crashed and gives you no explain. It seems like too many webview instance was created then I tried to use Singleton pattern to solve it.
public static class WebViewSingleton
{
private static WebView instance;
public static WebView GetInstance()
{
if (instance == null)
{
instance = new WebView(WebViewExecutionMode.SeparateProcess)
{
Source = new Uri("https://www.google.com/")
};
}
return instance;
}
}
public HomePage()
{
this.InitializeComponent();
MyWebView = WebViewSingleton.GetInstance();
MyWebView.Navigate(new Uri("https://sketchfab.com/models/a6af6d1ae2744a55820d00599aca71f2/embed?
autostart=1&internal=1&ui_infos=0&ui_snapshots=1&ui_stop=0&ui_watermark=0"));
this.RootGrid.Children.Add(MyWebView);
}
In this way, debugger tells me MyWebView is already a children for another element. I tried every way to disconnect MyWebView with it's parent but failed.
I find it works when adding NavigationCacheMode="Enabled" to my page, but that is not what I want.
add this to page.xmal
protected override void OnNavigatedFrom(NavigationEventArgs e)
{
if (this.RootGrid.Children.Contains(MyWebView))
{
this.RootGrid.Children.Remove(MyWebView);
}
}
I follows samples code provided in https://github.com/PrismLibrary/Prism-Samples-Wpf/blob/master/17-BasicRegionNavigation
I want to achieve the following result when I run the application (without explicitly clicking Navigate to View A). Does anyone know how to do it?
I have tried adding Navigate("ViewA"); after this line. However, I cannot get the desired outcome. Is it because the module hasn't been initialized?
Thanks.
did you add your module to the modulecatalog using override method ConfigureModuleCatalog? take a look at here
Eventually I solve by adding the following code in MainWindow.xaml.cs
public partial class MainWindow
{
IRegionManager _regionManager;
public MainWindow()
{
InitializeComponent();
_regionManager = ServiceLocator.Current.GetInstance<IRegionManager>();
RegionManager.SetRegionManager(ContentRegion, _regionManager);
Loaded += MainWindow_Loaded;
}
private void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
_regionManager.RequestNavigate("ContentRegion", "ViewA");
}
}
Get idea from: https://github.com/MahApps/MahApps.Metro/issues/1020#issuecomment-44779574
I'm kinda late to the party here, but I also stumbled over the question of how to navigate to a default view during the applications startup.
I found two ways:
1. App decides the default view
This can be solved in the CreateShell()-override in the App-Class.
This is my CreateShell-Method:
/// <inheritdoc />
protected override Window CreateShell()
{
var window = this.Container.Resolve<MainWindow>();
window.Loaded += (sender, args) =>
{
var manager = this.Container.Resolve<IRegionManager>();
manager.RequestNavigate("ContentRegion", "ViewA");
};
return window;
}
2. ViewModel decides the default view
Add a constructor to MainWindowViewModel that looks like this:
public MainWindowViewModel(IRegionManager regionManager)
{
regionManager.RegisterViewWithRegion("ContentRegion", "ViewA");
}
I Am very new to Caliburn and have to expand an existing program, using caliburn.micro
I need my DataContext in a View to be set to a ViewModel which has some propertyinjected parameters. All this should work, so i only need to build it up.
however it does not! here is the code where i try to bulid:
public ProductionMainView()
{
InitializeComponent();
var gg = IoC.Get<ProductionMainViewModel>();
IoC.BuildUp(gg);
this.DataContext = gg;
}
As far as i can understand I need to get the object and then build it.
Now I should get a view "Containing" my ViewModel, but the View is blank,
I hope i have explained myself well enough.
Best regards
First off you are using a really old version, present version is 2.0.2, and you still need to have overrides for GetInstance, GetAllInstances, BuildUp methods in your BootStrapper or a variant for use with Ninject
http://putridparrot.com/blog/caliburn-micro-and-inversion-of-control-using-ninject/
Link above has some source for this.
Remember there is nearly no code in the Codebehind of the View... It will all go into the ViewModels (for the most part). ShellView => ShellViewModel with in ShellViewModel var gg = IoC.Get<ProductViewModel>() depending on you are intent is with that you can bind it to a <ContentControl x:Name="ProductViewModel" /> with a property in yoru viewmodel called exactly that. CM will go out and fine that ViewModel and associated view and mash them together automagically. Expected results on the screen should be your ProductViewModel in that contentcontrol location.
public class ShellViewModel : Screen
{
private ProductViewModel _productViewModel;
public ShellViewModel (){
}
protected override void OnActivate(){
ProductViewModel = IoC.Get<ProductViewModel>();
}
public ProductViewModel ProductViewModel {
get{ return _productViewModel;}
set{
_productViewModel = value;
NotifyOfPropertyChanged (); // 2.0.2 feature...
}
}
}
Now, if you decide to move to the latest version there are subtle changes one Bootstrapper<T> does not exist anymore it was refactored into BootstrapperBase. Next Initialize() will be placed into the ctor of your Bootstrapper(). From there everything will be based on your starting screen is after Initialize() is called in the CTOR you will call DisplayRootViewFor<ShellViewModel>() in the OnStartup override.
Some have said and I tend to agree over using IoC.Get<T>() can be anti-pattern, caution when using it. Sometimes things change unexpectedly. Those tend to DI the items via the CTOR and use from there accordingly.
/*version 1.52*/
public class Bootstrapper : BootStrapper<LoginViewModel>{
public Bootstrapper(){
Start();
}
protected override Configure(){
/* -- your Ninject configurations -- */
}
protected override object GetInstance(Type service, string Key){
if(service == null)
throw new ArgumentNullException("Service");
return _kernel.Get(service);
}
protected override IEnumerable<object> GetAllInstances(Type service){
return _kernel.GetAll(service);
}
protected override void BuildUp(object instance){
_kernel.Inject(instance);
}
protected override void OnExit(object sender, EventArgs e)
{
kernel.Dispose();
base.OnExit(sender, e);
}
}
To clarify do you have to login to get to the ProductionMainViewModel? What determines your logic for getting to ProductionMainViewModel to even display?
I'm actually working on a project using WPF, MEF and Prism. When I start the application, I need to export a module from the container to open a configuration window before the mainwindow is shown. The code therefore is like this:
protected override void OnStartup(StartupEventArgs e)
{ base.OnStartup(e);
Bootstrapper bootstrapper = new Bootstrapper();
bootstrapper.Run();
var window = bootstrapper.statcontainer.GetExport<Configshell>();
var configview = bootstrapper.statcontainer.GetExport<Module.Module1.View.ConfigView>();
window.Value.Show();
Keyboard.Focus(configview.Value.ok_button); }
Where bootstrapper.statcontainer is a public CompositeContainer (allocated with the "Maincontainer" of the MEFBootstrapper in CreateContainer-Method). I use it to export modules at startup.
Now at GetExport() I get the following first chance exception thrown:
GetExportedValue cannot be called before prerequisite import 'MyApp.Module.Module2.ViewModels.Module2_Functions..ctor (Parameter="C_Aggregator", ContractName="Microsoft.Practices.Prism.PubSubEvents.IEventAggregator")' has been set.
And this is how the ctor there looks like:
[Import]
public IEventAggregator Configaggregator;
[ImportingConstructor]
public Module2_Functions(IEventAggregator C_Aggregator)
{
this.Configaggregator = C_Aggregator;
Configaggregator.GetEvent<FromConfigWindow>();
FromConfigWindow.Instance.Subscribe(receiveStatusFromConfigWindow);
Configaggregator.GetEvent<ToConfigWindow>();
}
I'am using the EventAggregator to publish the configuration and have the same ctor in another module. The confusing thing is that it worked that way until I added another completely independent import to that ViewModel. Here is how the ctor of the ConfigwindowViewModel looks like:
[ImportingConstructor]
public ConfigVM(IEventAggregator C_aggregator)
{
this.Configaggregator = C_aggregator;
Configaggregator.GetEvent<ToConfigWindow>();
ToConfigWindow.Instance.Subscribe(actualizeCompStatus);
Configaggregator.GetEvent<FromConfigWindow>();
}
[Import]
public IEventAggregator Configaggregator;
The two events are looking like this and both already worked until 2 days ago ;-)
[Export]
public class FromConfigWindow : PubSubEvent<Int16>
{
private static readonly EventAggregator _eventAggregator;
private static readonly FromConfigWindow _event;
static FromConfigWindow()
{
_eventAggregator = new EventAggregator();
_event = _eventAggregator.GetEvent<FromConfigWindow>();
}
public static FromConfigWindow Instance
{
get { return _event; }
}
}
[Export]
public class ToConfigWindow : PubSubEvent<Int16>
{
private static readonly EventAggregator _eventAggregator;
private static readonly ToConfigWindow _event;
static ToConfigWindow()
{
_eventAggregator = new EventAggregator();
_event = _eventAggregator.GetEvent<ToConfigWindow>();
}
public static ToConfigWindow Instance
{
get { return _event; }
}
}
So finally the Problem looks to me like the EventAggregator doesn't get instanciated and therefore the exception gets thrown. But how can I work around this? Or am I doing something wrong in the linkage of the Aggregator in the constructors?
I already tried to modify all constructor arguments with an [Import] attribute, this threw the same exception as well, or removing all [Import] attributes form the IEventAggregator Configaggregator objects in the ViewModels.
The problem is similar to this link here but in my case happens with the EventAggregator from the Prism framework.
Please tell me if I should provide you more parts of the code.
I'm not sure why you're Exporting your PubSubEvents or holding a reference to a static new EventAggregator in them. You should only be using one instance of EventAggregator (in this example) which you'll get from your container (Prism will put it there for you).
You should go back to basics and read the excellent Prism documentation. Section 9 "Communicating Between Loosely Coupled Components" for an overview of EventAggregator and PubSubEvents.
If you want to create a bare bones project which simulates the problem you're having and upload it somewhere, I'll gladly have a look at it for you.
It looks like the error is because you have not satisfied all your imports before beginning operations on them. I concur with ChrisO, you should go back and check out the docs. There are a lot of things going on here which seem to be overcomplicating things. Why is there a new EventAggregator() in there? MEF should import that dependency for you. Why all the messing around with the container and getting exports? It seems you are doing a lot of work that should be taken care of by MEF and Prism.
Have been learning about MVP and have tried writing a test app using it in WinForms. I'm struggling to find a well explained example on how to navigate between my forms/views. As an example, the program starts and I want to show a login dialog then go into my main view if the login was successful. At the moment, my Main method looks something like this:
static void Main()
{
var loginView = Injector.Resolve<ILoginView>();
if (loginView.DoLogin() != LoginResult.OK) return;
var mainView = Injector.Resolve<IMainView>();
Application.Run(mainView); // won't work as mainView isn't a form
}
The Injector object is just a wrapper around an IoC tool (currently StructureMap). The thing is, I've read that I shouldn't really be manually creating instances via the Injector as they should really be done via constructor injection.
I've managed to do this up to a point but not when it comes to navigation. I can't think of an elegant way of moving through my views and was wondering if anyone here might shed some light on this? I've read a little on application controllers but have not found an example to show it clearly.
In regards to the navigation question:
I've managed to do this up to a point but not when it comes to
navigation. I can't think of an elegant way of moving through my views
and was wondering if anyone here might shed some light on this? I've
read a little on application controllers but have not found an example
to show it clearly.
Below is a simplified version of a construct I've used. Note that the setup and tear down hooks are called automatically when the NavigateTo method is called. Also, +1 to #AlexBurtsev, as his answer hints at this very same approach.
// Presenter can and should offer common services for the
// subclasses
abstract class Presenter
{
public void Display()
{
OnDisplay();
}
public void Dismiss()
{
OnDismiss();
}
protected virtual OnDisplay() // hook for subclass
{
}
protected virtual OnDismiss() // hook for subclass
{
}
private NavigationManager _navMgr;
internal NavigationMgr NavigationManager
{
get
{
return _navMgr;
}
set
{
_navMgr = value;
}
}
}
// NavigationManager is used to transition (or navigate)
// between views
class NavigationManager
{
Presenter _current;
// use this override if your Presenter are non-persistent (transient)
public void NavigateTo(Type nextPresenterType, object args)
{
Presenter nextPresenter = Activator.CreateInstance(nextPresenterType);
NavigateTo(nextPresenter);
}
// use this override if your Presenter are persistent (long-lived)
public void NavigateTo(Presenter nextPresenter, object args)
{
if (_current != null)
{
_current.Dismiss()
_current.NavigationMgr = null;
_current = null;
}
if (nextPresenter != null)
{
_current = nextPresenter;
_current.NavigationMgr = this;
_current.Display(args);
}
}
}
class MainMenuPresenter : Presenter
{
private IMainMenuView _mainMenuView = null;
// OnDisplay is your startup hook
protected override void OnDisplay()
{
// get your view from where ever (injection, etc)
_mainMenuView = GetView();
// configure your view
_mainMenuView.Title = GetMainTitleInCurrentLanguage();
// etc
// etc
// listen for relevent events from the view
_mainMenuView.NewWorkOrderSelected += new EventHandler(MainMenuView_NewWorkOrderSelected);
// display to the user
_mainMenuView.Show();
}
protected override void OnDismiss()
{
// cleanup
_mainMenuView.NewWorkOrderSelected -= new EventHandler(MainMenuView_NewWorkOrderSelected);
_mainMenuView.Close();
_mainMenuView = null;
}
// respond to the various view events
private void MainMenuView_NewWorkOrderSelected(object src, EventArgs e)
{
// example of transitioning to a new view here...
NavigationMgr.NavigateTo(NewWorkOrderPresenter, null);
}
}
class NewWorkOrderPresenter : Presenter
{
protected override void OnDisplay()
{
// get the view, configure it, listen for its events, and show it
}
protected override void OnDismiss()
{
// unlisten for events and release the view
}
}
I haven't used WinForms for a long time, but I'll try to answer this. I would use the same strategy as WPF Prism do.
About MainView and Application.Run:
Create a main Region (root Form), with empty container inside which can hold UserControl (I forgot exact class names), then when you need to switch root view, you do RootView.SetView(UserControl view) which will do something like Form.Clear(), Form.AddChild(view).
About the navigation and using container:
You could create a service for navigation: INavigationService which you inject in constructors with method like INavigationService.NavigateView(String(or Type) viewName, params object[] additionalData)
You can insert a method in mainView that returns the actual form.Then you can call
Mainview:IMainView
{
Form GetView()
{
//return new Form();
}
}
In Main you can call ,
Application.Run(mainView.GetView())