I am launching an MVVM application with code in the App.xaml.cs like so:
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
//Set data directory
string baseDir = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData) + #"\BlowTrial";
if (!Directory.Exists(baseDir))
{
Directory.CreateDirectory(baseDir);
}
AppDomain.CurrentDomain.SetData("DataDirectory", baseDir);
//Application initialisation
AutoMapperConfiguration.Configure();
//Security
CustomPrincipal customPrincipal = new CustomPrincipal();
AppDomain.CurrentDomain.SetThreadPrincipal(customPrincipal);
// Create the ViewModel to which
// the main window binds.
var mainWindowVm = new MainWindowViewModel();
MainWindow window = new MainWindow(mainWindowVm);
// When the ViewModel asks to be closed,
// close the window.
EventHandler handler = null;
handler = delegate
{
window.Close();
if (!window.IsLoaded) //in case user cancelled close event
{
mainWindowVm.RequestClose -= handler;
}
};
mainWindowVm.RequestClose += handler;
window.Show();
}
I would like to test for the existence of entities containing important data for running the application, and if these do not exist, run a wizard (as a dialog) which obtains these settings:
if (BlowTrialDataService.GetBackupDetails().BackupData == null
|| !_repository.LocalStudyCentres.Any())
{
DisplayAppSettingsWizard();
}
static void DisplayAppSettingsWizard()
{
//testfor and display starup wizard
var wizard = new GetAppSettingsWizard();
GetAppSettingsViewModel appSettings = new GetAppSettingsViewModel();
wizard.DataContext = appSettings;
EventHandler wizardHandler = null;
wizardHandler = delegate
{
wizard.Close();
wizard = null;
appSettings.RequestClose -= wizardHandler;
};
appSettings.RequestClose += wizardHandler;
wizard.ShowDialog();
}
When I place this code in the MainWindow.xaml.cs, the application runs correctly. When it is placed in either the App.xaml.cs (before the code to instantiate the instance of MainWindow), or in the constructor for MainWindowViewModel, the wizard displays correctly, but the application ends without displaying the MainWindow on completion of the wizard. If there is no cause to display the wizard, MainWindow displays correctly in all cases.
Examining the debug output, there are no errors of note (a few first chance exceptions related to sql commands).
Is there a reason for this - having the code in the code behind MainWindow.xaml does not seem the most logical place (which to my mind would be the app.xaml.cs).
Thank you for your expertise.
The default value of ShutdownMode is System.Windows.ShutdownMode.OnLastWindowClose which means if the last window was closed App will shutdown.
You didn't put all in code in here, I suppose that setting wizard window didn't show before main window closed, this lead app exit.
I suggest you set shutdownmode to OnExplicitShutdown which you can decide when to close your app by your own.
Related
I have a requirement to show a progress bar in my WPF application when I navigate from one view to another view. I've a service to show and close the progress bar. My code to show the progress bar goes like below. And it's showing perfectly fine.
public void ShowProgressBar<T>() where T : Window
{
var thread = new Thread(
new ThreadStart(
delegate ()
{
_progressWindow = Activator.CreateInstance<T>();
_progressWindow .Show();
_currentDispatcher = Dispatcher.CurrentDispatcher;
Dispatcher.Run();
}
));
thread.SetApartmentState(ApartmentState.STA);
thread.Priority = ThreadPriority.Highest;
thread.IsBackground = true;
thread.Start();
}
After the progress bar is being shown, I'm trying to navigate to another view using viewManagementService wherein it removed existing view from the region if any and adds the new view and Since I know the last method that gets hit, I'm trying to close my progress bar there withe same service class being injected into its constructor and my closing logic goes like this.
public void CloseProgressBar()
{
if (_progressWindow != null && _currentDispatcher != null)
{
//Close the window and shutdown the dispatcher.
_currentDispatcher.Invoke(() => CloseWindow());
}
else if(_progressWindow != null && _currentDispatcher == null)
{
_progressWindow.Close();
}
}
/// <summary>
/// CloseWindow
/// </summary>
private void CloseWindow()
{
_progressWindow.Close();
_currentDispatcher.InvokeShutdown();
}
But, while trying to do this, it's sometimes saying that the task is already cancelled or it's saying that the task is being owned by a different thread. I couldn't figure out whether the problem is with my code or the way I'm doing?
Any suggestion is highly appreciated. Thank you.
To simulate a modal dialog in WPF, I display a Window and call: Mouse.Capture(dialogBoxArea, CaptureMode.SubTree);
The call returns false.
Mouse.Captured is null.
dialogBoxArea.Visibility is Visibility.Visible.
dialogBoxArea.IsEnabled is true.
If the line is called again a second time, it returns true and correctly captures the mouse.
What condition might I be missing that is preventing the capture from working?
Edit
Here's what I've tried so far.
if (Mouse.Captured != null)
{
// Not called, so presumably, nothing has already captured the mouse
MessageBox.Show("already captured");
}
if (dialogBoxArea.Visibility != Visibility.Visible)
{
// Not called
MessageBox.Show("not visible");
}
if (!dialogBoxArea.IsEnabled)
{
// Not called
MessageBox.Show("not enabled");
}
// According to documentation, this should release mouse capture from anything that holds it
Mouse.Capture(null);
// Attempt to capture the mouse
if (!Mouse.Capture(dialogBox, CaptureMode.SubTree))
{
// This is called
Mouse.Capture(null);
Mouse.Capture(dialogBox, CaptureMode.SubTree);
}
As a first iteration i would talk to your client.
The following opens a dialog option window that is always on top of the original window and blocks calls to it, but does not hinder the overall execution at all. If your customer sees the behaviour he may be happy with that.
namespace StackoverflowExample
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
void NewWindowAsDialog(object sender, RoutedEventArgs e)
{
Window myOwnedDialog = new Window();
myOwnedDialog.Owner = this;
myOwnedDialog.ShowDialog();
}
}
}
I will post another option later here that will illustrate how to load a window into a subdivision (grid etc.) of your xaml. You could filter all other calls based on the content that is loaded into that division rather then filtering the mouscall. Your filtering could run into the problem of the logical vs the viewtree - you only ever want to look at the trees if you create your own templates from scratch.
So I have a WPF application (MVVM) with a Splash Screen. On the splash screen startup I have a background thread on the ViewModel that does some start up related activities. In certain instances I want to open a couple of additional windows (user input needed etc...). I was getting a number of issues/errors/exceptions while trying to do this (mostly around that new window - also MVVM - trying to populate its UI items, such as combo boxes). So I've pulled back the issue to a simpler form - the "tempWindow" doesn't have anything so it doesn't throw UI population errors, but basically it does just open them and once the background thread is done, closes them all. If someone could point me in the right direction on what I am doing incorrectly here it would be appreciated.
The constructor for the ViewModel kicks off a background thread
public SplashScreenViewModel()
{
this.LoadingStatusText = "Starting Startup Processing ... ";
this.VersionNumber = "version " + System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString();
var threadBackgroundStartUpProcesses = new Thread(new ThreadStart(this.BackgroundStartUpProcesses));
threadBackgroundStartUpProcesses.SetApartmentState(ApartmentState.STA);
threadBackgroundStartUpProcesses.IsBackground = true;
threadBackgroundStartUpProcesses.Start();
}
The background thread, should just open three windows (which it does) but those windows should stay open (they disappear once the thread completes).
private void BackgroundStartUpProcesses()
{
for (int i = 0; i < 3; i++)
{
var objTempWindow = new tempWindow();
objTempWindow.Show();
}
}
// EDIT: updated with responses, now get an error when the TempWindow has a comboBox that is being populated from the TempWindowViewModel.
private void BackgroundStartUpProcesses()
{
for (int i = 0; i < 3; i++)
{
var objTempWindow = new tempWindow();
objTempWindow.Show();
}
System.Windows.Threading.Dispatcher.Run();
}
When it goes to open the TempWindow the exception: "The calling thread cannot access this object because a different thread owns it." is thrown and appears to be when a ComboBox on that Window is trying to be populated.
I suspect that windows need an owner and when the owner dies, so does the window. Opening the windows on the main thread makes them stick around. Something like this...
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
var threadBackgroundStartUpProcesses = new Thread(new ParameterizedThreadStart(this.BackgroundStartUpProcesses));
threadBackgroundStartUpProcesses.SetApartmentState(ApartmentState.STA);
threadBackgroundStartUpProcesses.IsBackground = true;
threadBackgroundStartUpProcesses.Start(System.Windows.Threading.Dispatcher.CurrentDispatcher);
}
private void BackgroundStartUpProcesses(object d)
{
System.Windows.Threading.Dispatcher dispatcher = (System.Windows.Threading.Dispatcher) d;
for (int i = 0; i < 3; i++)
{
dispatcher.BeginInvoke((Action)(() =>
{
var objTempWindow = new tempWindow();
objTempWindow.Show();
}));
}
}
}
edit
I've just done some digging on WPF threading and it looks like you can open windows on multiple threads, but you need to start the new dispatcher. See near the end of this page:
http://msdn.microsoft.com/en-us/library/ms741870.aspx
In your BackgroundStartupProcesses, under objTempWindow.Show() add this line
System.Windows.Threading.Dispatcher.Run();
Are you setting your MainWindow before closing the splash screen? WPF sets the first opened window of an application as the MainWindow and unless you've changed the ShutdownMode of your App.xaml then once you close the splash screen the application shuts down.
Some context here...I have a System.Windows.Window that is used to display a modal message box. I created a Show() method that initializes the content of the window, and then calls ShowDialog(). The user clicks a button on this window, some information about the clicked button is set in the Tag property, and then the window is closed via Close().
As expected, I get a ShowDialog Exception when attempting to call ShowDialog() on the Window once is has been closed. Is there some way to reuse that same Window instance so that I don't have to new up an instance every time I need a message box?
For example...
MessageBoxWindow mbw = new MessageBoxWindow();
result = mbw.Show("caption", "message 1");
mbw.Show("caption", "message 2");
// The above throws an exception, so I have to do this...
mbw = new MessageBoxWindow();
result = mbw.Show("caption", "message 2");
Any help would be greatly appreciated!
Use .Hide() instead of .Close(). That removes it without destroying it. Then you can call Show() again when needed.
MainWindow test = new MainWindow();
test.Show();
test.Hide();
test.Show();
You can add a FormClosing event that cancels the form close and instead sets the Form.Visible to false. Then you would also need Show method that checks if this Form is null, so you would know whether you need to create a new Form or just show the one you already have.
For example:
private void FormMessageBox_FormClosing(object sender, FormClosingEventArgs e)
{
//This stops the form from being disposed
e.Cancel = true;
this.Visible = false;
}
public static void Show(FormMessageBox formMessageBox, string message)
{
//if formMessageBox is null we need to create a new one otherwise reuse.
if (formMessageBox == null)
{
formMessageBox = new FormMessageBox(message);
formMessageBox.ShowDialog();
}
else
{
formMessageBox.lblMessage.Text = message;
formMessageBox.Visible = true;
}
}
In my WPF app (csharp) I have an event handler that when triggered will open a new window (window B) of the application and display some data. However, when the event is triggered again, if the new window (window B) is still open, I don't want to spawn another instance of window B but just update the data being displayed in the current instance. So the question is: How to detect if window B is already and only open if it is not already, otherwise just update the data?
I found the Application.Current.Window collection but somehow that isn't working for me yet. Ideas?
You could create a LoadWindow() method in WindowB that you can call to load (or refresh) the data & that will work regardless of if the window is already open or not. Have it take a delegate to call when this window gets closed:
private Action ParentCallbackOnClose;
public void LoadWindow( Action parentCallbackOnClose ) {
// load the data (set the DataContext or whatever)
ParentCallbackOnClose = parentCallbackOnClose;
// Open the window and activate/bring to the foreground
Show( );
Activate( );
}
and have your window closed event call the close delegate:
private void WindowClosed( object sender, EventArgs e ) {
ParentCallbackOnClose.Invoke( );
}
Now, from your class that opens Window B, have it hold onto that instance it opens, so that if WindowB is already open when someone tries to reload it, it just calls LoadWindow on the existing instance. Something like...
private WindowB WinB;
private void LoadWindowB(Content content)
{
if (WinB == null ){
WinB = new WindowB( );
}
WinB.LoadWindow(content, WindowBClosed);
}
And then you can just have it null out WinB on that close callback so if WinB is closed, then the next time LoadWindowB() is called it will create a new instance of it:
private void WindowBClosed( ){
WinB = null;
}
Since this is the first link Google listed, which posted several years ago, for a solution to check if a Window is already open, I'll post my answer, for others, which I find easier to implement. The ChildWindow is only called from MainWindow so no other Window will need to do any checks.
private void OpenChildWindow()
{
if (this.OwnedWindows.OfType<ChildWindow>().Count() > 0)
{
ChildWindow Win = this.OwnedWindows.OfType<ChildWindow>().First();
Win.Activate();
}
else
{
ChildWindow Win = new ChildWindow();
Win.Owner = this;
Win.Show();
}
}
There is an old school way to do this using an interface. I see this in Java a lot as a way to compensate for not having delegates (correct me if I am wrong). This method will allow you to check if there is a window already open (of any kind). The original response works very well, but you can also do it the following way:
Create the interface
public interface IWindowTracker
{
void WindowIsOpened();
void WindowIsClosed();
}
Implement the interface on the parent (from where you are opening):
public partial class MainWindow : Window, IWindowTracker
In your constructor, accept an object that is of the IwindowTracker interface. Save the instance for future use
IWindowTracker windowTracker;
public ProjectManager(IWindowTracker parentWindowTracker)
{
windowTracker = parentWindowTracker;
InitializeComponent();
}
Setup the calls to the window tracker object
protected override void OnActivated(EventArgs e)
{
windowTracker.WindowIsOpened();
base.OnActivated(e);
}
protected override void OnClosed(EventArgs e)
{
windowTracker.WindowIsClosed();
base.OnClosed(e);
}
and finally implement the IWindowTracker in your parent WPF window
bool windowIsOpen = false;
public void WindowIsOpened()
{
windowIsOpen = true;
}
public void WindowIsClosed()
{
windowIsOpen = false;
}
This will allow you to keep track of if the window is still open and if it is, there is no need to open a new instance of it:
if (!windowIsOpen)
{
remoteProjectManager = new ProjectManager(this);
remoteProjectManager.Show();
}
remoteProjectManager.Focus();
Calling show() on a closed window seems to throw an exception, so my guess is that there is some other way or that if you have closed the window, the window is technically "destroyed"
The nice thing to this is that I can detect if the window is still open and focus on it (so that it comes to the front again).
NOTE: There is a draw back to this, in that in this setup it limits you to opening only one window at a time (assuming that all your windows are implemented like this). In my case, I only ever want to have one window open besides the main window.
You might also want to check if your window is null or not, considering that it probably isn't the only window you will have to open.
edit: oops, my answer is specific to Windows Forms. i just now saw the WPF mention. i'm not sure what the specific code would be for WPF, but i would imagine that it's not all that different conceptually. I think in WPF the property is called IsVisible instead of Visible
You could hold on to the instance of your window (or make it a Singleton) and then when you need to determine if it is visible or not, check it's Visible property.
for example:
if(myWindow.Visible){
myWindow.Hide();
}else{
myWindow.Show();
}
This article it the best I found for passing data between WPF pages. The author used KISS approach to provide a simple solution.