Component - Subclass event c# - c#

I have a class what I would like to close into a component. I try to make it work, based on the following code,
The issue is, that the properties are editable and viewable in the property browser & the Test Event is viewable but it cannot be filled form the property browser, just from the code.
How can I solve this anomaly?
namespace TestComponents
{
public partial class Test: Component
{
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public SubClass SubClass { get; set; }
public Test()
{
InitializeComponent();
SubClass = new SubClass();
}
}
public delegate void TestEventHandler(Object sender, TestEventArgs e);
public class TestEventArgs: EventArgs
{
public Boolean Test { get; set; }
public TestEventArgs(Boolean ATest): base()
{
Test = ATest;
}
}
[TypeConverterAttribute(typeof(System.ComponentModel.ExpandableObjectConverter))]
public class SubClass
{
public Boolean TestProperty { get; set; }
public event TestEventHandler TestEvent;
protected virtual void OnTestEvent(TestEventArgs e)
{
if (TestEvent != null)
TestEvent(this, e);
}
}
}

Problem solved. If the subclass inherited from Component, the Visual Studio can manage "subclass events" well.

Suspect the property editor doesn't know how it should handle input related to the complex TestEventArgs class, so you can't edit in in the Visual Studio property editor.
You could have a look at writing a Custom UI Type Editor and then specify the custom editor by using the EditorAttribute:
[EditorAttribute(typeof(YourCustomEditor),typeof(System.Drawing.Design.UITypeEditor))]

Related

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!");
}
}

How to invoke a method when a property of a nested object changes?

Say I have the class MyObject:
public class MyObject
{
public SomeOtherObject SomeOtherObject { get; set; }
public void MyMethod()
{
//Do something
}
}
Where MyObject.SomeOtherObject is as follows:
public class SomeOtherObject
{
public string Information { get; set; }
}
Assume that the property SomeOtherObject.Information is set by an instance of another class.
How can I automatically invoke MyObject.MyMethod() when MyObject.SomeOtherObject.Information changes?
Define an event callback. In SomeOtherObject;
public EventCallback OnInformationChangedEvent { get; set; }
I am not sure exactly what is setting the Information property. But ultimately you need a line somewhere in you SomeOtherObject class that does this;
await OnInformationChangedEvent.InvokeAsync();
You could even do this in the setter of the property itself.
In the parent MyObject you can pass the method that you want to be invoked. And refine your method as follows;
public void MyMethod(object sender, EventArgs e)
{
//Do something
}
And where you define SomeOtherObject;
SomeOtherObject.OnInformationChangedEvent += MyMethod;
There are other ways to do it (for example defining your own Observer pattern, which I think is what .NET is doing underneath anyway).
I didn't run that code so my syntax might be slightly off, but you should be 99% there with that.
I recommend using events. In the class MyObject, you can specify an event and register an event handler for this event - either use MyMethod as event handler or create another method that calls MyMethod.
Then, rewrite SomeOtherObject:
public class SomeOtherObject
{
public string Information
{
get => _Information;
set
{
_Information = value;
// add code to fire the event
}
}
private string _Information;
}

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
}
}

How to add menu to a Component Class?

I've just created a solution and added a 'Component Class' to it.
All I need is to add a menu to Component Class when it is in the componentbar of a win-form, like the ImageList component of .NET.
Can anyone help me?
I assume you are referring to the little tiny arrow that appears on the ImageList component when you select it and you see a list of options. That requires a custom ComponentDesigner.
Make references to:
System.Components.Design
System.Design
System.Windows.Forms.Design
Here is a simple little component example:
[Designer(typeof(TestComponentDesigner))]
public class TestComponent : Component {
public class TestComponentDesigner : ComponentDesigner {
private DesignerVerbCollection verbs = new DesignerVerbCollection();
public override void Initialize(IComponent component) {
base.Initialize(component);
verbs.Add(new DesignerVerb("Say Hello", new EventHandler(SayHello)));
}
public override DesignerVerbCollection Verbs {
get {
return verbs;
}
}
private void SayHello(object sender, EventArgs e) {
MessageBox.Show("Hello");
}
}
}
Results:
For more information, see Writing Custom Designers for .NET Components

Trying to call methods between classes created dynamically

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();
}
}

Categories

Resources