I am new to using caliburn.micro and currently learning MVVM.
I am using the windows template studio to create my UWP app, and it works great! But unfortunately, I am not familiar with MVVM and still learning UWP.
I get how the navigation works etc and how the shellpage is loaded. However, I want to prompt the user to log in upon opening the app (i.e. a login in page will start with no navigation sidebar).
I also want to make sure I'm following best practices...
I have tried substituting the MainViewModel with LoginViewModel which I get works, however, I don't want to create the navigation pane. I get that this is triggered by the "new Lazy(CreateShell)". I'm just not sure if I want to remove this from the activation service and call a method upon login?
Below is the default code supplied by the windows template studio which triggers on activation of the app if I understand correctly.
private ActivationService CreateActivationService()
{
return new ActivationService(_container, typeof(ViewModels.LoginViewModel), new Lazy<UIElement>(CreateShell));
}
private UIElement CreateShell()
{
var shellPage = new Views.ShellPage();
_container.RegisterInstance(typeof(IConnectedAnimationService), nameof(IConnectedAnimationService), new ConnectedAnimationService(shellPage.GetFrame()));
return shellPage;
}
I just need to be pointed in the right direction or lead to a video/tutorial as I'm struggling!!! any help much appreciated.
If you want to show login page,you can remove the ShellPage.It is a navigation view.
in App.xaml.cs
private ActivationService CreateActivationService()
{
return new ActivationService(this, typeof(LoginPage));
}
private UIElement CreateShell()
{
return new Views.ShellPage();
}
When login successfully,if you want to show the navigation view,you can set the ShellPage to the content of current window.
Window.Current.Content = new Views.ShellPage();
Related
I want to change frame, but I get this exception:
Navigation:
Frame rootFrame = new Frame();
rootFrame.Navigate(typeof(ScoreWindow), null, new EntranceNavigationTransitionInfo());
Exception appears on constructor:
public ScoreWindow()
{
this.InitializeComponent();
results = new List<Result>();
playerList = new();
LoadData();
var _resultsView = ConvertToView();
sfDataGrid.ItemsSource = _resultsView;
}
Thanks for answers in advance and happy holidays!
P.S. Thanks to Raymond, I detected this message:
WinUI: Error creating second Desktop Window on the current process. No more than one Desktop Window is allowed per process.
There is another question: how to change current frame to other? I mean, I have login view, user logged in successfully and want to see data/other things.
After a little break, I understood what I did wrong. There is a way how to navigate between pages.
Rule #1: In WinUI, you have only one active window, and it's MainWindow. Always. If you want to change layout, you have to use Frames.
In MainWindow.xaml, you write this:
<Grid>
<Frame x:Name="mainFrame"/>
</Grid>
Element "Frame" give ability to navigate between pages.
Then switch to MainWindow.xaml.cs and in constructor have to be something like this:
public MainWindow()
{
InitializeComponent();
mainFrame.Navigate(typeof(NameOfYourPage));
}
It will immediately activate your page.
Then, if you want to navigate from page to page, write in control of page this:
Frame.Navigate(typeof(NameOfYourPage), null, new EntranceNavigationTransitionInfo());
The third parameter is animation, but I didn't notice changes.
More information you can find here:
Tutorial about navigation
Microsoft documentation
Edit: Please see my comment below - the code itself seems to be correct (at least the Prism region code) but navigation in the new window instance is still not working.
To start off with, here is the issue I'm having...
I have a main window with a menu bar that switches views in the main window to take the user to different screens. This is all working great.
So I thought today that I would add a 'first time user' screen to handle all the initial setup for the application. This is a new window that will pop up if certain first time properties haven't been set and welcome the new user, get the initial setup complete, etc. I wanted to have navigation on this new window in a new region (just next and back buttons that take the user through the setup).
I thought this would be easy but after 3 hours of floundering and searching the darkest corners of the web I am still very confused - I also looked at Brian Lagunas' Pluralsight videos on MVVM but nothing I have tried to apply is working to setup navigation on the new window.
The content region for the main window is named "ContentRegion" and the content region for the new window is named "SetupRegion".
All views are registered in the bootstrapper like so:
// All views must be registered.
Container.RegisterTypeForNavigation<Home>( "Home" );
Container.RegisterTypeForNavigation<Index>( "Index" );
Container.RegisterTypeForNavigation<Settings>( "Settings" );
Container.RegisterTypeForNavigation<FirstTimeSetupWelcomeScreen>( "WelcomeScreen" );
Container.RegisterTypeForNavigation<FirstTimeSetupScreen2>( "FirstTimeSetupScreen2" );
Here is how the new window is being instantiated currently, from the main window:
public MainWindowViewModel(IRegionManager _regionManager, EventAggregator _eventAggregator)
{
eventAggregator = _eventAggregator;
regionManager = _regionManager;
NavigateCommand = new DelegateCommand<string>(Navigate);
// Set the default view to the home screen
regionManager.RegisterViewWithRegion("ContentRegion", typeof(FirstTimeSetupWelcomeScreen));
// Check to see if program is in first time run or not
if ((ConfigurationManager.GetSection("SaveLocationsGroup/Locations") as IndexLocationsSection).SaveLocation.Location == "")
{
var firstTimeWindow = new FirstTime();
firstTimeWindow.Show();
// Set the default view to the welcome screen on new window
regionManager.RegisterViewWithRegion("SetupRegion", typeof(FirstTimeSetupWelcomeScreen));
}
}
In the XAML for the new window, the content control is setup like this:
<Grid>
<ContentControl prism:RegionManager.RegionName="SetupRegion" />
</Grid>
I have tested by replacing the code in the Navigate command on the main window and having it to navigate to the new user controls, showing them in the main window and that works.
However, in the new window they are not and I can't seem to figure out why. I have also tested to see if the button in the first/default user control view model is firing correctly and it is - for reference, here is that Navigate command code:
private void Navigate(string uri)
{
// WriteLine command to test the button firing
Console.WriteLine(uri);
regionManager.RequestNavigate("SetupRegion", uri);
}
Lastly I've placed the first view inside the main window and it seems to fire correctly, changing the content in the main window - I just can't get it to work or anything to work on the new window at all no matter how I try it. I'm assuming that there is something that I don't know that has to do with either navigation on new instances of windows (aside from the main window) or having to do with containers and new windows but I haven't been able to figure out what. Thank you guys for all of your assistance as always.
It turn out Brian Lagunas has a course on multiple shells I should hopefully be able to use to accomplish what I need. I will attempt to use it.
I have a custom control and an iOS custom renderer for ordering list items by drag and drop (inheriting from ListView and ListViewRenderer). I have placed the control on a very simple page.
Dragging the items in the OrderListView works without a hitch when I set the page directly to the the application's MainPage. It also works when the page is pushed to a NavigationPage.
However, as soon as I use a MasterDetailsPage the drag operation does not work. The drag operation ends as soon as I start dragging, resulting in the item's new location beeing the same as the old.
Anyone got an idea on why the custom control behaves differently when used in MasterDetailsPage? I'm just guessing but maybe the MasterDetailsPage has some built in gestures that conflicts with the ListView's?
Application startup:
Working:
public App()
{
MainPage = new OrderListPage();
}
Not working:
public App()
{
InitializeComponent();
var masterDetailsPage = new MasterDetailPage
{
Master = new MenuPage(),
Detail = new OrderListPage()
};
MainPage = masterDetailsPage;
}
I using MvvmCross to build my UWP application. I have views with their own view models.
When I start the app then first time from Setting view navigate to Passcode view using ShowViewModel<PasscodeViewModel>(). Then it call view model and view constructor to build and initialize view. When user come back to setting view and again navigate to passcode view using same method like ShowViewModel<PasscodeViewModel>() then this time view and view model constructor not get called. Since unable to reinitialize passcode view. So it display previous instance of passcode view.
Following solution I have tried
I tried removing the backstack in the navigations but then also not constructor get call.
Also implement loaded event but this solution also not working for me.
Also implemented Void Init() in view model but this method also not get call.
I just want when I navigate to PasscodeView then each time it call constructor of PasscodeView and PasscodeViewModel.
So my question is how to force to re-initialize page and viewmodel each time while navigation??
Please help to resolve this issue.
I needed to use navigation cache mode on required.
I resolved it for me with the not very clean solution to call init again.
protected override void OnNavigatedTo(NavigationEventArgs e)
{
if (this.ViewModel!= null && e.NavigationMode != NavigationMode.Back)
{
var reqData = (string)e.Parameter;
var converter = Mvx.Resolve<IMvxNavigationSerializer>();
var req = converter.Serializer.DeserializeObject<MvxViewModelRequest>(reqData);
this.Vm.CallBundleMethods("Init", new MvxBundle(req.ParameterValues));
}
base.OnNavigatedTo(e);
}
This code avoids to call init again on back navigation.
I just set Universal Windows Phone apps page navigation cache mode "Disabled". I think its default value is "Required".
public PasscodeView()
{
InitializeComponent();
NavigationCacheMode = NavigationCacheMode.Disabled;
}
The above code work for me.
I'm currently building a universal app but I'm concentrating on the WP8.1 part of it right now. I'm using MVVMLight with this project.
For simplicity sake, we'll just assume that I only have 2 pages in the project.
Page1.xaml contains a list which has various items. The Page1.xaml is binded to its own ViewModel i.e. Page1ViewModel. Each item in the list represents a viewModel i.e. ItemViewModel.
When I tap on an item, I call the following code:
public RelayCommand<ItemViewModel> ItemTapCommand
{
get
{
return this._itemTapCommand ?? (this._itemTapCommand =
new RelayCommand<ItemViewModel>((msg) =>
ExecuteItempTapCommand(msg)));
}
}
When an item in the list is tapped, I call the following code:
private object ExecuteItempTapCommand(ItemViewModel selectedItemViewModel)
{
Page2ViewModel page2ViewModel =
SimpleIoc.Default.GetInstance<ItemViewModel>();
page2ViewModel.SelectedItem = selectedItemViewModel;
_navigationService.Navigate(typeof(Page2),
selectedItemViewModel);
return null;
}
As you can see I'm using my Ioc to create get an instance of my Page2ViewModel and I then set the SelectedItem to the selectedItemViewModel.
Once it is set, I navigate to Page2 which is binded to my Page2ViewModel.
What I want to know is, is the above is ok to do? I've seen plenty of examples when dealing with passing object from one page to another is done by passing an Id for example and then I request the information from Page2, but why request it again when most of the information I need is already in my SelectedItemViewModel since it represents the tapped item in my list in Page1.
If it's not correct, what is the best way to go about this using MVVMLight?
Can you provide a sample? I've seen something about Messaging but I'm not sure how this would work as if I navigate to my page2, the Page2ViewModel will only be initiated when the page is created, so how can it receive a message? The way I have it above seems to initiate the Page2ViewModel and my Pag2 loads, it's re-using it and everything bind correctly but I'm not sure this is the correct way to go about it.
Any help would be appreciated.
Thanks.
In your Page2ViewModel, why not use
protected override void OnNavigatedTo(NavigationEventArgs e)
{
Page2SelectedItem = e.Parameter as ItemViewModel;
base.OnNavigatedTo(e);
}
It looks like you are packing that data in with your _navigationService.Navigate call already.
With that set up, what happens if you just change to:
private object ExecuteItempTapCommand(ItemViewModel selectedItemViewModel)
{
_navigationService.Navigate(typeof(Page2), selectedItemViewModel);
return null;
}
You can use the ViewModel to get it if you do some work before that.
Read this blog post by Marco Minerva called Calling ViewModel methods in response to Page navigation events using MVVM Light in WinRT
which explains how to react to OnNavigatedTo and OnNavigatedFrom in the ViewModel.
It's a very cool solution.