I've got an experience in designing websites with ASP.Net MVC.
I want now to be able to deal with WPF. So, I'm developping a tiny App to learn a few topics like threading, filestreams, and so on.
But, my problem seems really basic :
I've got on my main window a button that fires an action which calls another window. The new windows'aim is to get 2 strings and 2 doubles, to send them back to the main window.
My problem is, that the main window is not launched that way :
MainWindow m = new mainwindow;
And I'd like to do something like :
m.someVariable = somethingFromMySecondWindow.
So, I've tryed to set the main window static, but I got lots of errors, so I removed the "static".
I can't access variables from my second window, or any public method.
I don't know if it is needed, but here is the c# code i've already written.
mainWindow :
namespace FlightPlanningDraft1
{
/// <summary>
/// Logique d'interaction pour MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private string _ACModel;
private string _ACIdentification;
private double _ACFuelConsumption;
private double _ACTotalFuel;
public MainWindow()
{
InitializeComponent();
}
private void MenuItem_Click(object sender, RoutedEventArgs e)
{
ChargementAvion c = new ChargementAvion();
c.Show();
}
public void Validation_Avion(string aCModel,string aCIdentification, double aCFuelConsumption, double aCTotalFuel)
{
_ACModel = aCModel;
_ACIdentification = aCIdentification;
_ACFuelConsumption = aCFuelConsumption;
_ACTotalFuel = aCTotalFuel;
}
}
}
My second window
namespace FlightPlanningDraft1
{
/// <summary>
/// Logique d'interaction pour ChargementAvion.xaml
/// </summary>
public partial class ChargementAvion : Window
{
public ChargementAvion()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
//I don't know what to do here.
}
}
}
You can add an event to the second windows. Subscribe on it inside MenuItem_Click (MainWindow), and fire that event from Second window (Button_Click).
You can pass any value to you event.
public partial class ChargementAvion :Window
{
public event Action<string> OnDone;
private void Button_Click(object sender, RoutedEventArgs e)
{
if(OnDone != null)
{
OnDone("any string you want to pass");
}
}
}
and in MainWindow:
private void MenuItem_Click(object sender, RoutedEventArgs e)
{
ChargementAvion c = new ChargementAvion();
c.OnDone += ResultsHandler;
c.Show();
}
public void ResultsHandler(string result)
{
//do what you want ;)
}
I'd suggest you to look through this article. Just to be more familiar with events and delegates in C#.
Related
So this sounds strange but I always get a stackoverflow exception when I execute 'this.Content' 3 times.
So I have a main window which stores all userControls so I dont have to create them always:
public partial class MainWindow : Window
{
CreateSessionWindow csw;
RateSessionWindow rsw;
CloseSessionWindow closesw;
MainMenuWindow mmw;
public MainWindow()
{
InitializeComponent();
csw = new CreateSessionWindow();
rsw = new RateSessionWindow();
closesw = new CloseSessionWindow();
mmw = new MainMenuWindow();
AllSessionWindows.csw = csw;
AllSessionWindows.rsw = rsw;
AllSessionWindows.closesw = closesw;
AllSessionWindows.mmw = mmw;
}
private void bttnStartProgram_Click(object sender, RoutedEventArgs e)
{
this.Content = AllSessionWindows.mmw;
}
}
public static class AllSessionWindows
{
public static RateSessionWindow rsw;
public static CloseSessionWindow closesw;
public static CreateSessionWindow csw;
public static MainMenuWindow mmw;
}
In my MainMenuWindow class I have a button and when I click on the button it changes the content:
public partial class MainMenuWindow : UserControl
{
public MainMenuWindow()
{
InitializeComponent();
}
private void bttnCreateSession_Click(object sender, RoutedEventArgs e)
{
this.Content = AllSessionWindows.csw; //here
}
}
And here is where I get usually the stackoverflowexception:
public partial class CreateSessionWindow : UserControl
{
public CreateSessionWindow()
{
InitializeComponent();
}
private void bttnGoBack_Click(object sender, RoutedEventArgs e)
{
this.Content = AllSessionWindows.mmw; //here I always get the exception
}
}
So no matter in which order I call this.Content (for eg. first mmw and than csw or csw and than mmw) I always get a stackoverflow Exception when I call it 3 times which you can see above. What could be the problem be?
The problem in your code is this.Content=... in UserControls (in this case this.Content is UserControl content not Window content). If you want to change content in the main window you should add property with MainWindow to class AllSessionWindows:
public static class AllSessionWindows
{
public static MainWindow MainWindow;
public static RateSessionWindow rsw;
public static CloseSessionWindow closesw;
public static CreateSessionWindow csw;
public static MainMenuWindow mmw;
}
In the MainWidnow constructor you must assign this property:
public MainWindow()
{
InitializeComponent();
...
AllSessionWindows.MainWindow = this;
}
And in UserControl you should use following code:
private void bttnCreateSession_Click(object sender, RoutedEventArgs e)
{
AllSessionWindows.MainWindow.Content = AllSessionWindows.csw;
}
Presented solution to this kind of problem by you is not the best solution. For this kind of problem, you can use Caliburn.Micro framework.
In the following link you can find a good tutorial:
http://www.mindscapehq.com/blog/index.php/2012/1/12/caliburn-micro-part-1-getting-started/
Your problem is described in part 5 and 6 of this tutorial.
In WPF I got one window in which there is a button and big text block, and the class in which I got a public method which sets the text to the text block in the window. The problem is, that this doesn't work and I quite don't understand why. The code looks like this:
In MainWindow.xaml.cs
private void GoButton_Click(object sender, RoutedEventArgs e)
{
Watcher watcher = new Watcher();
watcher.StoryMode();
}
And here is the public void StoryMode from class Watcher:
string text1 = #"C:/Users/Desktop/Folder/1.txt";
string mainText;
MainWindow mw = new MainWindow();
public void StoryMode()
{
mainText = text1;
mw.textBlock_story.Text = File.ReadAllText(mainText);
}
Every time when I click on the button, nothing happen and when I try to debug, I can see that it calls the function from the Watch class, but doesn't do anything at all. When I tried same code, but outside the Watch class, inside the MainWindow like this :
private void GoButton_Click(object sender, RoutedEventArgs e)
{
string text1 = #"C:/Users/Desktop/Folder/1.txt";
string mainText;
mainText = text1;
textBlock_story.Text = File.ReadAllText(mainText);
}
All works fine, but I that's not exactly something what I want in this case.
Could somebody explain me why does this happen and how to get a better solution for this problem?
Your window class needs to create an instance of the watcher class. It should then extract the text data from the watcher class.
class Watcher
{
public string mainText;
void StoryMode()
{
mainText = "Example Text";
}
}
public partial class MainWindow : Window
{
string texblock_story_text;
public MainWindow()
{
InitializeComponent();
}
void Get_Text()
{
Watcher MyWatcher = new Watcher();
texblock_story_text = MyWatcher.mainText;
}
}
I'm having trouble assigning the value of a variable from one class to another class. I have tried to do it in several ways but none works, the variable still has no value inside my method.
First Class:
namespace Simulador
{
public partial class Cidade : Window
{
private int QNTTodinho;
private void todinhobotao_Click(object sender, RoutedEventArgs e)
{
TodinhoBotaoo();
}
public void TodinhoBotaoo()
{
QNTTodinho += 1;
MainWindow Valor = new MainWindow(QNTTodinho);
}
}
}
Second Class:
namespace Simulador
{
public partial class MainWindow : Window
{
private int QNTTodinho;
public MainWindow(int qNTTodinho)
{
QNTTodinho = Convert.ToInt32(qNTTodinho);
}
private void Salgadinho_Click(object sender, RoutedEventArgs e)
{
Dinheiro22.Content = QNTTodinho.ToString();
}
}
}
I am guessing that the startup form for your application is
MainWindow. Which means you are creating an instance of MainWindow and running it as the main application window.
If this is the case, then creating another instance of MainWindow like what you are doing and passing the integer to it in the constructor wouldn't affect the actual main window. It is just setting the value in a copy of the MainWindow and directly scrapping that copy afterwards.
One way to fix that, although not the best practice, is to change the member you want to modify to be a static member, like that:
public partial class MainWindow : Window
{
public static int QntTodinho { get; set; }
public MainWindow()
{
}
private void Salgadinho_Click(object sender, RoutedEventArgs e)
{
Dinheiro22.Content = this.QntTodinho.ToString();
}
}
public partial class Cidade : Window
{
private int qntTodinho = 0;
private void todinhobotao_Click(object sender, RoutedEventArgs e)
{
TodinhoBotaoo();
}
public void TodinhoBotaoo()
{
this.qntTodinho += 1;
MainWindow.QntTodinho = this.qntTodinho;
}
}
Notice as well that I've done the following changes:
Used pascalCasing for private member
Used CamelCasing for public member
Get rid of Convert.ToInt32 as it is not needed
Things to consider with this solution are mainly thread safety and the lack of ways to notify MainWindow when the value changes.
I have a main window and would like to pass a value to a Pop Up window (which will use that value to set up some other values dependant on that value). The pop up window has multiple textboxes for user inputs. When a button called SaveButton is pressed I would like the user inputs (all of them) to be sent back to the main window. How can I accomplish this?
I am very new to C# and I am aware that there are similar questions. However, I am having difficulties with adapting the answers to my specific situation. Thank you for keeping that in mind when answering!
Thank you so much!
Edit: About the code
The code that I have:
For initiating the PopUp window (which is a Window WPF called PopUp)
PopUp popUp = new PopUp();
popUp.ShowDialog
The PopUp.xaml.cs is empty except for the standard stuff and an eventhandler for the click event of the button.
Look at this :
Your main window :
namespace WpfApplication1
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
//Defining public or internal parameters
public int MainWindowProp1 { get; set; }
public string MainWindowProp2 { get; set; }
public MainWindow()
{
InitializeComponent();
this.Loaded += MainWindow_Loaded;
}
private void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
//When you call your child window, pass this (mainwindow) as parameter.
childWindow cw = new WpfApplication1.childWindow(this);
cw.Param2 = "test";
cw.Param1 = 12;
cw.Closed += Cw_Closed;
cw.ShowDialog();
}
private void Cw_Closed(object sender, EventArgs e)
{
//On closed event, you can cast the sender as your child window.
var child = (sender as childWindow);
var param1 = child.Param1;
var param3 = child.Param2;
}
public void TestMethod()
{
//do anything you want
}
}
}
And your Child Window :
namespace WpfApplication1
{
/// <summary>
/// Interaction logic for childWindow.xaml
/// </summary>
public partial class childWindow : Window
{
//declare Mainwindow as a parameter in your child window
public MainWindow mainWindow;
public int Param1 { get; set; }
public string Param2 { get; set; }
//Add a parameter in your child window contructor.
public childWindow(MainWindow _mainWindow)
{
InitializeComponent();
//Assign your global parameter mainWindow to the _mainWindow parameter.
this.mainWindow = _mainWindow;
this.Loaded += ChildWindow_Loaded;
}
private void ChildWindow_Loaded(object sender, RoutedEventArgs e)
{
//You can get or set your main window properties.
this.mainWindow.MainWindowProp1 = 5;
this.mainWindow.MainWindowProp2 = "test";
//You can call methods ant events etc.. of your main window too (depending on acces modifiers).
this.mainWindow.TestMethod();
}
}
}
In general terms the most simplified solution is this one:
From MainWindow to Child window (Window1);
((Window1)Application.Current.Windows[1]).testlabel.Content = "In Sync";
From child window to MainWindow;
((MainWindow)Application.Current.MainWindow).label2.Content = "whatever";
Scenario:
Three forms: MainWindow, Positions, Calibration self-named (MainWindow : Window etc.)
MainWindow creates an instance of three objects:
Vars: Model Vars = new Model();
Positions: Positions PositionsWindow = new Positions();
Calibration: Calibration CalibrationWindow = new Calibration();
A button in MainWindow is used to Show and Hide the child windows. Form fields in MainWindow update fields in class Vars.
MainWindow code:
public partial class MainWindow : Window
{
Model Vars = new Model();
Positions PositionsWindow = new Positions();
Calibration CalibrationWindow = new Calibration();
private void OpenButton_Click(object sender, RoutedEventArgs e)
{
PositionsWindow.Show();
}
private void TextBoxUpdate_Click(object sender, RoutedEventArgs e)
{
Vars.TestVar = TestBox.Text;
}
}
Question: How can form fields in the child windows update the parent form fields and/or fields in the class "Vars", i.e. passing data from child to parent and trigger an action in the parent form?
Attempts: A similar question suggested passing the main window this, example: Positions PositionsWindow = new Positions(); however, this only works when the object is created in a method. At this point, PositionsWindow.Show(); is no longer valid. i.e. it is only suitable for a child window created and closed in a single method.
I would not really recommend initializing the variables before the constructor. Don't get used to that.
I would change the constructor of each of the three Windows:
public partial class Model : Window{
MainWindow MW;
Model(MainWindow MW){
this.MW = MW;
// other constructor stuff
}
}
Do the same thing for Positions and Calibration.
Obviously, you cannot use this when you are INITIALIZING the Windows BEFORE the constructor is called, because there is still no this to pass.
Therefore, in your MainWindow:
public partial class MainWindow : Window
{
Model Vars; // = new Model(this); <- the constructor was not yet called, there is no this
Positions PositionsWindow; // = new Positions();
Calibration CalibrationWindow; // = new Calibration();
MainWindow(){
Vars = new Model(this);
Positions = new Positions(this);
CalibrationWindow = new Calibration(this);
}
private void OpenButton_Click(object sender, RoutedEventArgs e)
{
PositionsWindow.Show();
}
private void TextBoxUpdate_Click(object sender, RoutedEventArgs e)
{
Vars.TestVar = TestBox.Text;
}
}
Edit: (to complete the answer to the question):
Now, if you want the Windows to change stuff to each other, just create functions in MainWindow that change stuff in each of the Windows. And with MW you can call these functions from any child Window
For me the best is using Subscribe/Publisher event-based way, here is the way to do it. (i recreate the code so that you can understand)
1) add an event publisher in your child windows.
public partial class ChildWindows : Window
{
// the is the event publisher
public event Action<string> ChildUpdated;
public ChildWindows()
{
InitializeComponent();
}
private void updateParentBtn_Click(object sender, RoutedEventArgs e)
{
// pass the parameter.
ChildUpdated(updateTb.Text);
}
}
2) Subscribe the publisher in your parent windows.
public partial class MainWindow : Window
{
Model Vars;
ChildWindows childWindows;
public MainWindow()
{
InitializeComponent();
Vars = new Model();
childWindows = new ChildWindows();
//this is the event subscriber.
childWindows.ChildUpdated += ChildWindows_ChildUpdated;
}
//do whatever you want here.
void ChildWindows_ChildUpdated(string obj)
{
// Update your Vars and parent
Vars.TestVar = obj;
updateLbl.Content = Vars.TestVar;
}
private void openButton_Click(object sender, RoutedEventArgs e)
{
childWindows.Show();
}
private void textBoxUpdate_Click(object sender, RoutedEventArgs e)
{
}
}
3) In this case, when i type inside the textbox in my child windows, and press a button, it will appear on a label inside my parent windows.
P/S : i had changed the ParentUpdated to ChildUpdated. thanks to #Adrian for constructive feedback
example