Swapping MainWindows in WPF? - c#

I have two "MainWIndows". A Login screen and the actual Content Main Window. This is the process in which i want to happen.
User starts application
Clicks Login Button on the Login Window
Initialize the Content Window
Wait until all my lists and Data have been gathered, parse, and added to ListViews
Close the Login Window and show the Main Window. (Make MainWindow the main Window)
I am having issues actually hiding the main window, but i still need to be able to initialize it so i can gather all my data.
I added this to my App.xaml:
<Application.MainWindow>
<NavigationWindow Source="MainWindow.xaml" Visibility="Hidden"></NavigationWindow>
</Application.MainWindow>
Here is my some of my LoginWindow code:
// Login complete, load the MainWindow Data
MainWindow mainWindow = new MainWindow();
mainWindow.setLoginWindow = this;
mainWindow.InitializeComponent(); //mainWindow.Show();
And the code i am using in the MainWindow:
public partial class MainWindow : MetroWindow
{
Window LoginWindow;
public Window setLoginWindow { get { return LoginWindow; } set { LoginWindow = value; } }
public MainWindow()
{
InitializeComponent();
// Hide the window to load Data, then on completion, close LoginWindow and show MainWindow: ::: LoginWindow.Close();
LoadData();
}
public void LoadData()
{
// Add player's to list ....
// Done loading data, show the window
LoginWindow.Close();
this.Visibility = Visibility.Visible;
}
}
The Question
How would i do this properly? Also, i want to keep the Focus on the LoginWindow until the MainWIndow has been shown.

(off the top of my head so watch for syntax errors etc...)
Edit the App.xaml and do this:
Startup="StartUp"
Then edit the App.xaml.cs and add a StartUp event like so:
private void StartUp(object sender, StartupEventArgs args)
{
...
}
Then inside you can call your login window and then start your main window after that.
var login = new LoginWindow();
if(login.ShowDialog()!=true)
{
//login failed go away
return
}
var mainWin = new MainWindow();
mainWin.Show();

I think the problem is that you are putting you logic in the MainWindow. Try putting it in the static Main() method or in the class App: Application class.
Here is a code project where he is doing something similar for a splash screen:
http://www.codeproject.com/Articles/38291/Implement-Splash-Screen-with-WPF
Here is a tutorial for working with the App.xaml.cs
http://www.wpf-tutorial.com/wpf-application/working-with-app-xaml/

Related

Prism WPF Closing view and dispose autowired ViewModel

In short the behaviour i want to accomplish is LOGIN->LOGOUT->LOGIN
My application starts with a login view. After authentication, it close and the MainView open:
public void Authenticated(){
MainWindow main = new MainWindow();
main.Show();
if (Application.Current.Windows.Count > 1) {
Application.Current.Windows[0].Close();
}
this.CloseAction();
}
the CloseAction is just an action variable which close from the codebehind like so
public partial class MainWindow : Window {
public MainWindow() {
InitializeComponent();
if ( (this.DataContext as MainWindowViewModel)!.CloseAction == null )
(this.DataContext as MainWindowViewModel)!.CloseAction = new Action(this.CloseH);
}
private void CloseH() {
this.Close();
}
}
My main cointains also two view regions pushed from the logic of the MainViewViewModel (THOSE TWO ARE USERCONTROLS)
_regionManager.RegisterViewWithRegion("FileTreeRegion", typeof(FileTree));
_regionManager.RegisterViewWithRegion("FileDetailsRegion", typeof(FileDetails));
At some point if i need to logout i run the function
public void Logout(){
Login login = new Login();
login.Show();
if (Application.Current.Windows.Count > 1) {
Application.Current.Windows[0].Close();
}
this.CloseAction();
// _eventAggregator.GetEvent<AppMessageLogout>().Publish();
// _regionManager.Regions.ToList().ForEach((r) => r.RemoveAll());
}
But when i retry to login, my views viewmodels (the usercontrols FileTree and FileDetails) are called two times (debugging the constructor method).
The previously commented lines are two attempts to solve the issue without success:
using a publish/subscribe command with a Disposable in the UserControl (I disposed only the register commands in the viewmodel since there isn't a Close() in a UserControl)
trashing all the views in the regionManager to avoid garbageCollection. Altought i guess this is useless since, as i read online, the parentWindow of the views is the MainWindow and when it close also the views do
The ViewModels are all autowired with Prism in the xaml files.

mvvmcross WPF show user dialog

How can I show a Loading-Dialog in my MvvmCross Application?
At first, i did it like so(MvvmCross standard);
[MvxWindowPresentation(Modal = true)]
public partial class LoadingView : MvxWindow
{
public LoadingView () => InitializeComponent();
}
and whenever i needed the LoadingDialog;
_navigationService.Navigate<LoadingView>());
This looks really weird because the Modal view is a new window, but i want to achieve a overlay in my main-application.
Second, tried it with a normal User Control and the MaterialDesignThemes nugget;
public partial class LoadingView : UserControl
{
public LoadingView () => InitializeComponent();
}
and whenever i needed the LoadingDialog;
var result = await MaterialDesignThemes.Wpf.DialogHost.Show(new LoadingView ());
This doesnt work, because I think have to register the MaterialDesignThemes.Wpf.DialogHost in the Mvx.IoCprovider before.
The DialogHost does not need to be registered. When you place a dialog host instance in XAML like below, the dialog instance will be registered automatically.
<materialDesign:DialogHost>
<materialDesign:DialogHost.DialogContent>
<!-- ...dialog content -->
<materialDesign:DialogHost.DialogContent>
<!-- ...content -->
</materialDesign:DialogHost>
Internally, the dialog hosts are tracked in a static HashSet. A DialogHost instance is registered when its Loaded event in XAML is fired and deregistered when the Unloaded event occurrs, as you can see from the reference source below. The InvalidOperationException (No loaded DialogHost instances.) exception is only thrown if, there are no loaded instances of DialogHost.
private static readonly HashSet<DialogHost> LoadedInstances = new HashSet<DialogHost>();
public DialogHost()
{
this.Loaded += new RoutedEventHandler(this.OnLoaded);
this.Unloaded += new RoutedEventHandler(this.OnUnloaded);
// ...
}
private void OnLoaded(object sender, RoutedEventArgs routedEventArgs)
{
DialogHost.LoadedInstances.Add(this);
}
private void OnUnloaded(object sender, RoutedEventArgs routedEventArgs)
{
DialogHost.LoadedInstances.Remove(this);
}
In other words, the Show method throws an exception, because you call it in places, where the DialogHost control in your XAML markup is not loaded yet and did not fire the Loaded event, or it is already Unloaded again. Consequently, you have to make sure that the dialog is loaded before calling Show, see a similar issue here.

The 'InitializeComponent' and '_FrameViews' does not exist in the current context

I'm in the process of learning WPF, so in my case I have an xbap application and the code below is the code behind MainView.xaml.cs. Also, it was initially of a Page Type and I just changed it to UserControl recently because I need to deploy this app using ClickOnce.
List of errors:
The name 'InitializeComponent' does not exist in the current context.
The name 'FrameViews' does not exist in the current context.
public partial class MainView : UserControl
{
public MainView()
{
InitializeComponent();
this.DataContext = MainViewModel.UniqueInstance;
MainViewModel.UniqueInstance.FrameNavigationService = _FrameViews.NavigationService;
_FrameViews.Unloaded +=new RoutedEventHandler(_FrameViews_Unloaded);
}
private void _FrameViews_Unloaded(object sender, RoutedEventArgs e)
{
_FrameViews.Content = null;
}
}
}
The InitializeComponent() is only available in MainWindow not in MainView
you need to write like that:
public partial class MainWindow : Window
and the _FrameView doesent exist you need to declare it

How to pass data from Window to MainWindow in WPF?

Im newbie to programming and now i have a problem with my new login window.
I created a new window for login to my server database,but in my mainwindow how do i call it? I don't know how to draw it up better.
In my login window:
using MyS_Database;
MyServer_Database server;
public void LoginButton_Click(object sender, RoutedEventArgs e)
{
server = new MyServer_Database("ClientName","ServerIP","","",UserID.Text,UserPassword.Password.ToString(),"01",MyServer_Database.LoginType.User,out serverresult)
swith(serverresult)
{
case 0:
Mainwindow.Show();
this.Close();
break;
default:
Environment.Exit(0);
}
}
But when I call a method on my MainWindow which is communicating with the server i have to call it like:
server.GetDataFromUserList();
But It doesn't recognize server,I tried something like Win1.server or similars but I failed.
How could i pass it? Thank you in advance!
The quick answer is to make server public like this:
public MyServer_Database Server { get; set; }
Then you can call it in MainWindow with:
Win1.Server.GetDataFromUserList();
But this is not a good approach. Better approach is to abstract away these kind of operations in different classes via MVVM. Read more about MVVM and you'll find great approaches.
Edit
You should also do one one of these two things:
Don't close Win1 instead do this.Hide();
Keep the instance of MyServer_Database in MainWindow by passing it to the constructor of Win1.
You should put this in MainWindow
public MyServer_Database Server { get; set; }
and When needed call this:
var Win1 = new LoginWindow(Server);
Then you have access to Server object in MainWindow

How to access UserControl's DataContext from another UserControl?

I'm working on a legacy application that's written using Silverlight 5, The application contains lot's of anti-patterns and bad practices. I'm responsible for adding real-time interactions (such as notification) using SingalR.
By the way, They're using these WCF RIA Services for interacting with authentication.
They have a Main page, this page is the place where I'm getting user's notification and show them for logged in users:
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
//...
}
}
So as you can see I didn't set DataContext property as long as user is logged in, I need to set MainPage's DataContext after a user logs in to application, So I have to do that in LoginOperation_Completed inside LoginForm page:
public partial class LoginForm : StackPanel
{
private LoginRegistrationWindow parentWindow;
private LoginInfo loginInfo = new LoginInfo();
public LoginForm()
{
InitializeComponent();
//...
}
private void LoginOperation_Completed(LoginOperation loginOperation)
{
if (loginOperation.LoginSuccess)
{
// Here I need to access MainPages's DataContext property and set it with my ViewModel
}
}
}
Now my question is that, how can I set MainPage's DataContext property inside another class (in this case LoginFrom)?
I have also tried to give an ID to my MainPage user control and access it like this:
mainPage.DataContext = new NotificationItemViewModel();
But the compiler gives me this error:
The name 'mainPage' does not exist in the current context
I finally figured out How to solve my question, There is a simple way to achieve this, I should have created the static instance of the MainPage class in the class itself:
public partial class MainPage : UserControl
{
public static MainPage Instance { get; private set; }
public MainPage()
{
InitializeComponent();
Instance = this;
}
}
Now I can access to the MainPage's DataContext this way:
MainPage.Instance.DataContext = new NotificationItemViewModel();
You need to name your MainPage UserControl where you pasted it in LoginForm XAML. Not in the definition of MainPage.

Categories