I created a page and added a button to this page.
And I put this page in a frame in the main window.
MainUi.Content = new Page1();
I want to start a thread in mainwindow when I click the button.
In MainWindow
namespace WpfApp3
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
public void SendMessage()
{
MessageBox.Show("This is a test massage.");
//And more
}
}
In Page
namespace WpfApp3.Pages
{
public partial class Page1: Page
{
public Page1()
{
InitializeComponent();
}
private void SendMessage_Click(object sender, RoutedEventArgs e)
{
SendMessage();
//I want run this thread from here
}
}
}
Thanks.
You could inject the Page with a reference to the window as suggested by #Nawed Nabi Zada, or you could get a reference to the parent window of the page using the static Window.GetWindow method:
private void SendMessage_Click(object sender, RoutedEventArgs e)
{
MainWindow win = Window.GetWindow(this) as MainWindow;
win.SendMessage();
}
Related
In this example, MainWindow has a button that opens Window2.
Window2 has a button that writes "Hello, World!" to MainWindow textblock.
Project source: https://www.dropbox.com/s/jegeguhycs1mewu/PassData.zip?dl=0
What is the proper way to pass data from Window2 to MainWindow?
private MainWindow mainwindow;
public MainWindow mainwindow { get; private set; }
public Window MainWindow { get; set; }
private object mainwindow { get; private set; };
private MainWindow mainwindow = ((MainWindow)System.Windows.Application.Current.MainWindow);
this.mainwindow = mainwindow;
MainWindow
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
// Open Window 2
private void buttonWindow2_Click(object sender, RoutedEventArgs e)
{
Window2 window2 = new Window2(this);
window2.Left = Math.Max(this.Left - window2.Width, 0);
window2.Top = Math.Max(this.Top - 0, 0);
window2.ShowDialog();
}
}
Window 2
public partial class Window2 : Window
{
private MainWindow mainwindow;
public Window2(MainWindow mainwindow)
{
InitializeComponent();
this.mainwindow = mainwindow;
}
// Write Message to MainWindow
private void buttonMessage_Click(object sender, RoutedEventArgs e)
{
mainwindow.textBlockMessage.Text = "Hello, world!";
}
}
The 'proper' way usually depends on what your needs and circumstances are. But in general, using a delegate to pass data between windows is a common and standard practice.
Lets say the data you want to pass is a string. In your Main window, you want to create a delegate that lets you pass a string. Then you create an instance of that delegate type and subscribe a method that matches. Then when you open your secondary window, you pass that delegate to your secondary window.
public delegate void DataTransfer(string data);
public partial class MainWindow : Window
{
public DataTransfer transferDelegate;
public MainWindow()
{
InitializeComponent();
transferDelegate += new DataTransfer(DataMethod);
}
public void DataMethod(string data)
{
// Do what you want with your data.
}
private void button1_Click(object sender, EventArgs e)
{
Window2 win = new Window2(transferDelegate);
win.Show();
}
}
Now, when you invoke that delegate in your secondary window, the DataMethod() of your Form1 gets called, and so you can pass information between windows.
Your secondary window implementation should look like this:
public partial class Window2 : Window
{
DataTransfer transferDel;
public Window2(DataTransfer del)
{
InitializeComponent();
transferDel = del;
}
private void button1_Click(object sender, EventArgs e)
{
string data = "Hello, World!"; // Your string data to pass.
transferDel.Invoke(data);
}
}
As you can see, when you invoke the delegate that was passed, it calls the corresponding method in your main program.
One stand out advantage of this method is that you don't need to pass an instance of MainWindow to your Window2, you simply use delegates and subscribed methods to pass data between the two instances of windows.
The answer you're looking for is very implementation-based and depends heavily on what you want Window2 as a class to do.
private MainWindow mainwindow;
This is acceptable.
public MainWindow mainwindow { get; private set; }
This would work but doesn't respect naming conventions because it's a property. Usually you'd use this for encapsulation of a field or for easy access to a computed value.
public Window MainWindow { get; set; }
This is not acceptable in your context because Window does not contain a textBlockMessage.
private object mainwindow { get; private set; };
This also wouldn't work for the same reason as above.
private MainWindow mainwindow = ((MainWindow)System.Windows.Application.Current.MainWindow);
This would work and would even let you not keep a field for the reference to the MainWindow instance in your Window2 instances. Still needs to get that MainWindow everytime you click the button however.
Another interesting way to do what you're doing however is to simply pass the handler to the child windows at instanciation:
MainWindow
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
// Open Window 2
private void buttonWindow2_Click(object sender, RoutedEventArgs e)
{
Window2 window2 = new Window2(); // No need to give a reference to the child window anymore
window2.setClickHandler((obj, ev) => {
textBlockMessage.Text = "Hello, world!"; // Direct access to the textblock.
});
window2.Left = Math.Max(this.Left - window2.Width, 0);
window2.Top = Math.Max(this.Top - 0, 0);
window2.ShowDialog();
}
}
Window2
public partial class Window2 : Window
{
public Window2()
{
InitializeComponent();
}
public void setClickHandler(RoutedEventHandler handler)
{
// The handler is given to the click event.
buttonMessage.Click -= handler;
buttonMessage.Click += handler;
}
}
And with that your Window2 class has no need to know MainWindow.
You could declare a delegate in Window 2 and pass a function that can be executed when the button is pressed in window 2.
public delegate void SendMessage(string Message);
public SendMessage mainWindowDel = null;
Make your constructor that accepts the delegate
public Window2(SendMessage del)
{
mainWindowDel = del;
}
create window 2 by passing a function as the parameter
public void showMessage(string Message)
{
if(!string.IsNullOrWhiteSpace(Message))
textBlockMessage.Text = Message;
}
private void buttonWindow2_Click(object sender, RoutedEventArgs e)
{
// Open Window 2
//Window2 window2 = new Window2(this);
Window2 window2 = new Window2(showMessage);
window2.Left = Math.Max(this.Left - window2.Width, 0);
window2.Top = Math.Max(this.Top - 0, 0);
window2.ShowDialog();
}
call the delegate when they press the button
// Write Message to MainWindow
private void buttonMessage_Click(object sender, RoutedEventArgs e)
{
mainWindowDel("Hello, world!");
}
You could probably set the datacontext of the MainWindow to an object that you could also pass to Window2 when it's created and set it's datacontext to the same object.
In that object could create a string property that could be used in both windows. And if you implement the INotifyPropertyChanged interface both windows would know when that string is updated.
Another Approach
MainWindow
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private bool DisplayText(string displayText)
{
txt_Main.Text = displayText;
return true;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
Window2 win2 = new Window2(DisplayText);
win2.ShowDialog();
}
}
Window2
public partial class Window2 : Window
{
private Func<string, bool> mainWindowMethod;
public Window2(Func<string, bool> displayMethod)
{
InitializeComponent();
this.mainWindowMethod = displayMethod;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
this.mainWindowMethod("Hello World");
}
}
I have a main window and it has a button. When I press the main window button, it will open sub-window. In sub window, I have a text box and when I enter the text and click the add button in sub-window, the text should display on the main window. How do I achieve this? Thanks in advance.
You can create parameterized constructor of MainWindow class and pass value of Textbox from subwindow to main window and in MainWindow you can set content to that label.
Here is the implementation
MainWindow.xmal.cs
public partial class MainWindow : Window
{
public MainWindow ()
{
InitializeComponent();
}
public MainWindow (string text) : this()
{
label.Content = text;
}
private void button_Click (object sender, RoutedEventArgs e)
{
Window1 win1 = new Window1();
win1.Show();
this.Close();
}
}
Here is the code for subWindow i.e. Window1.xaml.cs
public partial class Window1 : Window
{
private string text;
public Window1 ()
{
InitializeComponent();
}
private void button_Click (object sender, RoutedEventArgs e)
{
text = textBox.Text;
MainWindow mainWindow = new MainWindow(text);
mainWindow.Show();
this.Close();
}
}
You can simply modify the constructor of the second window :
public partial class Window1 : Window
{
string text;
public Window1 (string _text)
{
InitializeComponent();
this.text = _text;
}
}
I would add an event to your 'dialog' subwindow which the MainWindow can subscribe to as it instantiates it.
DialogWindow: (subwindow):
public class DialogInputEventArgs : EventArgs
{
public string Input { get; set; }
}
public partial class DialogWindow : Window
{
public event EventHandler<DialogInputEventArgs> InputChanged = delegate { };
private void SubmitInputButton_Click(object sender, RoutedEventArgs e)
{
InputChanged(this, new DialogInputEventArgs() { Input = this._inputTextBox.Text });
}
}
MainWindow:
private void ShowDialogButton_Click(object sender, RoutedEventArgs e)
{
DialogWindow dw = new DialogWindow();
dw.InputChanged += OnDialogInputChanged;
dw.Show();
}
private void OnDialogInputChanged(object sender, DialogInputEventArgs e)
{
// update the MainWindow somehow using e.Input (the text submitted in dialog)
}
If you need this mechanism for multiple windows I would go with something more generic, like a messagebus or observerpattern thing.
I'd suggest you to use CaliburnMicro framwework to achieve easier and better communication between your controls (assuming you are using MVVM pattern). You don't have to implement all features of CaliburnMicro, just EventAggregator to manage sending and handling messages between your controls.
In this example, MainWindow has a button that opens Window2.
Window2 has a button that writes "Hello, World!" to MainWindow textblock.
Project source: https://www.dropbox.com/s/jegeguhycs1mewu/PassData.zip?dl=0
What is the proper way to pass data from Window2 to MainWindow?
private MainWindow mainwindow;
public MainWindow mainwindow { get; private set; }
public Window MainWindow { get; set; }
private object mainwindow { get; private set; };
private MainWindow mainwindow = ((MainWindow)System.Windows.Application.Current.MainWindow);
this.mainwindow = mainwindow;
MainWindow
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
// Open Window 2
private void buttonWindow2_Click(object sender, RoutedEventArgs e)
{
Window2 window2 = new Window2(this);
window2.Left = Math.Max(this.Left - window2.Width, 0);
window2.Top = Math.Max(this.Top - 0, 0);
window2.ShowDialog();
}
}
Window 2
public partial class Window2 : Window
{
private MainWindow mainwindow;
public Window2(MainWindow mainwindow)
{
InitializeComponent();
this.mainwindow = mainwindow;
}
// Write Message to MainWindow
private void buttonMessage_Click(object sender, RoutedEventArgs e)
{
mainwindow.textBlockMessage.Text = "Hello, world!";
}
}
The 'proper' way usually depends on what your needs and circumstances are. But in general, using a delegate to pass data between windows is a common and standard practice.
Lets say the data you want to pass is a string. In your Main window, you want to create a delegate that lets you pass a string. Then you create an instance of that delegate type and subscribe a method that matches. Then when you open your secondary window, you pass that delegate to your secondary window.
public delegate void DataTransfer(string data);
public partial class MainWindow : Window
{
public DataTransfer transferDelegate;
public MainWindow()
{
InitializeComponent();
transferDelegate += new DataTransfer(DataMethod);
}
public void DataMethod(string data)
{
// Do what you want with your data.
}
private void button1_Click(object sender, EventArgs e)
{
Window2 win = new Window2(transferDelegate);
win.Show();
}
}
Now, when you invoke that delegate in your secondary window, the DataMethod() of your Form1 gets called, and so you can pass information between windows.
Your secondary window implementation should look like this:
public partial class Window2 : Window
{
DataTransfer transferDel;
public Window2(DataTransfer del)
{
InitializeComponent();
transferDel = del;
}
private void button1_Click(object sender, EventArgs e)
{
string data = "Hello, World!"; // Your string data to pass.
transferDel.Invoke(data);
}
}
As you can see, when you invoke the delegate that was passed, it calls the corresponding method in your main program.
One stand out advantage of this method is that you don't need to pass an instance of MainWindow to your Window2, you simply use delegates and subscribed methods to pass data between the two instances of windows.
The answer you're looking for is very implementation-based and depends heavily on what you want Window2 as a class to do.
private MainWindow mainwindow;
This is acceptable.
public MainWindow mainwindow { get; private set; }
This would work but doesn't respect naming conventions because it's a property. Usually you'd use this for encapsulation of a field or for easy access to a computed value.
public Window MainWindow { get; set; }
This is not acceptable in your context because Window does not contain a textBlockMessage.
private object mainwindow { get; private set; };
This also wouldn't work for the same reason as above.
private MainWindow mainwindow = ((MainWindow)System.Windows.Application.Current.MainWindow);
This would work and would even let you not keep a field for the reference to the MainWindow instance in your Window2 instances. Still needs to get that MainWindow everytime you click the button however.
Another interesting way to do what you're doing however is to simply pass the handler to the child windows at instanciation:
MainWindow
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
// Open Window 2
private void buttonWindow2_Click(object sender, RoutedEventArgs e)
{
Window2 window2 = new Window2(); // No need to give a reference to the child window anymore
window2.setClickHandler((obj, ev) => {
textBlockMessage.Text = "Hello, world!"; // Direct access to the textblock.
});
window2.Left = Math.Max(this.Left - window2.Width, 0);
window2.Top = Math.Max(this.Top - 0, 0);
window2.ShowDialog();
}
}
Window2
public partial class Window2 : Window
{
public Window2()
{
InitializeComponent();
}
public void setClickHandler(RoutedEventHandler handler)
{
// The handler is given to the click event.
buttonMessage.Click -= handler;
buttonMessage.Click += handler;
}
}
And with that your Window2 class has no need to know MainWindow.
You could declare a delegate in Window 2 and pass a function that can be executed when the button is pressed in window 2.
public delegate void SendMessage(string Message);
public SendMessage mainWindowDel = null;
Make your constructor that accepts the delegate
public Window2(SendMessage del)
{
mainWindowDel = del;
}
create window 2 by passing a function as the parameter
public void showMessage(string Message)
{
if(!string.IsNullOrWhiteSpace(Message))
textBlockMessage.Text = Message;
}
private void buttonWindow2_Click(object sender, RoutedEventArgs e)
{
// Open Window 2
//Window2 window2 = new Window2(this);
Window2 window2 = new Window2(showMessage);
window2.Left = Math.Max(this.Left - window2.Width, 0);
window2.Top = Math.Max(this.Top - 0, 0);
window2.ShowDialog();
}
call the delegate when they press the button
// Write Message to MainWindow
private void buttonMessage_Click(object sender, RoutedEventArgs e)
{
mainWindowDel("Hello, world!");
}
You could probably set the datacontext of the MainWindow to an object that you could also pass to Window2 when it's created and set it's datacontext to the same object.
In that object could create a string property that could be used in both windows. And if you implement the INotifyPropertyChanged interface both windows would know when that string is updated.
Another Approach
MainWindow
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private bool DisplayText(string displayText)
{
txt_Main.Text = displayText;
return true;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
Window2 win2 = new Window2(DisplayText);
win2.ShowDialog();
}
}
Window2
public partial class Window2 : Window
{
private Func<string, bool> mainWindowMethod;
public Window2(Func<string, bool> displayMethod)
{
InitializeComponent();
this.mainWindowMethod = displayMethod;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
this.mainWindowMethod("Hello World");
}
}
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 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).