Communicating both ways between classes - c#

A little background on my project:
I'm making a multi-form application, which consists of 1 mainform, and 6 childforms that can be called from the mainform, but only 1 childform can be active at a time. These childforms share certain parts of code, which I do not want to copy. To solve this, I have a codefile within the same namespace which holds the nessaccary code.
This codefile however, needs access to certain properties of the currently active childform.
My search has come down to using an interface to extract the needed information from the active childform.
My code is currently looking like this:
Interface:
public interface Interface1
{
TabControl tabControl_Buizen_
{
get;
}
TabPage tabPage_plus_
{
get;
}
}
Childform:
public partial class Childform : Form, Interface1
{
Interface1 dummy;
public TabControl tabControl_Buizen_
{
get { return this.tabControl_Buizen; }
}
public TabPage tabPage_plus_
{
get { return this.tabPage_plus; }
}
Methods_newTabPage methods = new Methods_newTabPage(dummy);
}
Codefile:
public class Methods_newTabPage
{
private readonly Interface1 form;
public Methods_newTabPage(Interface1 formInterface)
{
this.form = formInterface;
}
}
As you can see I'm using Methods_newTabPage methods = new Methods_newTabPage(dummy); to be able to call methods in my codefile, but the codefile requires the interface to be passed (which I filled as "dummy"). This however pops the error "A field initializer cannot reference the non-static field, method, or property Childform.dummy".
How can I let the childforms access the methods in the codefile, while also giving the codefile access to certain controls in differing childforms?

The error is easy to fix: just make dummy static.
static Interface1 dummy;
However, I don't think that will help you much. Why are you passing this dummy to Methods_newTabPage anyway? This will lead to NullReferenceExceptions inside the code file because dummy was never initialized with anything.
Don't you rather want to pass this, i.e. the current instance of Childform?
But you cannot just exchange dummy with this like so:
// Compiler error "Keyword 'this' is not available in the current context".
Methods_newTabPage methods = new Methods_newTabPage(this);
Instead you have to add a constructor that creates Methods_newTabPage:
public partial class Childform : Form, Interface1
{
private Methods_newTabPage methods;
public Childform()
{
methods = new Methods_newTabPage(this);
}
public TabControl tabControl_Buizen_ { get { return this.tabControl_Buizen; } }
public TabPage tabPage_plus_ { get { return this.tabPage_plus; } }
}

Try adding a constructor that initializes the field methods.
Also I don't see how that dummy makes sense. Instead initialize methods via methods = new Methods_newTabPage(this); in the constructor.

Related

Accessing object created in different Window in WPF application

I have created one window and declared 2 instances of my object, then I modified them and wanted to pass to another Window. My questions are:
How would i do that ?
(I can pass simple types such as string or int trough window constructor but passing my own object giving me an error (Inconsistent Accessibility parameter order is less accessible then method))
Does it have any connection with dataContext ?
Can anybody explain to me how I can achieve that (in the simplest possible way)? What are the correct ways to do that ?
Here is part of my code (everything is in one namespace):
public partial class Main_window : Window
{
Order myOrder = new Order();
Menu menu = new Menu();
public Main_window()
{ InitializeComponent() }
private void OpenSecondWindow(object sender, RoutedEventArgs e)
{
Second_Window SecondWindow = new Second_Window();
Second.ShowDialog();
}
}
// Second Window class
public partial class Second_Window : Window
{
public Second_Window(Order someOrder)
{ InitializeComponent(); }
}
Make sure that the Order type, and any other type you intend to inject the SecondWindow with, is defined as a public class:
public class Order { ... }
A non-public type cannot be part of the signature of a public method or constructor.

Static referenced in another .cs file

I am overlooking something simple I think. I have a form with a checkbox. I need to know if the checkbox is checked in a different cs file/class to know whether to make a column header Option1 or Option2.
Form1 (Public partial class) code:
public bool Checked
{
get
{
return checkBox1.Checked;
}
}
In my Export1 class I have private void CreateCell1 that takes in the data to be exported (creating an excel file from a datatable). The section of code I can't get to work is:
if (Form1.Checked.Equals("true"))
{
newRow["Option1"] = date2;
}
else
{
newRow["Option2"] = date2;
}
I am getting -Error 1 An object reference is required for the non-static field, method, or property 'Matrix1.Form1.Checked.get'
What did I overlook?
Well, the problem here is exactly what the compiler is telling you. You need an object reference in order to access the property.
Allow me to explain.
In C#, by default, class members (fields, methods, properties, etc) are instance members. This means that they are tied to the instance of the class they are a part of. This enables behavior like the following:
public class Dog
{
public int Age { get; set; }
}
public class Program
{
public static void Main()
{
var dog1 = new Dog { Age: 3 };
var dog2 = new Dog { Age: 5 };
}
}
The two instances of Dog both have the property Age, however the value is tied to that instance of Dog, meaning that they can be different for each one.
In C#, as with a lot of other languages, there are things called static members of classes. When a class member is declared static, then that member is no longer tied to an instance of the class it is a part of. This means that I can do something like the following:
public class Foo
{
public static string bar = "bar";
}
public class Program
{
public static void Main()
{
Console.WriteLine(Foo.bar);
}
}
The bar field of the Foo class is declared static. This means that it is the same for all instances of Foo. In fact, we don't even have to initialize a new instance of Foo to access it.
The problem you are facing here is that, while Form1 is not a static class and Checked is not a static property, you are treating it as such. In order for what you are trying to do to work, you need to create an instance of Form1 and access that instance's Checked property.
Depending on how your program is structured, there are many ways of doing this. If Form1 is created in the scope where you are trying to access Checked, then this will be straightforward. If Form1 is what spawns the new scope, then common practice is to pass a reference to it in the constructor.
For example, if Form1 creates a new Form2 then we do the following:
public class Form2 : Form
{
private Form1 parent;
public Form2(Form1 parent)
{
this.parent = parent;
InitializeComponent();
}
}
And then you can access parent throughout Form2. Of course, depending on the structure of your program, the exact implementation will be different. However, the general pattern is the same. Pass the reference to Form1, from the scope it was created in, to the new class, and then access it from there.
One way or another, you need to access the specific instance of Form1 that you're trying to check.
A few ways to do this are:
Pass the instance to the class constructor
Setting a public property of the other class to the instance of the form
Pass the instance to the method directly
For example:
public class SomeOtherClass
{
// One option is to have a public property that can be set
public Form1 FormInstance { get; set; }
// Another option is to have it set in a constructor
public SomeOtherClass(Form1 form1)
{
this.FormInstance = form1;
}
// A third option would be to pass it directly to the method
public void AMethodThatChecksForm1(Form1 form1)
{
if (form1 != null && form1.Checked)
{
// Do something if the checkbox is checked
}
}
// This method uses the local instance of the Form1
// that was either set directly or from the constructor
public void AMethodThatChecksForm1()
{
AMethodThatChecksForm1(this.FormInstance);
}
}
This class would need to be instantiated by the instance form1 using one of these methods:
// Pass the instance through the constructor
var someOtherClass = new SomeOtherClass(this);
// Or set the value of a property to this instance
someOtherClass.FormInstance = this;
// Or pass this instance to a method of the class
someOtherClass.AMethodThatChecksForm1(this);

C# - Unable to add item to listview from method invoked from class

Im having a strange problem with my programme, whenever I call a method from another class, it doesnt work as expected. Basically, what I am trying to do is add an item to a listview, and the code is in a method, and I am trying to invoke that method from another class. Here is my code:
public class Main1
{
public void addItemToLV(string text)
{
listView1.Items.Add(text);
}
}
public class MainForm
{
Main1 m1 = new Main1();
m1.addItemToLV("test");
}
Any ideas why this is happening? Thanks.
Under normal circumstances, the controls on a form are declared as protected properties within the designer.cs file rather than public properties, so those controls will normally not be accessible to code outside of the form on which they are declared. This is intentional, as it encourages good object-oriented programming habits.
Rather than modifying a control directly from code that exists outside the form, a better practice is to declare public methods and properties within your form that can be called from outside code to manipulate the protected controls:
public class Main1
{
public static void Main()
{
var mainForm = new MainForm();
mainForm.AddItemToListView("test");
}
}
public class MainForm
{
public void AddItemToListView(string text)
{
listView1.Items.Add(text);
}
}
You could try to pass the ListView as an argument in the constructor and make the function return this ListView to your MainWindow.
public class Main1
{
private readonly ListView _lv;
public Main1(ListView listview)
{
_lv = listview;
}
public ListView addItemToLV(string text)
{
_lv.Items.Add(text);
return _lv;
}
}
I think your code sample is not enough but I am trying to guess the reason behind the issue and I think it is one of the following:
1.You are initialising your listView1 in the load event of Main1, and you are trying to show the form after calling the method. In that case you should call the method after showing the Main1 form.
2. Or simply you are trying to call the method on a different instance than the one displayed.

How to update class code to make it Type Independent

Problem: I currently have a class that takes in an object of type Control and does some work. I'm attempting to create a class that can take in either a Control, Button or a Label object. I can make this work however it would involve that I copy and paste the class two more times. One to work with Buttons and another to work with Labels. The logic and the members being called are exactly the same with the exception of the Type. I have simplified the concept I'm wishing to convey below:
// This class currently only does work on a Control object
public class takeControlType
{
public takeControlType(Control control)
{
string objectName = control.Name.ToString();
}
}
I could copy paste the code above and make it work by overloading the class Constructor like this:
public class takeAnyType
{
public takeAnyType(Control control)
{
string objectName = control.Name.ToString();
}
public takeAnyType(Button button)
{
string objectName = button.Name.ToString();
}
public takeAnyType(Label label)
{
string objectName = label.Name.ToString();
}
}
Am I correct in thinking that this just seems like a drag in productivity? I'm hoping I can reuse the same logic despite the Type being different as the only item that I would need to replace is the Type. The logic and properties being implemented in my class are exactly the same for Controls, Buttons and Labels. I've researched generics but due to the fact that I'm pulling back properties and methods specific to either a Control, Button or Label I can't seem to get generics to work with the object properties such as .Name or .Width or .Capture for example. The only methods the generic Type provides me with are
Equals()
GetHashCode()
GetType()
ToString()
I need access to a few of the properties I mentioned previously. How does one accomplish this in order that I might avoid having to copy/paste 266 lines of code that make up my class that currently is only able to work with Control objects?
Aside from attempting to make use of Generics I also tried to see if I could use base class type object as opposed to Control but that led me to the same issue I'm currently having with Generics. I no longer have access to the members that are associated with Controls, Buttons and Labels.
To clear up any confusion the example (non-working) code below is what I'm attempting to accomplish.
public class takeAnyType
{
public takeAnyType(anyType obj)
{
string objectName = obj.Name.ToString();
obj.Cursor = Cursors.SizeNESW;
obj.Capture = true;
obj.Width = 20;
obj.Top = 100;
}
}
Button and Label classes inherit from Control (indirectly). This means that if you only create a class for Control, you can still use it for objects of type Button or Label. You don't have to create special classes for those.
In C# (and OO languages in general), you can assign an instance of a derived class to a variable of a super class. For example, this is valid C# code:
Control control = new Button();
An answer addresses your example, but your problem seems to describe something more - doing some more convoluted login on Labels and Buttons. One way to do this is the following:
1) declare a base class to handle common issue (e.g. your name example)
2) declare a class for each Label and Button to handle specific logic
public class ControlHelper
{
public virtual String GetControlName(Control control)
{
return control.Name.ToString();
}
// it is not possible to do the logic on a generic control, so force derived classes to provide the logic
public abstract void DoSomeFancyStuffWithControl(Control control);
// other common functions may come here
}
public class LabelHelper : ControlHelper
{
// you may override virtual methods from ControlHelper. For GetControlName, it should not be the case
public override DoSomeFancyStuffWithControl(Control control)
{
var button = control as Label;
// ...
}
// does not have to be virtual, but allow further inheritance
public virtual String GetText(Label l)
{
return l.Text;
}
// other label specific methods come here
}
public class ButtonHelper : ControlHelper
{
public override DoSomeFancyStuffWithControl(Control control)
{
var button = control as Button;
// ...
}
public virtual bool GetEnabled(Button b)
{
return b.Enabled;
}
// other button specific functions may come here
}

Nested class with hidden constructor impossible in c#?

I' ve been doing some programming lately and faced an issue which i found weird in c#. (at least for me)
public class Foo
{
//whatever
public class FooSpecificCollection : IList<Bar>
{
//implementation details
}
public FooSpecificCollection GetFoosStuff()
{
//return the collection
}
}
I want the consumer of Foo to be able to obtain a reference to FooSpecificCollection, even perform some operations on it. Maybe even set it to some other property of Foo or smth like that, but not To be able to CREATE an instance of this class. (the only class that should be able to instatiate this collection should be Foo.
Is my request really that far-fetched? I know that people way smarter defined c# but shouldn't there be such an option that a parent class can create a nested class instance but nobody else can't.
So far I created a solution to make an abstract class, or interface available through the property and implement a concrete private class that is not available anywhere else.
Is this a correct way to handle such a situation.?
The way embedded classes work is that they, as members of the outer class, get access to private members of that outer class. But not the other way around (what is what you want).
You can shield the constructor of FooSpecificCollection, but then the Factory has to be part of FooSpecificCollection itself. It could enlist the outer class:
public class Foo
{
public class FooSpecificCollection : List<Bar>
{
private FooSpecificCollection () { }
public static FooSpecificCollection GetFoosStuff()
{
var collection = new FooSpecificCollection ();
PrepareFooSpecificCollection(collection);
return collection;
}
}
private static void PrepareFooSpecificCollection(FooSpecificCollection collection)
{
//prepare the collection
}
}
Make your nested class private and make the return value of GetFoosStuff IList<Bar> instead of FooSpecificCollection.
Also, there's a good chance that deriving from List<Bar> is a bug.
If you are creating a library for others to use, you could make the constructor internal. Anyone outside the library will not be able to access it. If you are concerned about calling the constructor in your own project, just don't call it outside the parent class.
We create classes all the time which are not directly related to other classes, but the constructors don't have to be hidden from non-related classes. We (the programmers) know the the objects are not related so we don't ever create an instance of one in the other.
There is a solution but I don't think I would use it in my App :)
The idea is to have derived class from FooSpecific which is private and can be used only inside Foo but has public constructor, so Foo can create its instances.
public class Foo
{
//whatever
public class FooSpecific
{
// Protected contructor.
protected FooSpecific()
{
}
// All other code in here.
}
// Private helper class used for initialization.
private class FooSpecificInitHelper : FooSpecific
{
public FooSpecificInitHelper()
{
}
}
// Method in foo to create instaces of FooSpecific.
private FooSpecific CreateFooSpecific()
{
return new FooSpecificInitHelper();
}
}
No, and it doesn't really make sense.
I mean the whole point is so that you could potentially return other instances; but who will be deriving from that class anyway? Certainly not any other classes (Because that would be wrong, and imply it shouldn't be hidden inside the main class), so ...

Categories

Resources