In my current solution I have 2 projects:
1) A ClassLibrary project containing models and view models and
2) a project called UI containing 2 windows, a LoginWindow and a MainWindow.
Currently, the UI project has a reference to the ClassLibrary project to get the view models. The problem arises when I want to change the window from the LoginWindow to the MainWindow. I have read some articles and searches the internet for a few days now, but nothing seems to give a satisfying result in terms of what I am actually looking for. Typically it concerns a single window maintaining/switching between multiple views. That's not what I want. I want the LoginWindow to change to the MainWindow and close the LoginWindow on a button click. How is this achievable?
Edit1: I guess I need to clarify that I am using MVVM and need to access appropiate view models. I can’t just make a new instance of a certain window whenever needed and show it while hiding the other.
Edit2:
public static class MainTest
{
public static int Test()
{
Thread app = new Thread((ThreadStart)delegate
{
LoginWindow login = new LoginWindow();
LoginViewModel loginVM = new LoginViewModel();
if (loginVM.IsLoggedIn == false)
{
return -1;
}
else
{
MainWindow mainWindow = new MainWindow();
mainWindow.Show();
}
}
app.SetApartmentState(ApartmentState.STA);
app.Start();
return 0;
}
}
[SOLVED] At return -1 I get an error saying: "Anonymous function converted to a void returning delegate cannot return a value"
At app.SetApartmentState(ApartmentState.STA);I get an error saying: Argument2: cannot convert from 'void' to 'int'. I assume this has something to do with the delegate, you've written at the very top of the code.
Edit3:
Try this,
In your app.config file define the StartupUri xaml as login.xaml :
Application x:Class="CapronCRM.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="Login.xaml">
And in your login xaml, when the login attemt is successfull, call this code :
MainWindow mw = new MainWindow();
mw.Show();
this.Close();
I usually use a main class to do this.
Create a main class that has this method inside
public static int Main()
{
Thread app = new Thread((ThreadStart)delegate
{
MyLoginControl login = new MyLoginControl();
MyLoginVM lvm = new MyLoginVM();
login.DataConetxt = lvm;
login.ShowDialog();
if (lvm.IsLoginFailed)
{
return;
}
else
{
MainWindow myApp = new MainWindow();
MyAppVm avm = new MyAppVm();
myApp.DataContext = avm;
myApp.ShowDialog();
}
}
app.SetApartmentState(ApartmentState.STA);
app.Start();
return 0;
}
In your project Properties (in visual studio right click on your project --> Properties) in the application tab set your Main class as startup object
This will allow you to run the login and check also the result before starting the actual application, without shutting down when the login view return
EDIT: Added an example of how you can use your VM. The point is that you can do what you want in this method. It's only purpose is to prevent the application to shutdown when the login view return (normally a Dispose() would be launched internally causing the shutdown of the application on window return)
EDIT2: there was a little error in my code. Fixed
Related
I have a WPF Application. I need to minimize and restore the main window after instantiate it to obtain focus. I am using something like the following class but it is not making what I want because when the window is restored it has an invalid size. I've tried to modify the width and height but it is not working.
public class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
ConfigureWindow();
}
public void Show()
{
base.Show();
UpdateWindowPositionAndSize();
base.WindowState = WindowState.Normal;
base.Show();
}
private void ConfigureWindow()
{
base.ShowActivated = true;
this.Focusable = true;
if (base.IsActive == false)
{
base.Activate();
}
if (base.IsFocused == false)
{
base.Focus();
}
base.WindowState = WindowState.Minimized;
}
private void UpdateWindowPositionAndSize()
{
this.Top = (SystemParameters.WorkArea.Height - this.Height) / 2;
this.Left = (SystemParameters.WorkArea.Width - this.Width) / 2;
}
}
What I am doing wrong? There is another way to obtain the focus? Sorry if the question is too newby.
UPDATED:
What is the specific need?
I need that my WPF Application appears on focus and active after launch it.
why?
Since it will be launched by a Windows (7, 8.1 and 10) User after explicitly click on a submenu from a file context menu (meaning a Shell Extension). This is 'why' my client wants that appears on front of the screen and focused.
when?
After instantiate the window.
how?
Well, I made some research and I found several ways to do this. One of the methods that I've tried is minimize the window and the restore it. There where others like using the functions SwitchToThisWindow or setforegroundwindow, but I would like to know if there are better options.
What happen when I've tried minimize and restore the window? (correct size)
Well, this way gives me focus on the main window, but it change the width and heigh. By default I define them on 300 (w) and 300 (h), but after changing the windows state to normal these values change to 400 (w) and 350 (h).
If I dont do anything, it has the focus right away?
... No ...
UPDATE2:
I choose the method used in the next link:
https://www.roelvanlisdonk.nl/2014/09/05/reliable-bring-external-process-window-to-foreground-without-c/
I am not quite sure what your problem is but maybe this can help.
1.) Remove StartupUri="MainWindow.xaml" from App.xaml;
2.) Add Startup="Application_Startup"
Your App.xaml.cs should look like this:
public partial class App : Application
{
private void Application_Startup(object sender, StartupEventArgs e)
{
//Create new Instance of MainWindow
MainWindow mainWindow = new MainWindow();
//Set Properties of that Window
UpdateWindowPositionAndSize(mainWindow);
//Show it !
MainWindow = mainWindow; //This is the Application.MainWindow Property - not needed
mainWindow.ShowDialog();
}
private void UpdateWindowPositionAndSize(MainWindow mainWindow)
{
//Do your modifications here
mainWindow.Top = (SystemParameters.WorkArea.Height - mainWindow.Height) / 2;
mainWindow.Left = (SystemParameters.WorkArea.Width - mainWindow.Width) / 2;
}
}
So basically you just modify your Window until all is done.
There is no need to show it first, change its position and then bring it back on - if I got your "usecase" right.
Because to me it looks like you are hiding the window to do your "positioning".
But I think it's better to do it when Initializing.
Just a short comment on your code so far:
ConfigureWindow() is only doing minimize.
The rest of your code is useless cause obviously the window loses focus when it's minimized.
I would suggest not to create methods with names that already exist.
This will only lead to cusfusion.
If you got problems with WindowState = WindowState.Minimized; you can try Hide() and Activate().
By default when calling Window.Show(); the window will have focus. Check here for details.
Also after setting WindowState = WindowState.Minimized; you don't need to call base.Show(); again - the window is shown already. WindowState = WindowState.Normal; should do the job.
I have a login window that appears in the following scenarios:
Application starts: if the user has not logged in ( client id that is stored in the Properties.Setting ), the login window appears. The user logs in, the login windows closes and the main opens upon success.
The user is already logged in, but now wants to log in as a different user: the user presses a the login button and the login window appears and the user logs in. Upon success, the login window closes, and the new user's information is displayed in a small textbox.
The problem here is that I want to use the same login window in both scenarios. What I imagined was a custom callback method for each of these scenarios that would be invoked upon logon success. I'm facing the problem of accessing LogonWindow through my LogonViewModel, where the logic of logging in happens. The reason for this, is that I want to close the window upon success and do other stuff.
Here's my code:
App.xaml.cs
private void check()
{
if (isloggedin)
{
Client c = new Client();
Main m = new Main(c);
m.Show(); //
}
else
{
LoginViewModel vm = new LoginViewModel();
vm.callback = (loginViewModel, client) =>
{
// the user logged in, now show the window and close the login window
Main m = new Main(client);
m.Show();
// close LoginWindow after we're done logging in.
// But where? Who has access to window?
};
LoginWindow lw = new LoginWindow(vm);
lw.Show();
}
}
LoginViewModel.cs
public class LoginViewModel : ViewModelBase
{
public Action<LoginViewModel, Client> callback { get; set; }
public LoginViewModel()
{
}
public ICommand SignIn
{
get
{
return new RelayCommand<object>(signin, o => canLogin());
}
}
private bool canLogin()
{
return true;
}
private void signin(object o)
{
if (clogin.login())
{
Console.WriteLine("Client Found!");
Client client = clogin.getClient();
// save settings
Properties.Settings.Default.clientid = client.Uid;
Properties.Settings.Default.Save();
Client = client;
// pass the new client, and pass the current view model?
callback(this, client);
}
}
}
The initial thought was the to pass the entire window object to the viewmodel, but I think that's breaking essence of MVVM and the be able to Close the window from within my callback method since I'm already passing in the LoginViewModel. My question, is there a way to achieve what I'm trying to do? Remember, the essence is to do something after the user's logged in successfully depending from which point in my application... Thanks for the input.
In your situation I would add two events to my ViewModel
public event Action<Client> SignInSucceded;
public event Action CloseApplication;
When you create your Viewmodel you can bind the actions you want to get performed onsign in to the events.
So for example you could either create the mainwindow and show it or grab an existing one and show it.
Same procedure with the close call. Just bind an method that performs a close for all views and components that arent needed.
Because of the fact that when you bind your viewmodel to this event you 've got a valid instance of it there should be no problem on binding it. I do not know what your client class is exactly but you could move the creation of this in the method that is bind to the event and just call the event with a uid.
Edit:
In your App.xaml.cs you keep a Property that beholds the instance for your windows then you can do sthh like:
viewModel.CloseApplication += () => this.mainWindow.Close();
Just pay attention to synchronization (Dispatcher)
I hope I did understand your intentions correctly.
This question already has an answer here:
Pass Parameters Between Windows
(1 answer)
Closed 7 years ago.
My problem is, to pass some information from a WPF window to an existing WPF page. I would like to open a the window by pressing a button on WPF Page1.
Then, i have to get all the text stored in Textbox1 to a variable in Page1. But only when the user presses ButtonXY on the "Window". How can i solve this Problem without using the "Bindings" because there has to be abig "Switch" clause next to Page1?
If you are using MVVM then both the window and the page could have a common ViewModel and those TextBoxes should be bound to the same property with UpdateSourceTrigger set to PropertyChanged and this way no more events or notifications are needed.
Otherwise, sometimes i tend to create a global project which will be added as a references where needed. This way, you will be able to set events and their handlers to accomplish your specific issues. I think this is not an elegant solution but it helps me a lot communicating between different projects or classes.
Make a new class that will contain all your data you want to transfer between all your windows.
public YourNewClassWithSettings
{
string StringNumber1;
string StringNumber2;
}
Create an instance of this class in your main window and set the values of the properties you want.
Pass the instance of YourNewClassWithSettings by reference to your constructor of your next window.
YourNewClassWithSettings test = new YourNewClassWithSettings();
test.StringNumber1 = "mySetting";
WindowControl w = new WindowControl(ref test);
w.ShowDialog();
//See what was changed!!!!
string changedValue = test.StringNumber1; //Will be "IamDone"
In your constructor you would say:
public WindowControl(ref YourNewClassWithSettings test)
{
// example: You can now say TextBox1.Text = test.StringNumber1;
// Whatever you change here like test.
test.StringNumber1 = "IamDone";
//When you close this window, because test was passed by ref : you
// will see StringNumber1 = "IamDone" in your main window again
//when accessing the property of that class. Always pass by ref
this.Close();
}
This is the MVVM approach.
Lets assume you have a MainWindow and a SubWindow.
Your SubWindow contains a Button and a Textbox. When you click on the Button in the SubWindow you want to transfer the Text from the Textbox into the MainWindow.
Main Window.
You implment a Property (a Getter and Setter) wich will contain the transfered Text string. The MainWindow contains also the SubWindow! Don't forget to pass the MainWindow into the SubWindow Constructor (look below) so the SubWindow know the MainWindow instance
public partial class MainWindow : Window
{
public string Text { get; set; }
private Window subWindow;
public MainWindow()
{
InitializeComponent();
subWindow = new SubWindow(this);
subWindow.Show();
}
}
SubWindow
public partial class SubWindow : Window
{
private Window mainWindow;
public SubWindow(Window mainWindow)
{
this.mainWindow = mainWindow;
InitializeComponent();
}
private void ButtonTransferTheData_Click(object sender, RoutedEventArgs e)
{
mainWindow.Text = myTextBoxInSubWindow.Text;
}
}
Your SubWindow knows the MainWindow. So you can access the Text Property. On the Button click you wirte the Text from the Textbox into the Property of the MainWindow.
HINT
The mainWindow.Text = myTextBoxInSubWindow.Text; line could throw an exception. this is because you want to access a thread from another.
So you need to dispatch it. Change this line into:
Dispatcher.Invoke(() => mainWindow.Text = myTextBoxInSubWindow.Text);
Hope this helps.
My problem deals with the following 3 forms:
MainWindow.cs
SettingsWindow.cs
AuthenticationWindow.cs
Settings window contains information like "Ask for password during startup or not".
I call the Authentication Window from Settings Window in order to remove password (when the password is set).
I call the Authentication Window also during startup (when the password is set).
My Authentication Window interacts with the settings window using a Static variable(To say whether the authentication is successful or not).
But, in order to reuse the same code (that is, to call the same authentication window during startup), I am unable to tell the MainWindow whether the authentication is successful or not.
However, I must some how reuse the code.
My question is: Is it possible to notify the Child Window about whom the parent window is? If yes, Sample code please...
Hope my question is clear.
Kindly help!
I assume that Authentication Window is being used with ShowDialog() along the lines of:
AuthenticationWindow auth = new AuthenticationWindow();
if (auth.ShowDialog(this) == DialogResult.Ok)
{
// we know it was successful
}
Then within AuthenticationWindow when you've had success you'll call:
DialogResult = DialogResult.Ok;
Close();
to get the feedback above, or to signal that it failed by
DialogResult = DialogResult.Cancel;
Close();
Alternatively, you could set a property on AuthenticationWindow:
class AuthenticationWindow : Form
{
public bool Success { get; set;}
}
and set the value of Success appropriately from within the AuthenticationWindow code.
Lastly, if you want immediate feed back to be sent to your other windows, consider implementing an event:
class AuthenticationWindow : Form
{
public event Action<bool> SignalOutcome;
private OnSignalOutcome(bool result)
{
Action<bool> handler = SignalOutCome;
if (handler != null) handler(result);
}
}
Then you will have to subscribe to that event where you call the Authentication window:
AuthenticationWindow auth = new AuthenticationWindow();
auth.SignalOutcome += (outcome) => { /* do something with outcome here */ };
auth.ShowDialog(this);
ChildWindow c1=new ChildWindow();
c1.Owener=authenticationWindow;
c1.Show(); //or ShowDialog();
ChildWindow c2=new ChildWindow();
c1.Owener=anotherWindow;
c2.Show(); //or ShowDialog();
//to get the parent, use the property c.Owner
if(c.Owner is AuthenticationWindow) //AuthenticationWindow is the type of authenticationWindow instance
{
...
}
Basically, I have a settings window, and when you click "OK", it's suppose to apply settings to the main form (eg, set font of a control, etc), and then close.
frmmain frm = new frmmain();
frm.OLVAltBackColor = Color.Aquamarine ;
I tried that, but it only applies the settings to that instance, and you can see it if you do frm.Show();
I'm trying to make it so the already opened form has it's control's properties changed.
What you are trying to do is not working because you are creating a NEW instance of your main form and updating that rather than the first instance. It is possible to update the main form by keeping a reference to it in your settings form... but...
...it sounds like you are approaching this from the wrong direction.
Don't make the settings form dependent on the main form. Instead create the settings form from the main dialog.
class SettingsForm : Form
{
// You need to ensure that this color is updated before the form exits
// either make it return the value straight from a control or set it
// as the control is updated
public Color OLVAltBackColor
{
get;
private set;
}
}
In your main form
(I'm assuming some kind of button or menu click)
private void ShowSettingsClicked(object sender, EventArgs args)
{
using (SettingsForm settings = new SettingsForm())
{
// Using 'this' in the ShowDialog parents the settings dialog to the main form
if (settings.ShowDialog(this) == DialogResult.OK)
{
// update settings in the main form
this.OLVAltBackColor = settings.OLVAltBackColor;
}
}
}
Apply the property change to the form that already exists and is already shown instead of creating a new form and changing that one.
In this code you're creating a new instance of the frmmain. Any changes you make to that new object will happen in the new object, not the one you actually want to change.:
frmmain frm = new frmmain(); //Creating a new object isn't the way.
frm.OLVAltBackColor = Color.Aquamarine ;
What you're looking for is a way to call on the already existant frmmain class and change the property of that.
Edit, for example:
using System;
class Statmethod
{
//A class method declared
static void show()
{
int x = 100;
int y = 200;
Console.WriteLine(x);
Console.WriteLine(y);
}
public static void Main()
{
// Class method called without creating an object of the class
Statmethod.show();
}
}