object reference is null - c#

There is one MainWindow and one user-control in my WPF application. I want to call function of my MainWindow in user-control, without creating new instance of MainWindow. For this i made main-window parent of user-control. I wrote this code below for calling function of Parent.
Child User-Control
public partial class AppLogo : UserControl
{
public MainWindow myparent { get; set; }
private void activate_Click_1(object sender, RoutedEventArgs e)
{
myparent.function();
}
. . .
}
Parent Window:
public MainWindow()
{
InitializeComponent();
AppLogo childWindow = new AppLogo();
. . .
Questions:
Is It Possible to create Window a parent of user-control?
If answer of above question is Yes then why it is generating error that Object Reference is Null.
If answer is No it is not possible then how can i achieve this goal. As it is necessary to create user-control in my application as it is requirement.

If you want to have reference in UserControl to MainWindow use following code:
MainWindow mw = Application.Current.MainWindow as MainWindow;
http://msdn.microsoft.com/en-us/library/system.windows.application.mainwindow.aspx
private void activate_Click_1(object sender, RoutedEventArgs e)
{
MainWindow mw = Application.Current.MainWindow as MainWindow;
if(mw != null)
{
mw.function();
}
}
Second solution:
In your code you should set myparent property in MainWindow constructor:
public MainWindow()
{
InitializeComponent();
AppLogo childWindow = new AppLogo();
childWindow.myparent = this;
...
}
In activate_Click_1 event handler the good habit is check if myparent is not null:
private void activate_Click_1(object sender, RoutedEventArgs e)
{
if(myparent != null)
myparent.function();
else
...
}

I'm assuming that the null reference is for the myparent property on AppLogo?
After this line AppLogo childWindow = new AppLogo(); add one saying childWindow.myparent = this;

You may introduce a child parent dependecy as suggested, however since you didn't instantiate MainWindow you should expect a null reference exception when calling myparent.function();
First, you need to instantiate MainWindow, and then set the child parent relationship by calling AppLogo .set_myparent, only then your call won't fail.

You need to pass a reference to the instance of MainWindow as an argument to AppLogo's constructor, then set it to AppLogo's variable for MainWindow.
public AppLogo(MainWindow mainWindow)
{
this.myparent = mainWindow;
}

If you locate your UserControl directly inside your Window, then its Parent property will reference your window.
The exception is called when you try to access the field which contains null value. It contains null because noone placed there anything else. You might want to set it:
AppLogo childWindow = new AppLogo();
childWindow.myparent = <something>;
You just need to recursively search your UserControl's parents until you get an instance of a Window, which will be your goal.
public static Window GetWindow(FrameworkElement element)
{
return (element.Parent as Window) ?? GetWindow(element.Parent);
}

Related

How to propagate the StateChanged event

I have a child window that has to be on top of another one which is the main.
I don't want to put the child one as TopMost since the user might want to check for data on other windows.
In short the child has to follow that maximize/minimize events as the parent main one
Main minimize--->Child minimize
Main maximize--->Child maximize
To do that I have defined in the main:
this.StateChanged += MainWindow_StateChanged;
and in that
public static event EventHandler OnMainWindowStateChanged;
private void MainWindow_StateChanged(object sender, EventArgs e)
{
OnMainWindowStateChanged?.Invoke(sender,e);
}
The logic should be:
Main window main class ---> Main window engine class ----> child window
To put some names it:
public MainWindow()
{
this.StateChanged += MainWindow_StateChanged;
//call to the engine
m_Designer = new CWorkFlowEditor(this, App.IsDeployment, OnMainWindowStateChanged);
}
...
//In the engine:
public EventHandler OnMainWindowStateChanged;
public CWorkFlowEditor(object parent, bool IsDeployment, EventHandler _OnMainWindowStateChanged)
{
OnMainWindowStateChanged = _OnMainWindowStateChanged;
}
...
// Finally, when I want to create the final child window:
wndPluginConfigurator = new Window() {};
OnMainWindowStateChanged += MainWindow_StateChanged;
wndPluginConfigurator.ShowDialog();
}
private void MainWindow_StateChanged(object sender, EventArgs e)
{
Console.Beep();
}
So the fact is that this event is never called for the above OnMainWindowStateChanged event is always null. And that is for the OnMainWindowStateChanged is also always null.
Obviously if there is a better way to achieve the result and I'd be most grateful for the explanation
Thanks for helping
ADD: The MainWindow is not visible to the CWorkflowEditor. I have therefore tried to pass the EventHAndler with an interface but that didn't work either.
To achieve the following
Main minimize--->Child minimize
Main maximize--->Child maximize
While launching the Child window set the Owner with Main Window.
Means
Window childwindow = new Window
childwindow.Owner = MainWindow
childwindow.Show()
There seems to be some issue passing your eventhandler around, but as the eventhandler is static surely it will be easier to do this instead:
MainWindow.OnMainWindowStateChanged += MainWindow_StateChanged;

Access properties of a Windows Form which was created in another Windows Form [duplicate]

How do I get access to the parent controls of user control in C# (winform). I am using the following code but it is not applicable on all types controls such as ListBox.
Control[] Co = this.TopLevelControl.Controls.Find("label7", true);
Co[0].Text = "HelloText"
Actually, I have to add items in Listbox placed on parent 'Form' from a user control.
Description
You can get the parent control using Control.Parent.
Sample
So if you have a Control placed on a form this.Parent would be your Form.
Within your Control you can do
Form parentForm = (this.Parent as Form);
More Information
MSDN: Control.Parent Property
Update after a comment by Farid-ur-Rahman (He was asking the question)
My Control and a listbox (listBox1) both are place on a Form (Form1). I have to add item in a listBox1 when user press a button placed in my Control.
You have two possible ways to get this done.
1. Use `Control.Parent
Sample
MyUserControl
private void button1_Click(object sender, EventArgs e)
{
if (this.Parent == null || this.Parent.GetType() != typeof(MyForm))
return;
ListBox listBox = (this.Parent as MyForm).Controls["listBox1"] as ListBox;
listBox.Items.Add("Test");
}
or
2.
put a property public MyForm ParentForm { get; set; } to your UserControl
set the property in your Form
assuming your ListBox is named listBox1 otherwise change the name
Sample
MyForm
public partial class MyForm : Form
{
public MyForm()
{
InitializeComponent();
this.myUserControl1.ParentForm = this;
}
}
MyUserControl
public partial class MyUserControl : UserControl
{
public MyForm ParentForm { get; set; }
public MyUserControl()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
if (ParentForm == null)
return;
ListBox listBox = (ParentForm.Controls["listBox1"] as ListBox);
listBox.Items.Add("Test");
}
}
You can use Control.Parent to get the parent of the control or Control.FindForm to get the first parent Form the control is on. There is a difference between the two in terms of finding forms, so one may be more suitable to use than the other.:
The control's Parent property value might not be the same as the Form
returned by FindForm method. For example, if a RadioButton control is
contained within a GroupBox control, and the GroupBox is on a Form,
the RadioButton control's Parent is the GroupBox and the GroupBox
control's Parent is the Form.
Control has a property called Parent, which will give the parent control. http://msdn.microsoft.com/en-us/library/system.windows.forms.control.parent.aspx
eg Control p = this.Parent;
You can get the Parent of a control via
myControl.Parent
See MSDN:
Control.Parent
A generic way to get a parent of a control that I have used is:
public static T GetParentOfType<T>(this Control control)
{
const int loopLimit = 100; // could have outside method
var current = control;
var i = 0;
do
{
current = current.Parent;
if (current == null) throw new Exception("Could not find parent of specified type");
if (i++ > loopLimit) throw new Exception("Exceeded loop limit");
} while (current.GetType() != typeof(T));
return (T)Convert.ChangeType(current, typeof(T));
}
It needs a bit of work (e.g. returning null if not found or error) ... but hopefully could help someone.
Usage:
var parent = currentControl.GetParentOfType<TypeWanted>();
Enjoy!
According to Ruskins answer and the comments here I came up with the following (recursive) solution:
public static T GetParentOfType<T>(this Control control) where T : class
{
if (control?.Parent == null)
return null;
if (control.Parent is T parent)
return parent;
return GetParentOfType<T>(control.Parent);
}
Not Ideal, but try this...
Change the usercontrol to Component class (In the code editor), build the solution and remove all the code with errors (Related to usercontrols but not available in components so the debugger complains about it)
Change the usercontrol back to usercontrol class...
Now it recognises the name and parent property but shows the component as non-visual as it is no longer designable.
((frmMain)this.Owner).MyListControl.Items.Add("abc");
Make sure to provide access level you want at Modifiers properties other than Private for MyListControl at frmMain
If you want to get any parent by any child control you can use this code,
and when you find the UserControl/Form/Panel or others you can call funnctions or set/get values:
Control myControl= this;
while (myControl.Parent != null)
{
if (myControl.Parent!=null)
{
myControl = myControl.Parent;
if (myControl.Name== "MyCustomUserControl")
{
((MyCustomUserControl)myControl).lblTitle.Text = "FOUND IT";
}
}
}

Sending object to method in another class on event

In my second window, on double click I want to call a method in my MainWindow and send it an object.
Everything worked just fine when the second window was Owned by the MainWindow, but that caused MainWindow to always be drawn behind the second which is not what I wanted.
So my question is, how on earth do I call my public LoadSong(Song tempSong) method in my MainWindow on button click in my second window (assuming that I cannot directly call the method)?
There are many ways to skin this cat. Below two examples.
First Approach
Simple approach without any external libraries would be to create a custom even on the child window and subscribe to it from parent. Also you can propagate an object this way.
The object to propagate:
public class MyCommunicationObject
{
public string Message { get; set; }
}
And then the child window:
public partial class ChildWindow : Window
{
public event Action<MyCommunicationObject> MyChildWindowEvent;
public ChildWindow()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
var myObject = new MyCommunicationObject();
myObject.Message = "Hello from Child Window";
this.MyChildWindowEvent(myObject);
}
}
Clicking the button will propagate the MyChildWindowEvent event.
In the main window you have to subscribe for the event when you create the child dialog (in my example I'm doing that on button click because that's when the window is created).
The main window code:
private void Button_Click(object sender, RoutedEventArgs e)
{
var childWindow = new ChildWindow();
childWindow.MyChildWindowEvent += ChildWindow_MyChildWindowEvent;
childWindow.ShowDialog();
}
Second Approach
Or as suggested above use an EventAggregator. You can use for instance Prism. You will have to install it using NuGet manager. Once it's installed it Allows you to use EventAggregator object. The object can propagate events that inherit from PubSubEvent, e.g.:
public class MyEvent : PubSubEvent<MyCommunicationObject>
{
}
The main window and child window have to share an instance of the EventAggregator. Then you have to subscribe for an event that's propagated by your child window. Assuming the object has been created in the main window below is an example how to subscribe and handle the event on the main window (again on button click):
private void Button_Click_2(object sender, RoutedEventArgs e)
{
var childWindow = new AnotherChildWindow(eventAggregator);
eventAggregator.GetEvent<MyEvent>().Subscribe(obj =>
{
this.myTextBox2.Text = obj.Message;
});
childWindow.ShowDialog();
}
And the child window has to publish the event (together with the object that's used for communication):
private void Button_Click(object sender, RoutedEventArgs e)
{
var myObject = new MyCommunicationObject();
myObject.Message = "Hello from another child window";
this.eventAggregator.GetEvent<MyEvent>().Publish(myObject);
}
Here on the child window the instance of the EventAggregator comes from the main window.
You can use EventAggregator or other event-based patterns.
First create new event with property of your object type to send it between components.
Next subscribe MainWindow to your event and call LoadSong in event handler with parameter received from handler parameter.
Finally raise (or publish in other terms) your event from your second window on double click event handler.
As you can see both of implementations is a part of MVVM libraries and this pattern can be useful for your app.

Passing value between forms [duplicate]

How do I pass a value from a child back to the parent form? I have a string that I would like to pass back to the parent.
I launched the child using:
FormOptions formOptions = new FormOptions();
formOptions.ShowDialog();
Create a property (or method) on FormOptions, say GetMyResult:
using (FormOptions formOptions = new FormOptions())
{
formOptions.ShowDialog();
string result = formOptions.GetMyResult;
// do what ever with result...
}
If you're just using formOptions to pick a single value and then close, Mitch's suggestion is a good way to go. My example here would be used if you needed the child to communicate back to the parent while remaining open.
In your parent form, add a public method that the child form will call, such as
public void NotifyMe(string s)
{
// Do whatever you need to do with the string
}
Next, when you need to launch the child window from the parent, use this code:
using (FormOptions formOptions = new FormOptions())
{
// passing this in ShowDialog will set the .Owner
// property of the child form
formOptions.ShowDialog(this);
}
In the child form, use this code to pass a value back to the parent:
ParentForm parent = (ParentForm)this.Owner;
parent.NotifyMe("whatever");
The code in this example would be better used for something like a toolbox window which is intended to float above the main form. In this case, you would open the child form (with .TopMost = true) using .Show() instead of .ShowDialog().
A design like this means that the child form is tightly coupled to the parent form (since the child has to cast its owner as a ParentForm in order to call its NotifyMe method). However, this is not automatically a bad thing.
You can also create a public property.
// Using and namespace...
public partial class FormOptions : Form
{
private string _MyString; // Use this
public string MyString { // in
get { return _MyString; } // .NET
} // 2.0
public string MyString { get; } // In .NET 3.0 or newer
// The rest of the form code
}
Then you can get it with:
FormOptions formOptions = new FormOptions();
formOptions.ShowDialog();
string myString = formOptions.MyString;
You can also create an overload of ShowDialog in your child class that gets an out parameter that returns you the result.
public partial class FormOptions : Form
{
public DialogResult ShowDialog(out string result)
{
DialogResult dialogResult = base.ShowDialog();
result = m_Result;
return dialogResult;
}
}
Use public property of child form
frmOptions {
public string Result; }
frmMain {
frmOptions.ShowDialog(); string r = frmOptions.Result; }
Use events
frmMain {
frmOptions.OnResult += new ResultEventHandler(frmMain.frmOptions_Resukt);
frmOptions.ShowDialog(); }
Use public property of main form
frmOptions {
public frmMain MainForm; MainForm.Result = "result"; }
frmMain {
public string Result;
frmOptions.MainForm = this;
frmOptions.ShowDialog();
string r = this.Result; }
Use object Control.Tag; This is common for all controls public property which can contains a System.Object. You can hold there string or MyClass or MainForm - anything!
frmOptions {
this.Tag = "result": }
frmMain {
frmOptions.ShowDialog();
string r = frmOptions.Tag as string; }
Well I have just come across the same problem here - maybe a bit different. However, I think this is how I solved it:
in my parent form I declared the child form without instance e.g. RefDateSelect myDateFrm; So this is available to my other methods within this class/ form
next, a method displays the child by new instance:
myDateFrm = new RefDateSelect();
myDateFrm.MdiParent = this;
myDateFrm.Show();
myDateFrm.Focus();
my third method (which wants the results from child) can come at any time & simply get results:
PDateEnd = myDateFrm.JustGetDateEnd();
pDateStart = myDateFrm.JustGetDateStart();`
Note: the child methods JustGetDateStart() are public within CHILD as:
public DateTime JustGetDateStart()
{
return DateTime.Parse(this.dtpStart.EditValue.ToString());
}
I hope this helps.
For Picrofo EDY
It depends, if you use the ShowDialog() as a way of showing your form and to close it you use the close button instead of this.Close(). The form will not be disposed or destroyed, it will only be hidden and changes can be made after is gone. In order to properly close it you will need the Dispose() or Close() method. In the other hand, if you use the Show() method and you close it, the form will be disposed and can not be modified after.
If you are displaying child form as a modal dialog box, you can set DialogResult property of child form with a value from the DialogResult enumeration which in turn hides the modal dialog box, and returns control to the calling form. At this time parent can access child form's data to get the info that it need.
For more info check this link:
http://msdn.microsoft.com/en-us/library/system.windows.forms.form.dialogresult(v=vs.110).aspx
i had same problem i solved it like that , here are newbies step by step instruction
first create object of child form it top of your form class , then use that object for every operation of child form like showing child form and reading value from it.
example
namespace ParentChild
{
// Parent Form Class
public partial class ParentForm : Form
{
// Forms Objects
ChildForm child_obj = new ChildForm();
// Show Child Forrm
private void ShowChildForm_Click(object sender, EventArgs e)
{
child_obj.ShowDialog();
}
// Read Data from Child Form
private void ReadChildFormData_Click(object sender, EventArgs e)
{
int ChildData = child_obj.child_value; // it will have 12345
}
} // parent form class end point
// Child Form Class
public partial class ChildForm : Form
{
public int child_value = 0; // variable where we will store value to be read by parent form
// save something into child_value variable and close child form
private void SaveData_Click(object sender, EventArgs e)
{
child_value = 12345; // save 12345 value to variable
this.Close(); // close child form
}
} // child form class end point
} // name space end point
Many ways to skin the cat here and #Mitch's suggestion is a good way. If you want the client form to have more 'control', you may want to pass the instance of the parent to the child when created and then you can call any public parent method on the child.
I think the easiest way is to use the Tag property
in your FormOptions class set the Tag = value you need to pass
and after the ShowDialog method read it as
myvalue x=(myvalue)formoptions.Tag;
When you use the ShowDialog() or Show() method, and then close the form, the form object does not get completely destroyed (closing != destruction). It will remain alive, only it's in a "closed" state, and you can still do things to it.
The fastest and more flexible way to do that is passing the parent to the children from the constructor as below:
Declare a property in the parent form:
public string MyProperty {get; set;}
Declare a property from the parent in child form:
private ParentForm ParentProperty {get; set;}
Write the child's constructor like this:
public ChildForm(ParentForm parent){
ParentProperty= parent;
}
Change the value of the parent property everywhere in the child form:
ParentProperty.MyProperty = "New value";
It's done. the property MyProperty in the parent form is changed. With this solution, you can change multiple properties from the child form. So delicious, no?!

Main window Textbox acces from class in other file

so I have a main window it has lots of other window instance in it
MainWindow
{
Window1 win1= new Window1();
Window2 win2 = new Window2();
// ....... and so on
private keydownevent( ,key e)
{
if(e.keu==key.return)
{
//some logic here
if(some condition)
{
win1.show();
}
else if(some condition)
{
win2.show()
}
// ....
}
}
}
// and in window1 lets say
Window1
{
foo_class fcl = new foo_class();
click_button()
{
// do some logic
fc1.function in class;
}
}
now textbox content are a barcode and i want to clear textbox in MainWindow when window1 is showed and click_button in window 1 is done
//////////
i have tried
MainWindow win= (MainWindow)Application.Current.MainWindow;
win.txtBlock1.Text = "";
putting in foo_class as well as in button_click but it throws error window1 can not be cast to mainwindow
i also tried
creating a constructor that takes argument as textbox in keydown function as window(texbox) but that willl create a new instance every tim but i want only want on instance created while instantiating mainwindow and keep using that window1 instance
PLease suggest some method that work in clearing textbox in main window ? and where should i put that method
When creating the Windows, you could set the Owner to this. i.e.:
public class MainWindow
{
Window1 win1 = new Window1();
Window2 win2 = new Window2();
...
//in code, before call Show() on win1 or win2
//set win1/win2.Owner = this;
}
Then when you ned to clear the parent you could get a reference to the parent by simply calling ((MainWindow)this.Owner).txtBlock1.Text = "";.
This is all on the assumption that Window1 and Window2 are actually subclasses of Window, or you actually meant to declare win1 and win2 as Window.
EDIT:
As mentioned in the comments, an alternative would be to supply a reference to an instance of MainWindow to the constructors of win1 and win2 if they are subclasses of window via a new constructor.
I'd also recommend that you should create a new method on MainWindow called ClearText so you don't have to expose the text box name.

Categories

Resources