MVVM - how show view? - wpf

My MVVM application started with App.xaml.cs
Here I create a main window. It has frame. Here I put LoginView.
It has button "Login". I have command, which checks and do login.
This code I have in LoginViewModel.
If all ok - I should show the next View. How I can do it?
App.xaml.cs
private void OnStartup(object sender, StartupEventArgs e)
{
LoginViewModel loginVM = new LoginViewModel();
MainView mainView = new MainView();
LoginView loginView = new LoginView();
loginView.DataContext = loginVM;
mainView.Frame.Content = loginView;
mainView.Show();
}
LoginViewModel.cs
// this method calls by binding after Click Login in LoginView
private void Login()
{
//TODO: Realize it
if (LoginModel.Login("User1", "Password"))
{
// HERE I SHOULD CLOSE LOGINVIEW AND SHOW NEXT VIEW
}
}
How and where I should show all necessary views?
I Use now WPF MVVM Toolkit.

In a situation such as this you could have your startup form be your main program, and the Login is a dialog box. If the dialog box fails, exit the program. If it succeeds, proceed in loading up the main form.
private void OnStartup(object sender, StartupEventArgs e)
{
LoginViewModel loginVM = new LoginViewModel();
LoginView loginView = new LoginView();
loginView.DataContext = loginVM;
loginView.ShowDialog(); // Change this to a ShowDialog instead of Show
if (!login.DialogResult.GetValueOrDefault())
{
// Should probably handle error in login class, not here");
Environment.Exit(0);
}
// This code will never get reached if Login fails
MainView mainView = new MainView();
mainView.Frame.Content = loginView;
mainView.Show(); // Change this to a ShowDialog instead of Show
}

I don't know anything about the MVVM Toolkit, but a simple way I did this was to have a delegate to do it, something like: (simplified code)
private void OnStartup(object sender, StartupEventArgs e)
{
LoginViewModel loginVM = new LoginViewModel();
loginVM.ShowNextScreen += () => {
SomeOtherVM nextVM = new SomeOtherVM();
nextVM.ShowForm();
}
// ...
}
So you have a 'ShowNextScreen' action on your VM which calls this code.
I have a small app on Google Code which does that (it also deals with only having one form open, error handling etc). Note that in this case, it's the ViewModel which has responsibility for opening the view.
But this is going to get complicated quickly, for any reasonable size of app you'd want to split this functionality out into some kind of 'application controller' which dealt with opening screens, navigation etc.

Related

How to auto-close the Caliburn Dialog window?

I have a ViewModel defined like
public class PlayerViewModel : Screen, IDiscoverableViewModel
I am showing a dialog pop up as
var result = await _dialogManager.ShowDialogAsync(item, new List<DialogResult>() { DialogResult.Cancel });
Here item is the another ViewModel which shows UI from the related View. This pop up is showing some information and needs to be auto closed after few seconds in case user doesn't select Cancel button.
Following is the Timer tick event that is getting fired after 10 seconds.
void timer_Tick(object sender, EventArgs e)
{
this.DialogHost().TryClose(DialogResult.Cancel);
}
But it's not working and throwing exception as this.DialoHost() is getting null always. I tried this solution but it is closing the whole ViewModel instead I want to close only the dialog window.
Could you confirm if your 'pop-up viewmodel' is deriving from Screen ? If so, TryClose should work. Could you please verify it ? Sample code for closing.
public class CreatePersonViewModel:Screen
{
System.Timers.Timer _timer = new Timer(5000);
public CreatePersonViewModel()
{
_timer.Elapsed += (sender, args) =>
{
_timer.Enabled = false;
TryClose(true);
};
_timer.Start();
}
}

Is there a way to keep additional windows active when showing a modal window?

I'm afraid the answer is probably no...but some background. To draw a custom border on a window where the sizing logic works beyond the visible border (as it does on windows 10) I added layered windows around the edges to capture the messages and then forward them to the central window. This worked great until the form was shown modaly, at which point all the edge windows were automatically disabled. Obviously this is by design...but I'm not sure if there is some way around it. I tried making the edge windows owned by the central window, but that didn't work.
Or maybe there is a better approach entirely.
Here's a sample of the issue:
public partial class Form1 : Form
{
public Form1()
{
}
protected override void OnClick(EventArgs e)
{
base.OnClick(e);
Form f2 = new Form();
f2.Text = "Non Modal";
f2.Show();
Form f3 = new Form();
f3.Text = "Modal";
f3.ShowDialog(this);
}
}
I think you can fake the modal window, so that it is not modal but disable the caller. I used this in a own project. I did it this way:
//Setup small Interface
public interface IDialog
{
//Our own Event which tell the caller if the Dialog is active/inactive
public event DialogChangedEventArgs DialogChanged;
}
//Setup EventArgs for our own Event
public class DialogChangedEventArgs : EventArgs
{
public bool DialogActive{get;}
public DialogChangedEventArgs(bool dialogActive)
{
DialogActive = dialogActive;
}
}
//Setup the Form which act as Dialog in any other form
public class Form2 : Form, IDialog
{
public event EventHandler<DialogChangedEventArgs> DialogChanged;
//If this Form is shown we fire the Event and tell subscriber we are active
private void Form2_Shown(object sender, EventArgs e)
{
DialogChanged?.Invoke(this, true);
}
//If the user close the Form we telling subscriber we go inactive
private void Form2_Closing(object sender, CancelEventArgs e)
{
DialogChanged?.Invoke(this, false);
}
}
public class Form1 : Form
{
//Setup our Form2 and show it (not modal here!!!)
private void Initialize()
{
Form2 newForm = new Form2();
newForm.DialogChanged += DialogChanged;
newForm.Show();
}
private void Form2_DialogChanged(object sender, DialogChangedEventArgs e)
{
//Now check if Form2 is active or inactive and enable/disable Form1
//So just Form1 will be disabled.
Enable = !e.DialogActive;
}
}
It's really simple. Just use an event to tell your first Form: Hey iam second Form and active. Then you can disable the first Form with while second is active. You have the full control which forms are active or not. Hope this helps.

Using a UserControl to Login and then enable menuStrip in Primary form

Ok so here is what i am trying to do.
I have a Primary form in a C# desktop application in which i have a menuStrip and a splitContainer.
On running the application, I am loading a UserControl named 'Login' to the splitContainer.Panel2 while hiding the menuStrip. The Login control contains fields for Username, Password and a button to log in.
http://i.stack.imgur.com/5jcnK.png
Once authenticated (on click of the button) i want to enable the menuStrip and allow other UserControls in the splitContainer.Panel2, while hiding the Login control.
http://i.stack.imgur.com/lwLvP.png
How to i achieve this? I was trying to fire up an event from Login control and somehow make it work in Primary form but unable to implement.
Is this approach even worth trying or should i open multiple forms separately (i would hate to do so!)
Any cleaner approach on how to change views in splitContainer.Panel2 (other than stacking panels one above the other, which would be a design nightmare for me) while keeping splitContainer.Panel1 with same content.
Your attempt sounds like it should have worked.
Are you adding the Login control at design-time or via code?
Here's an example of it being created thru code...worked fine for me.
Form1:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
menuStrip1.Visible = false;
Login login = new Login();
login.Authenticated += new EventHandler(login_Authenticated);
splitContainer1.Panel2.Controls.Add(login);
}
void login_Authenticated(object sender, EventArgs e)
{
Login login = (Login)sender;
// ... possibly extract some info from "login" ...
menuStrip1.Visible = true;
login.Dispose();
}
}
Login UserControl:
public partial class Login : UserControl
{
public Login()
{
InitializeComponent();
}
public event EventHandler Authenticated;
private void btnLogin_Click(object sender, EventArgs e)
{
if (true) // if they have authenticated
{
if (Authenticated != null) // only raise the event if we have subscribers
{
Authenticated(this, new EventArgs());
}
}
}
}

How to logout on app exit in Silverlight application?

I have a silverlight application with custom form authentication.
How i can logout application when the browser window is closed?
I tried something like this:
public App()
{
Startup += ApplicationStartup;
Exit += Application_Exit;
UnhandledException += ApplicationUnhandledException;
var webContext = new WebContext {Authentication = new FormsAuthentication()};
ApplicationLifetimeObjects.Add(webContext);
InitializeComponent();
}
private void ApplicationStartup(object sender, StartupEventArgs e)
{
Resources.Add("WebContext", WebContext.Current);
RootVisual = new MainPage();
}
private void Application_Exit(object sender, EventArgs e)
{
WebContext.Current.Authentication.Logout(false);
}
but this didn't work. Ewery time I close the browser, I receive the exception An AsyncCallback threw an exception without any details.
How can I handle this problem?
you could call an ajax call on the page with onbeforeunload, forget the idea to call logoff with silverlight whilst it is closing.

Silverlight closing UserControl Childwindow

On my project I show a Usercontrol childwindow for logging in. Now when I want to submit the login values (username, password) the content of that childwindow has become null... You prob think that I made it a 2nd time but no...
Here is my code for creating the childwindow. And for closing it (that's where it fails)
public void openLoginWindow()
{
if (login == false)
{
window.Content = new LoginView();
window.HasCloseButton = false;
window.Show();
}
else
{
window.Close();
}
}
Thank's for the help
Evert
what is that LoginView object? Is it a custom usercontrol? I'm not sure how your system is working but what I would do is create a specific childwindow for logging in (in that childwindow you can use your LoginView object if you want). Then in code :
public void openLoginWindow()
{
LoginChildWindow dlg = new LoginChildWindow();
dlg.HasCloseButton = false;
dlg.Closed += new EventHandler(dlg_Closed);
dlg.Show();
}
void dlg_Closed(object sender, EventArgs e)
{
LoginChildWindow dlg = ((LoginChildWindow)sender);
dlg.Closed -= dlg_Closed;
//Retrieve your values here
}

Resources