Setting the properties of form values from another class - c#

I have been working on an assignment with forms for a while now and everything works, however my professor want us to devide everything in seperate classes.
So what I have now is:
MainForm.cs
MainForm.Designer.cs
MainForm.resx
program.cs
In the MainForm.cs is where i have all my code and where i call the buttons, labels, textboxes etc from.
What I want to do, is to have a strucutre with other classes such as
MainForm.cs
MainForm.Designer.cs
MainForm.resx
program.cs
class1.cs
class2.cs
I tried doing this, but from my class1 i couldn't call the Design(name) of the Form since it dont exist in the context. I have been searching a lot but haven't found anything that matched my problem or how to solve it.
How can I solve this problem?

For any property to be accessible from another class (another form for instance as Form itself is a class), the property must be public, so for example lets say you have a textbox named txtSomething and you need to access its text, you may create a public property that lets you get and set its Text property:
public string SomeProperty { get { return txtSomething.Text;} set {txtSomething.Text = value;}}
You can of course change MainForm.Designer.cs and make all controls (for example textboxes) public where they are defined, but it is not a good choice at all. because you should always give public access only where it is needed. for example if you need a controls text, let just its text property be accessible (the code above).
Even, if the second form has just to get the textbox value and does need to set it, you may give a readonly access. so the code above would be:
public string SomeProperty { get { return txtSomething.Text;} }
Then assuming that the instance of FrmMain is frmMain you can access the Text property of that textbox like:
string propertyValue = frmMain.SomeProperty;

Related

Get the owner Form of a NotifyIcon?

In C# or Vb.Net, using managed or unmanaged code, how I could retrieve the owner Form of a NotifyIcon?
I've checked the base types of NotifyIcon Class and also the ComponentConverter trying to find out a possible type-casting to obtain the Form, but I was not able to.
I also seen the NotifyIcon.ContextMenuStrip.FindForm() function, but for any reason when I assign a contextmenustrip the FindForm() function always returns a null-reference exception, and anyways even if it could work will not be a safe approach because I could have a notifyicon without a contextmenu.
My intention is to pass a NotifyIcon as an argument to some methods that will perform common tasks to save me time and reduct code.
Pseudo example:
Public Shared Sub MinimizeToSystray(ByVal ntfy As NotifyIcon)
If (ntfy Is Nothing) Then
Throw New ArgumentNullException(paramName:="ntfy")
ElseIf (ntfy.Icon Is Nothing) Then
Throw New ArgumentException(message:="The NotifyIcon doesn't have an icon.",
paramName:="ntfy")
Else
Dim f As Form = ntfy.GetOwnerForm()
f.WindowState = FormWindowState.Minimized
f.Hide()
ntfy.Visible = True
End If
End Sub
The FindForm() method can only find the form for controls. The kind that derive from Control and are embedded in a form through its Parent property. But NotifyIcon is not a control, it is Component. A Component only has a Site property, its value is only defined at design time.
There is a casual relationship between a component and the form, Winforms promises to automatically dispose any components that have a constructor overload that takes an IContainer argument. Not all them do, OpenFormDialog and BackgroundWorker for example don't, NotifyIcon does. They omit the constructor when they don't need disposal.
Which makes it technically possible to find the form back. You'd need to iterate Application.OpenForms(). And use reflection to iterate their private components collection. Do note that this can only work when the form was actually opened, its Show() method must have been called.
That's a solution that scores -100 points, it is both ugly and error prone. The simple and always-correct solution is to just add an extra argument to the method to allow passing the "owner" form. With the assumption that, since the caller needs to know the NotifyIcon instance, it also should know the form. Typically Me.
Component doesn't have a FindForm method like controls and if you need such property you should customize the component and apply a workaround. Unfortunately NotifyIcon is sealed and can not be inherited.
As mentioned by Ivan Stoev in comments, you can use Tag property to store a reference to the container form.
But If you are looking for a designer based solution that works without writing such initialization codes to set the Tag, as a good option, you can create an extender component that adds a property ParentForm to your NotifyIcon component and set the property at design-time, then you can simply use it at run-time and when setting the ParentForm property at design-time you can set Tag property in component code, and then use it at run-time.
And here is the usage:
Add a the ComponentExtender (see the code at the end of post) to your project, then build the project. Then:
Add the ComponentExtender from toolbox to your form
Set the ParentForm on componentExtender1 property of your notifyIcon1 at designer using property grid:
Use this code to find the parent form of your notify icon:
var parent = this.notifyIcon1.Tag as Form`
Code
Here is an implementation that I used and works properly:
[ProvideProperty("ParentForm", typeof(NotifyIcon))]
public class ComponentExtender
: System.ComponentModel.Component, System.ComponentModel.IExtenderProvider
{
private Hashtable components;
public ComponentExtender() : base() { components = new Hashtable(); }
public bool CanExtend(object extendee)
{
if (extendee is Component)
return true;
return false;
}
public Form GetParentForm(NotifyIcon extendee)
{
return components[extendee] as Form;
}
public void SetParentForm(NotifyIcon extendee, Form value)
{
if (value == null)
{
components.Remove(extendee);
component.Tag = null;
}
else
{
components[extendee] = value;
component.Tag = value;
}
}
}

How to access a non-static property from another class

I have a non-static property inside a non-static MainForm class:
public string SelectedProfile
{
get { return (string)cbxProfiles.SelectedItem; }
set { cbxProfiles.SelectedItem = value; }
}
I would like to get the value of this property, from another non-static class. Using MainForm.SelectedProfile gives an error saying "An object reference is required for the non-static field, method or property".
Usually I would solve this problem by making SelectedProfile static, but I can't, since cbxProfiles (a ComboBox control) can't be made static.
So how do I access the property's value without making it static?
You access non-static members the same way you always do: by using a reference to an instance of the object.
So whatever code you want to be able to use that property, you need to pass it a reference to a MainForm object.
As said in the compilation error, you need to have a reference of the existing MainForm instance to act on it.
// You surely do this somewhere in your code
MainForm mainForm = new MainForm();
// ...
// Use the reference to your mainForm to access its public properties
String selectedProfile = mainForm.SelectedProfile;
I might be late to the party but my solution might help someone someday down the road. You can directly access an open form's controls (even private ones) using Application.OpenForms[n]...
For example, let's assume you have created a MainForm and then created a comboBox such that it is inside MainForm => Tab (named tabControl) => TabPage (named tabPageMain) => Panel (named pnlMain) => ComboBox (named cmbSeconds). Then you can access this last control as follows:
ComboBox combo = Application.OpenForms[0].Controls["tabControl"].Controls["tabPageMain"].Controls["pnlMain"].Controls["cmbSeconds"] as ComboBox;
string SelectedProfile = (string)combo.SelectedItem;
// OR
bool isMaximized = Application.OpenForms[0].WindowState == FormWindowState.Maximized;
i.e. you've got to traverse the path from the top-level form down to that particular control. Document Outline view of Visual Studio (View menu => Other Windows => Document Outline) might help you in this bcoz you might be overlooking some transparent containers in between.
Use it cautiously. For example, if the handles of any of the referenced controls are not yet created, you might see runtime exceptions.

Mutator method not changing TextBox text to parameter contents

I have a series of mutator methods in another class, each of which is linked to a textBox.
(ClassA). Now, I am using an object of ClassA (myClassAObject.setFirstName(param here), to set the text, so the contents of that parameter will display in that textbox.
The content of that mutator method is as follows:
public void setFirstName (string newFirstName)
{
txtBoxFirstName.Text = newFirstName;
}
I know that the mutator works correctly, because otherwise I'd not see the first name of the patient, I'd see "null", or in the case of a println, a blank space.
The question is below this line
The mutator method, for some reason is not causing the textBox to display the text it is given in a parameter, when I access it from the other class. The textBox remains blank. How can I get it to work correctly? I have used MessageBoxes to check if there is a value for the textBox to display, and yes, the contents of the variable appear onscreen.
Here is how the parameter is passed from the second class, to the class in which the textBox resides:
myClassAObject.setFirstName(firstName);
The code above is example code, but it illustrates what I am doing.
Below is the actual code.
Firstly, from the class where the textBox resides.
Secondly, where the new parameter is being passed from.
public void setPatientFirstName(string newPatientFirstName)
{
txtBoxPatientFirstName.Text = newPatientFirstName;
}
Second part of code:
patientRecordClassOverseer.setPatientFirstName(patReaderFirstName);
I am using a "Reader" (OleDB) to read the data from the database. It is working, as I have MessageBoxes setup for debugging purposes.

inherited ListViewItem in WinForms, C#, .Net2.0

I got a problem with ListView in System.Windows.Forms, that i can't handle it on myself, begging for help or a hint where do I do wrong?
Description:
- I have a class - name it cListViewItem ('c' from custom), that inherits from standard ListViewItem, but stores my own data handling class. Now, after adding cListViewItem to a ListView class using ListView.items.Add( ) i don't seem to have any control over the item's name.
- fragments of my source (lil changed for the purpose of this post)
using System.Windows.Forms;
cListViewItem:ListViewItem
{
// gives a basic idea
public cListViewItem( myclass DataStorage )
{
// constructor only stores DataStorage to a local variable for further use;
this._storage = DataStorage;
}
protected myclass _storage;
// and there goes the fun:
// I thought that ListView class uses .Text property when drawing items, but that is not truth
// my idea was to 'cheat' a little with:
new public String Text
{
get
{
// overriding a getter should be enough i thought, but i was wrong
return( some string value from DataStorage class passed via constructor );
// setter is not rly needed here, because data comes from this._storage class;
// in later stages i've even added this line, to be informed whenever it's called ofc before return( ); otherwise VisualStudio would not compile
MessageBox.Show( "Calling item's .Text property" );
// guess what? this message box NEVER shows up;
}
}
}
I see that's important to use .Text setter, but constructor is the last moment i can do it, right after creation cListViewItem is being added to ListView Items property and displayed, so there's no place to call .Text = "" again.
My piece of code only works when I set all things in cListViewItem 's constructor like:
public cListViewItem( myclass DataStorage )
{
this._storage = DataStorage;
this.Text = DataStorage.String1;
// and if I add subitems here, I will see em when the ListView.View property be changed to View.Details
}
So am I blind or what? when I use cListViewItem.Text = "string" I will see 'string'
in the ListView but when I just override .Text getter i can't see the items :(
ListView class gives the flexibility of showing items the way I need. I wanted to create a class that will bind my custom data storage class with a ListView class. In the next stage of my application I want to bind a form for selected item in a ListView, that will allow me change item's (my custom class) values. That's why i wanted to make each ListViewItems item remembering corresponding custom data storage class.
Names shown in ListView will never be uniqe, so multiple same names all allowed, but items will differ by a id value (database-wise);
I just can't figure out why using ListViewItem.Text setter does the job, altho ListView class does not use ListViewItem.Text getter for displaying items (my MessageBox never pops up)??
Pls help.
The main problem here is that you are hiding the property with the new keyword. The original property is not virtual ("overwritable") so it is NOT overwritten but shadowed.
Read here for more information.
If I understand correctly, then the following points might be helpful.
For storing custom data you don't actually need to derive from the ListViewItem class, instead you can use an instance of a ListViewItem and set the Tag property to any object, this can be your DataStorage class. If you do this, then after you've constructed the ListViewItem set the Text of it
DataStorage storage = GetDataStorage();
ListViewItem item = new ListViewItem(storage.Name);
item.Tag = storage;
If you are going to inherit the ListViewItem then set the value in the constructor
public cListViewItem( myclass DataStorage )
{
// constructor only stores DataStorage to a local variable for further use;
this._storage = DataStorage;
this.Text = this._storage.Name;
}
Property and Method hiding gets a little confusing for myself at least, I can't quite remember the rules, but ultimately the call to Text that is done automatically is not going to be calling your version...

Access control's properties from another class in C# WPF

I'm in a mess with visibility between classes. Please, help me with this newbie question.
I have two controls (DatePickers from default WPF toolbox) which are in different windows, so in different classes. I can easily access these controls properties like datePicker1.Text from within its native class, i.e. in its native window, but when I try to reach datePicker1.Text from another window I get nothing.
I try to assign value of one datePicker to another, using reference to the window in my code:
string testStr;
...
AnotherWindow aw = new AnotherWindow();
testStr = aw.datePicker2.Text;
datePicker1.Text = testStr;
and it doesn't work
also I tried to do it through public property of a class, like:
public partial class AnotherWindow : Window
{
....
public string dateNearest
{
get { return datePicker2.Text; }
set { datePicker2.Text = value; }
}
....
and then use it in another window:
string testStr;
...
AnotherWindow aw = new AnotherWindow();
testStr = aw.dateNearest;
but also no value assigned.
Please, help me to understand this basic issue. I know there are other ways of accessing values in WPF like databinding, but I would like to understand basics first.
Unfortunately, the basics of WPF are data bindings. Doing it any other way is 'going against the grain', is bad practice, and is generally orders of magnitude more complex to code and to understand.
To your issue at hand, if you have data to share between views (and even if it's only one view), create a view model class which contains properties to represent the data, and bind to the properties from your view(s).
In your code, only manage your view model class, and don't touch the actual view with its visual controls and visual composition.
I'm using VS 2010 beta 2 right now which crashes regularly doing the simplest WPF coding, like trying to duplicate your question's code :) : but consider :
Is it possible that using this syntax will "do the right thing" :
public string dateNearest
{
get { return this.datePicker2.Text; }
set { this.datePicker2.Text = value; }
}
Edit 1 : Okay, I got a WPF replication of your code that didn't crash : using the above syntax I can both get and set the property in the "other window."
Edit 2 : The code also works using your original code :) Which, seemed to me to be "proper" the first time I read it. Are you setting that property before you read it ? : to my knowledge a DateTimePicker's Text property will be an empty string by default when first created.
Edit 3 : in response to Rem's request :
the main window has a button, 'button1 : which tests setting and getting the Public Property DTContent defined in the instance of the second Window named : 'WindowAdded : here's the 'Click event handler for that button in the main window's code :
private void button1_Click(object sender, RoutedEventArgs e)
{
WindowAdded wa = new WindowAdded();
wa.DTContent = DateTime.Now.ToString();
Console.WriteLine("dt = " + wa.DTContent);
}
Edit 4 : a better "real world" example : most cases you are going to want to create that instance of another window, and hold on to it, for re-use: imho : not have it exist only within the scope of a button's Click event. So consider, please :
Somewhere in the scope of the main window's code define a "place-holder" for the window(s) you will add : private WindowAdded wa;
In the event you select as most appropriate for creating the instance of that window : create the instance, and assign to your "place-holder" variable : then re-use it as needed. In WinForms I most often create required secondary windows that I will need to re-use references to the instances of to access something on them in the main form's load or shown events.
Discussion : of course, if your intent is to create "temporary" windows, and you don't need to re-use that reference to the new window's instance again, then creating it in the scope of some function is fine.
And, if the only thing you ever need to access on your second Window is the DateTimePicker, then you use the same technique suggested above, but create and hold to a reference to the instance of the DateTimePicker only.
As the others already pointed out, this is probably not the way to go, but you can use:
<object x:FieldModifier="public".../>
To set the object public.
See msdn for more info.

Categories

Resources