I have a WPF app, in file Main.xaml.cs I have the following constructor:
public MainWindow()
{
InitializeComponent();
Loaded += new RoutedEventHandler(MainWindow_Loaded);
}
from another class:
In App.xaml.cs
I need to fire an event which will make run method MainWindow_Loaded in Main.xaml.cs
Any idea how to do it?
You can do this by manually creating the MainWindow in your App class. To do it, remove the StartUp attribute from the App.xaml so that it looks like this...
<Application x:Class="Anything.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
>
</Application>
In your App.xaml.cs class, override the OnStartup method like this...
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
MainWindow mw = new MainWindow();
mw.Loaded += mw_Loaded;
mw.Show();
}
void mw_Loaded(object sender, RoutedEventArgs e)
{ // loaded event comes here
throw new NotImplementedException();
}
}
This override manually creates the MainWindow and shows it. It also subscribes to the Loaded event and receives the notification in the mw_Loaded method. You can also call the window's method directly because you have the window instance.
Alternatively, you can overload the MainWindow constructor and pass it an Action delegate. It would look like this...
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
MainWindow mw = new MainWindow(DoSomething);
mw.Show();
}
public void DoSomething()
{
}
}
And the MainWindow would look like this...
public partial class MainWindow
{
private readonly Action _onLoaded;
public MainWindow(Action onLoaded)
{
_onLoaded = onLoaded;
InitializeComponent();
Loaded += MainWindow_Loaded;
}
void MainWindow_Loaded(object sender, System.Windows.RoutedEventArgs e)
{
_onLoaded();
}
}
That gives you two alternatives, there are other ways also, but these are the most expedient. As Sheridan pointed out, tinkering with a window's loaded event can have confounding side effects, like re-entrancy. The WPF forefathers envisioned it as a lifetime event.
Related
I have a wpf project without StartupUri. I set the MainWindow as TestWindow in app.cs. But i can't use the DoNothing method. How can i access to methods of TestWindow?
MainWindow.DoNothing(); //No such method. Get error when try to build
Project:
TestWindow.cs
public partial class TestWindow : BaseWindow
{
...
public void DoNothing()
{
return;
}
...
}
app.xaml
<Application x:Class="Test.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Test"/>
app.cs
...
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
MainWindow = new TestWindow();
}
...
Cast MainWindow to your type:
(MainWindow as TestWindow)?.DoNothing();
Or store a reference to the TestWindow in a variable of your own and access the window directly using this one:
public partial class App : Application
{
private readonly TestWindow testWindow = new TestWindow();
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
MainWindow = testWindow;
...
testWindow.BeginInit();
}
}
I have a WPF application that host a service, the code behind is this:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
_host = new ServiceHost(typeof(GestorAplicacionesService));
_host.Open();
}
private ServiceHost _host;
}
I have read that it is good practice to close the service, but I don't know how to do it in this case? Because I have the main window, that if I close the application, I could close the service in the closing event. How ever, if there are some exception that could break the application that doesn't fire the closing event, then the service wouldn't be close.
So I was wondering how it would be the best way to close the service when it is hosted in a wpf application.
Thanks.
Handle the Closing event and close it there. You may also want to implement the IDisposable interface to cope with best practises for disposable fields:
public sealed partial class MainWindow : Window, IDisposable
{
private readonly ServiceHost _host = new ServiceHost(typeof(GestorAplicacionesService));
public MainWindow()
{
InitializeComponent();
_host.Open();
Closing += MainWindow_Closing;
}
private void MainWindow_Closing(object sender, CancelEventArgs e)
{
Dispose();
}
public void Dispose()
{
_host.Close();
_host.Dispose();
}
}
This is the best you can do. If the entire process gets shut down unexpectedly, there is not much you can do about it in your WPF application. The memory will still be returned to the operating system.
you can check that all in app.xaml
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
this.DispatcherUnhandledException += App_DispatcherUnhandledException;
base.OnStartup(e);
}
private void App_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
{
((MainWindow)Application.Current.MainWindow).host.Close();
}
protected override void OnExit(ExitEventArgs e)
{
if (((MainWindow)Application.Current.MainWindow).host.State == System.ServiceModel.CommunicationState.Opened)
((MainWindow)Application.Current.MainWindow).host.Close();
base.OnExit(e);
}
and for threading issues please follow this link : https://soumya.wordpress.com/2010/05/26/wcf-simplified-part-7-hosting-a-wcf-service-using-wpf/
I got an Problem with Events. I got a first Window which looks like this:
using System.Windows;
namespace EventsTests
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
/*Binding Event to MainWindow
dont work until you will help*/
MainWindow mw = new MainWindow();
mw.RaiseEvent += raiseEvent_EventHandler;
}
public void raiseEvent_EventHandler()
{
MessageBox.Show("MAINWINDOW Event Fired");
}
private void Button_Click(object sender, RoutedEventArgs e)
{
SecondPage sp = new SecondPage();
sp.Show();
}
}
}
Now the seconde Page donĀ“t do very much:
using System.Windows;
namespace EventsTests
{
/// <summary>
/// Interaction logic for SecondPage.xaml
/// </summary>
public partial class SecondPage : Window
{
SecondPageViewModel spvm = new SecondPageViewModel();
public SecondPage()
{
this.DataContext = spvm;
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
spvm.raiseEventActivate();
}
}
}
And at last I have the SecondPageViewModel:
namespace EventsTests
{
public delegate void raiseEventEventHandler();
class SecondPageViewModel
{
public event raiseEventEventHandler raiseEvent;
public void raiseEventActivate()
{
if(raiseEvent != null)
{
raiseEvent();
}
}
}
}
Now I want, when I click the button on the second page, the Event is fired an the MainWindow recognise the event.
With this code i get the Error:
Error 1 Cannot assign to 'RaiseEvent' because it is a 'method group'
Can someone help me? Or give me an example?
Thanks for every hint ;)
RaiseEvent is not your event, it's a method of the Window.
I think you want to do this:
SecondPage sp = new SecondPage();
sp.raiseEvent += raiseEvent_EventHandler;
sp.Show();
That is, register an event handler with the second page event.
Though I wouldn't advocate event handlers for this. While I don't know what you are trying to achieve I'd rather do something like pass a ViewModel object to the SecondPage and the main window can respond to state changes on that ViewModel.
In WPF, I always aim for zero code behind.
In response to discussion, how one VM could have reference to another. First pass the VM in:
SecondPageViewModel spvm;
public SecondPage(SecondPageViewModel model)
{
spvm = model;
this.DataContext = spvm;
InitializeComponent();
}
Then the SecondpageVM takes a MainVM as a paramter in the constuctor:
SecondPage sp = new SecondPage(new SecondPageViewModel(mainVM));
Updates to the main model are done within the SecondPageViewModel. The second page itself has no references to it.
ThirdPage tp = new ThirdPage(new ThirdPageViewModel(spvm))
Third page VM can access main page VM via property on second page vm: spvm.MainVm
In MainWindow you're trying to subscribe to a Window method, instead of your raiseEvent. And certainly you don't need to instantiate another MainWindow...
Your MainWindow code should be something like this:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
public void raiseEventFromSecondPage_EventHandler()
{
MessageBox.Show("MAINWINDOW Event Fired");
}
private void Button_Click(object sender, RoutedEventArgs e)
{
SecondPage sp = new SecondPage();
sp.raiseEventFromSecondPage += raiseEventFromSecondPage_EventHandler();
sp.Show();
}
}
You then need that SecondPage exposes the raiseEvent. This will be a different event from the one in its ViewModel, but you'll chain both.
public partial class SecondPage : Window
{
SecondPageViewModel spvm = new SecondPageViewModel();
public event raiseEventEventHandler raiseEventFromSecondPage;
public SecondPage()
{
this.DataContext = spvm;
spvm.raiseEvent += raiseEvent_EventHandler;
InitializeComponent();
}
public void raiseEvent_EventHandler()
{
if (raiseEventFromSecondPage != null)
raiseEventFromSecondPage();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
spvm.raiseEventActivate();
}
}
I have a Main Window which includes some User Controls that are initialized in the WPF XAML
MainWindow.xaml.
<Grid>
<local:RegularUnit x:Name="ucRegularUnit" Grid.Row="0" />
<local:Actions x:Name="ucActions" Grid.Row="1" />
// .....
</Grid>
I have a public function in the Main Window which I want to call after clicking a Button in my User Control. After searching for some solutions, I found a way to get the parent window instance in my User Control class, but it can't find the function when I'm using parentWindow.myFunction().
User Control RegularUnit.cs:
public partial class RegularUnit : UserControl
{
public RegularUnit()
{
InitializeComponent();
}
private void Button_SearchSerialNumber_Click(object sender, RoutedEventArgs e)
{
Window parentWindow = Window.GetWindow(this);
//parentWindow. //Can't find the function myFunction()
}
}
MainWindow.cs:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
public void myFunction()
{
// Do Some Stuff...
}
}
What am I doing wrong, and how can I fix it?
You can't call myFunction on parentWindow because it's not a member of the standard WPF Window class but of your custom MainWindow.
What you could do is to cast the result of Window.GetWindow(this) to MainWindow, like
MainWindow parentWindow = (MainWindow) Window.GetWindow(this);
parentWindow.myFunction();
However this is a really bad class design because now your user control depends on being embedded in a specific window.
What you should rather do is to add an event to the user control on which the parent control can subscribe to.
public event EventHandler SerialNumberSearch;
private void Button_SearchSerialNumber_Click(object sender, RoutedEventArgs e)
{
var handler = SerialNumberSearch;
if (handler != null) handler(this, EventArgs.Empty);
}
Of course you could use a different kind of EventHandler, depending on what you need.
System.Windows.Application.Current.Windows.OfType<YourWindow>().SingleOrDefault(x => x.IsActive).YourPublicMethod();
Although the above code is a messy way of doing it, but it gets the job done nevertheless.
Solution based on event subscription as suggested by Dirk. I have based event on a simple delegate but you can follow similar pattern and base it on a delegate that suits your scenario.
// In UserControl
namespace TextEditor
{
public partial class TextEditorToolBar : UserControl
{
// you can use Action type delegate also
public delegate void getDocumentKeywords();
public event getDocumentKeywords getDocumentRakeKeywordsEvent;
public TextEditorToolBar()
{
InitializeComponent();
}
// This is event handloer for the button on your user control
private void ExtractRakeKeywords(object sender, RoutedEventArgs e)
{
var handler = getDocumentRakeKeywordsEvent;
if (getDocumentRakeKeywordsEvent != null)
getDocumentRakeKeywordsEvent();
}
}
}
// In MainWindow
namespace TextEditor
{
public partial class MainWindow : Window
{
private DocumentKeywordsExtractor KeyWordsExtractor;
public MainWindow()
{
InitializeComponent();
KeyWordsExtractor = new DocumentKeywordsExtractor(richTextBox);
// toolbar is the name given to UserControl in MainWindow.xaml
toolbar.getDocumentRakeKeywordsEvent += ExtractRakeKeywords;
}
private void ExtractRakeKeywords()
{
KeyWordsExtractor.GetRakeKeywords();
}
}
I have a button in a window that basically does a rerun through some code (retry button)
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
}
private void btnRetry_Click(object sender, RoutedEventArgs e)
{
//TODO retry function
//MainWindow.Connect();
}
private void btnCancel_Click(object sender, RoutedEventArgs e)
{
this.Close();
}
}
I basically want to use the connect method in my main window class. However I can't do that unless it's a public static. However, if I do change Connect() to a public static, all the controls in it require to be static. I'm trying to minimize the amount of static controls I have; can anybody please help with a retry method?
Another solution is to make Window1.btnRetry visible to the parent form
public MainWindow : Window
{
private void ShowWindow1()
{
var window1 = new Window1();
window1.btnRetry.Click += OnRetryClicked;
window1.ShowDialog();
}
private void OnRetryClicked(object sender, EventArgs e)
{
// will be called when window1.btnRetry is clicked.
// retry the connection.
Connect();
}
}
First, you do need to make the method public (or internal) so that Window1 can use the method. However, do not make it static.
Instead, accept an instance of MainWindow in the Window1 constructor, and store it so that you can invoke the Connect() method on it later.
For example:
public partial class Window1 : Window
{
private MainWindow mainWindow;
public Window1(MainWindow mainWindow)
{
if (mainWindow == null) {
throw new ArgumentNullException("mainWindow");
}
this.mainWindow = mainWindow;
InitializeComponent();
}
private void btnRetry_Click(object sender, RoutedEventArgs e)
{
mainWindow.Connect();
}
// ...
}
Then, if constructing the instance from inside of MainWindow change your constructor invocation from new Window1() to new Window1(this).