Trying to call methods between classes created dynamically - c#

I have been trying to work out how to call a method in a different class. Both classes are created dynamically at run-time. Most of the issues I have seen here relate to inheritance, which is different from what I have (I think.)
I am still fairly new to C#, and am trying to test some concepts out.
The first class is something like this:
public class Record
{
CustomPanel _panel;
public void recordFunc(){}
}
The internally created class has something like this:
public class CustomPanel : Panel
{
List<Control> _myControls = new List<Control>;
// _myControls[0] += new EventHandler(myFunc);
public void myFunc(object sender, EventArgs e)
{
// parentClass.recordFunc();
}
}
My objective is to create a Record at run-time from a database call. At that point, it creates a Panel (from my CustomPanel class) that gets added to a FlowLayoutControl. When events are fired from the panel's internal controls, I need to have it update parts of the parent Record class.
Any help is greatly appreciated.

I'm not 100% sure what you're asking, but it seems you want to know how to call a function on a class, when you don't know the class type at runtime, but it could be one or many record types. Is that correct?
If so, a way to cleanly achieve the above is to implement an interface on your derived types and call the interface method. For instance, if you have multiple "Record" classes and don't know the type at runtime, try the following:
public interface IRecord
{
void RecordFunc();
}
public class ARecord : IRecord
{
public void RecordFunc()
{
Console.WriteLine("ARecord.RecordFunc");
}
}
public class AnotherRecord : IRecord
{
public void RecordFunc()
{
Console.WriteLine("AnotherRecord.RecordFunc");
}
}
public class CustomPanel : Panel
{
private IRecord _parentRecord;
// Where parentRecord could be ARecord or AnotherRecord
public class CustomPanel(IRecord parentRecord)
{
_parentRecord = parentRecord;
}
public void MyFunc(object sender, EventArgs e)
{
_parentRecord.RecordFunc();
}
}
If that's not what you're looking for, please clarify.

There is no magic instance of the Record class available from within a CustomPanel just because a Record instance contains a CustomPanel. You'll have to set up such a relationship yourself. E.g.
public class Record
{
CustomPanel _panel;
public CustomPanel panel
{
get { return _panel; }
set { _panel = value; _panel.parent = this; }
}
public void recordFunc(){}
}
public class CustomPanel : Panel
{
public Record parent { get; set; }
public void myFunc(object sender, EventArgs e)
{
parent.recordFunc();
}
}

Related

Using C# reflection to make a Generic List of Controllers derived of the same baseclass

In order to prevent the generation of new identical lines of code, I wanted to retrieve all the fields / properties of the same class and iterate over it in order to execute their functions.
This way, if we need to add more menus to the UIsystem ( MenuControllers) we just need to add the declaration line of the new menu.
Lets write the example code
Main class
public class MenuSystem : UISystem
{
public MainMenuController _mainMenuCtrl;
public PlayerMenuController _playerMenuCtrl;
public StoreMenuController _storeMenuCtrl;
public ...
//This is what I want
private IList<MenuController<BaseMenu>> _menuList;
private const BindingFlags Flags = BindingFlags.Instance | BindingFlags.Public;
private void InitializeAllMenus()
{
//This is how it looks like now
_mainMenuCtrl.RetrieveMenuInfo();
_playerMenuCtrl.RetrieveMenuInfo();
_storeMenuCtrl.RetrieveMenuInfo();
//****WHAT I WANT TO DO*****
foreach(var menu in _menuList)
{
menu.RetrieveMenuInfo();
}
}
private void DisposeAllMenus()
{
//This is how it looks like now
_mainMenuCtrl.Dispose();
_playerMenuCtrl.Dispose();
_storeMenuCtrl.Dispose();
//****WHAT I WANT TO DO*****
foreach(var menu in _menuList)
{
menu.Dispose();
}
}
}
MenuControllers Definitions
public MainMenuController: MenuController<MainMenu>
{
public Show();
public Hide();
public OnBackButtonClicked();
...
}
public PlayerMenuController : MenuController<PlayerMenu>
{
public Show();
public Hide();
public OnBackButtonClicked();
...
}
...etc
MenuController Class
public abstract class MenuController<T> where T : BaseMenu
{
public void RetrieveMenuInfo() {...}
public void Dispose() {...}
}
I've tried something like this ( and much more to be honest but I think this is enough)
private void FillMenuList()
{
***Retrieving fields, Option 1***
var fieldList = GetType().GetFields(Flags)
.Select(var => var.GetValue(this));
***Retrieving fields, Option 2***
var fieldList = GetType().GetFields(Flags)
.Select(var => var.GetValue(this)).OfType<MenuController<BaseMenu>;
}
OPTION1 of the function above retrieve the fields of the MenuSystem class correctly as IEnumerable<object>
but Option 2 with IEnumerable<MenuController<BaseMenu>> does not retrieve any field.
Our main trouble here is that we cannot fill a list/array with all those types/derived-types to iterate over it.
I really hope its enough with this info. I'm quite newbie using reflection.
I managed to do this before in other parts of the code but with no generics involved
Thanks a lot!
You can try using GetType().GetProperties() on the object, then for each property do item.PropertyType.GetGenericArguments()[0].FullName, this will give you the generic class name. Then you can cast that to the class that you need and get all the fields data.
I hope this helps.

Accessing parent instance data from child instances in .NET 5.0 / C# 9.0

I have a .NET 5.0 web application that instantiates classes for each of the endpoints. Those classes instantiate child classes. Is there a more elegant or efficient way to access parent instance data from child instances besides the way I'm doing it right now?
As an example:
public class ComponentClass
{
private PageClass _page;
public ComponentClass(PageClass page)
{
_page = page;
}
public void ComponentMethod()
{
// Call the method from the parent instance
page.PageMethod();
}
}
public class PageClass
{
private ComponentClass _component;
public PageClass()
{
_component = new ComponentClass(this);
}
public async Task ProcessRequest(HttpContext context)
{
// Call the component's method
_component.ComponentMethod();
}
public void PageMethod()
{
// Do something here
}
}
Specifically, I'm trying to avoid having to pass this to every ComponentClass instance...
If you want to call a method on the parent, then you have two options. The first is to pass a reference of the parent into the child. There's no way around this, an object has no way to know in which object it is referenced from. In fact, it could be referenced by multiple parent objects.
The better solution is to use events. That way the child never knows anything about the parent(s) and can emit events that any number of components can subscribe to. See here for more details on events. For example, your component could look something like this:
public class Component
{
public event EventHandler Tick;
public void DoSomething()
{
EventHandler handler = Tick;
handler?.Invoke(this, new EventArgs());
}
}
And your PageClass:
public class PageClass
{
public Component _component { get; set; }
public void Init()
{
_component = new Component();
_component.Tick += Component_Tick;
}
public void MakeComponentTick()
{
// This method is just for testing, it's likely this would be triggered by user input
_component.DoSomething();
}
private void Component_Tick(object sender, EventArgs e)
{
Console.WriteLine("Component ticked!");
}
}

C# WinForms 'this.Controls.Find' in a separate class

I am trying to divide my program into classes to reduce clutter and increase readability.
In one of my methods, I need to find the location of a label on the screen.
this.Controls.Find worked before I moved everything into separate classes but it doesn't exist anymore because I am no longer executing it in the same class as the controls. I tried Main.Controls.Find (Main.cs is where my form is executed and set out) but this also didn't work and I got the error, "An object reference is required for the non-static field, method, or property 'Control.Controls'"
How do I reference the controls? Do I need to add an additional using statement?
Thanks,
Josh
You need a reference to the form, passed down to the newly introduced method (or class).
Before
public class Main : Form {
public void Whatever() {
...
this.Controls.Find(...);
}
}
After
public class Main : Form {
public void Whatever() {
...
new Helpers().HelperMethod( this );
}
}
public class Helpers {
public void HelperMethod( Form form ) {
...
form.Controls.Find
}
}
or
public class Main : Form {
public void Whatever() {
...
new Helpers( this ).HelperMethod();
}
}
public class Helpers {
private Form Form { get; set; }
public Helpers( Form form ) {
this.Form = form;
}
public void HelperMethod() {
...
this.Form.Controls.Find
}
}

Code Pattern for accessing owning class from within a sub-component class (Friend Interfaces?)

If I have a class (class P) which makes use of some other re-usable component (class C) (eg a state manager), then if that component needs to access some data within my top level class (P), then what choices do I have?
The key thing is that I dont want to expose this data to the outside world, just to within components I know and trust and use within P.
public static class Program
{
private void Main()
{
var owner = new Owner();
// I can call Foo()!!!
((IOwner)owner).Foo();
}
}
public interface IOwner
{
void Foo();
}
public class Owner : IOwner
{
private Component m_component;
public void SomeExternalAPI()
{
m_component = new Component(this);
m_component.DoSomething();
}
void IOwner.Foo()
{
// do something
}
}
public class Component
{
private readonly IOwner m_owner;
public Component(IOwner owner)
{
m_owner = owner;
}
public void DoSomething()
{
m_owner.Foo();
}
}
I could use an interface on P, but this then exposes the data externally.
I could use an explicit interface on P, but this can be cast and so also easily exposes the data.
If I could somehow impart "Friendship" upon the component (which I created, and ideally at the instance level!), and make IOwner a friend-only interface then, it would be secure.
I know this is impossible in C# at the moment.
It comes up quite often for me.
Has anyone got any solutions or suggestions?
You can use the internal accessor on your interface and Component class.
internal interface IOwner
{
void Foo();
}
internal class Component
{
private readonly IOwner m_owner;
public Component(IOwner owner)
{
m_owner = owner;
}
public void DoSomething()
{
m_owner.Foo();
}
}
The Owner class would be public
public class Owner : IOwner
{
private Component m_component;
public void SomeExternalAPI()
{
m_component = new Component(this);
m_component.DoSomething();
}
void IOwner.Foo()
{
// do something
}
}
With this approach, you won't be able to access the interface nor the Component class from an external assembly
The client would only see the Owner class and its SomeExternalAPI() method.
var Owner = new Owner();
owner.SomeExternalAPI();
//owner.Foo() --> Won't compile!
//((IOwner)owner).Foo() --> Won't compile!
I think I've found a reasonable solution, altho its quite hard work and more code than I'd like
Use a proxy class, which implements the public IOwner interface, but which can then call into the actual owner using an internal IInternalOwner interface, which it was given on construction.
The proxy then acts like a token allowing the owner to be called by anyone it gives this token to. Its more code than I would like, and it would be nice if this was built into C# :-).
But, it works between assemblies (in fact I had 4 to test it!).
public class Owner : IInternalOwner
{
private ITheComponent m_component;
public void SomeExternalAPI()
{
var proxy = new Proxy(this);
m_component = ClassFactory.ConstructTheComponent(proxy);
m_component.DoSomething();
}
void IInternalOwner.Foo()
{
// do something
Console.WriteLine("Owner.Foo was called");
}
private class Proxy : IOwner
{
private IInternalOwner m_owner;
public Proxy(IInternalOwner owner)
{
m_owner = owner;
}
/// <summary>
/// pass through for each method & property!
/// </summary>
public void Foo()
{
m_owner.Foo();
}
}
}
internal interface IInternalOwner
{
void Foo();
}

C# Correct way to access parent method

I am new to C# and OOP and have researched many of the similar topics but end up more confused than when I started. I need to be able to call a method in a parent class from a child in another namespace.
Below is a (over) simplified example of what I have now and seems to work, but is this the right/best way?
File Form1.cs:
namespace Test1
{
public partial class Form1 : Form
{
NotTest1.Class1 myClass1 = null;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
// Start the child class and pass this parent
myClass1 = new NotTest1.Class1(this);
}
public void Form1Function(String text)
{
textBox1.AppendText(text + Environment.NewLine);
}
private void button1_Click(object sender, EventArgs e)
{
// Do some stuff then call Function1 in myClass1
myClass1.Function1();
}
}
}
File Class1.cs:
namespace NotTest1
{
class Class1 {
Test1.Form1 _parent;
public Class1(Test1.Form1 parent) {
_parent = parent;
}
public void Function1()
{
// Do lots of "stuff"
_parent.Form1Function("Got Here");
}
}
}
Examples appreciated, as I am still trying to learn all of the correct terminology.
Thanks
The best way in Class1.cs use using.
using Test1;
namespace NotTest1
{
class Class1 {
Form1 _parent;
public Class1(Form1 parent) {
_parent = parent;
}
public void Function1()
{
// Do lots of "stuff"
_parent.Form1Function("Got Here");
}
}
}
If Class1 needs to call methods on a Form1 instance, then what you have done is perfectly fine, though I don't see how you have parent and child classes here. What you really a Class1 class that happens to accept a Form1 instance in order to call methods on it.
What you did works fine.
Nonetheless, you may want to explore a bit on Events - this way your Parent class may instantiate a child class and subscribe to its events, and your child class may be completely decoupled from your Parent class.
A very nice, clear example is shown on this thread:
Super-simple example of C# observer/observable with delegates

Categories

Resources