CollectionChanged get the instance of object thats holding the collection - c#

Is it possbible to get the Instance of an item, within the CollectionChanged event?
For Example:
public class Foo
{
public string Name { get; set; }
public ObservableCollection<Bar> Bars { get; set; }
public Foo()
{
Bars += HelperFoo.Bars_CollectionChanged;
}
}
public class Bar
{
public string Name { get; set; }
}
public static class HelperFoo
{
public static voic Bars_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
//sender is the collection Foo.Bars
//can I get the Instance of Foo?
}
}
(I wouldnt mind using reflection)
If this isnt possible is there a way to get the Instance of object that intializes an other object?
For Example:
public class Foo
{
public string Name { get; set; }
public Foo()
{
var bar = new Bar(); //yes I know, I could write new Bar(this) and provide an overload for this
}
}
public class Bar
{
public string Name { get; set; }
public Bar()
{
//Get the Foo, since the constructor is called within Foo, is this possible?
//without providing an overload that takes an object, and just change it to `(new Bar(this))`
}
}

I agree with #Gaz but if you are really wanting to do what you describe then add a Dictionary to your HelperFoo class. Then in your Foo class add this as the creator as follows.
public static class HelperFoo
{
private static Dictionary<ObservableCollection<Bar>, object> lookupCreators = new Dictionary<ObservableCollection<Bar>, object>();
public static void AddBarsCreator(ObservableCollection<Bar> bars, object creator)
{
lookupCreators.Add(bars, creator);
}
public static void Bars_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
ObservableCollection<Bar> bars = (ObservableCollection<Bar>)sender;
if (lookupCreators.ContainsKey(bars))
{
}
}
}
public class Foo
{
public ObservableCollection<Bar> Bars { get; set; }
public Foo()
{
Bars = new ObservableCollection<Bar>();
HelperFoo.AddBarsCreator(Bars, this);
Bars.CollectionChanged += HelperFoo.Bars_CollectionChanged;
}
}

Your code seems rather oddly structured.
If your HelperFoo class needs to do something with Foo, then pass it Foo, and let it subscribe to Bar events itself.
If HelperFoo shouldn't know anything about Bars, then expose an event on Foo instead and subscribe to that. You can raise then event inside Foo when Bars changes.
Have a read up on the Law Of Demeter.

Related

Is there a way to get the conversion of derived class to baseclass work in this case?

I have currently a problem
I have 1 Interface with two types of argument like this
ITestInterface<ArgumentA>
ITestInterface<ArgumentB>
this interface has only the argument as different
I would like to pass this interface to an constructor of a class. sth like this
public class MyClass
{
public ITestInterface<object> MyInterface {get; set;}
public MyClass(ITestInterface<ArgumentA> testInterfaceA){
this.MyInterface = testInterfaceA as ITestInterface<object>;
this.MyTestInterface.SomeEvent += this.OnSubcribe;
}
public MyClass(ITestInterface<ArgumentB> testInterfaceB){
this.MyInterface = testInterfaceB as ITestInterface<object>;
this.MyTestInterface.SomeEvent += this.OnSubcribe;
}
public void OnSubcribe(){
//Work to do here, dont care about what argument the interface has.
}
}
and to call the MyClass constructor I have sth like this:
public List<MyClass> ClassList = new();
public void testMethod(){
var interA = getInterfaceWithArgumentA();
var myClassA = new MyClass(interA);
var interB = getInterfaceWithArgumentB();
var myClassB = new MyClass(interB);
}
So the problem is i am not able to cast the interface argument to object. I dont need to differenciate the argument either. I just want to avoid to have 2 properties of MyInterface like (MyInterfaceA, MyInterfaceB).
I need also to consider that maybe in the future I will have more type of Argument so maybe to have multiple properties like MyInterfaceA, MyInterfaceB, MyInterfaceC and also multiple constructor for each Interfaceargument type would be a mess.
I just thought about have a Baseclass and the ArgumentA and ArgumentB class derived from it so the cast would work but its not like that.
How would I solve this problem ?
Many Thanks
I think you have not provided what getInterfaceWithArgumentB() and getInterfaceWithArgumentA() method doing. I am making few assumption.
To solve your problem Generic will help.
Following is the example of it.
public class MyClass<T>
{
public ITestInterface<T> MyInterface { get; set; }
public MyClass(ITestInterface<T> testInterfaceA)
{
this.MyInterface = testInterfaceA;
this.MyInterface.SomeEvent += MyInterface_SomeEvent;
}
private void MyInterface_SomeEvent(object sender, EventArgs e)
{
Console.WriteLine(sender);
}
}
public class ArgumentA
{
public string Name { get; set; }
}
public class ArgumentB
{
public int Id { get; set; }
}
public interface ITestInterface<T>
{
T Data { get; set; }
event EventHandler SomeEvent;
void OnSomeEvent();
}
public class TestInterface<T> : ITestInterface<T>
{
public T Data { get ; set; }
public event EventHandler SomeEvent;
public void OnSomeEvent()
{
if(SomeEvent != null)
SomeEvent(Data, EventArgs.Empty);
}
}
You can use it like following.
MyClass<ArgumentA> myClass = new MyClass<ArgumentA>(
new TestInterface<ArgumentA>()
{
Data = new ArgumentA() { Name = "test" }
});
MyClass<ArgumentB> myClas2 = new MyClass<ArgumentB>(
new TestInterface<ArgumentB>()
{
Data = new ArgumentB() { Id = 10 }
});
myClas2.MyInterface.OnSomeEvent();
myClass.MyInterface.OnSomeEvent();
UPDATE
class Program
{
static void Main(string[] args)
{
ObservableCollection<MyClass> items = new ObservableCollection<MyClass>();
MyClass<ArgumentA> myClass = new MyClass<ArgumentA>(
new TestInterface<ArgumentA>()
{
Data = new ArgumentA() { Name = "test" }
});
MyClass<ArgumentB> myClas2 = new MyClass<ArgumentB>(
new TestInterface<ArgumentB>()
{
Data = new ArgumentB() { Id = 10 }
});
items.Add(myClass);
items.Add(myClas2);
myClas2.MyInterface.OnSomeEvent();
myClass.MyInterface.OnSomeEvent();
}
}
public class MyClass
{
public ITestInterface MyInterface { get; set; }
}
public class MyClass<T> : MyClass
{
public MyClass(ITestInterface<T> testInterfaceA)
{
this.MyInterface = testInterfaceA;
this.MyInterface.SomeEvent += MyInterface_SomeEvent;
}
private void MyInterface_SomeEvent(object sender, EventArgs e)
{
Console.WriteLine(sender);
}
}
public class ArgumentA
{
public string Name { get; set; }
}
public class ArgumentB
{
public int Id { get; set; }
}
public interface ITestInterface
{
event EventHandler SomeEvent;
void OnSomeEvent();
}
public interface ITestInterface<T> : ITestInterface
{
T Data { get; }
}
public class TestInterface<T> : ITestInterface<T>
{
public T Data { get; set; }
public event EventHandler SomeEvent;
public void OnSomeEvent()
{
if (SomeEvent != null)
SomeEvent(Data, EventArgs.Empty);
}
}

Saving item picked from list

Main class:
public class Main
{
private string param;
public Main(string param) { this.param = param; }
public List<Foo> Foos
{
get {return GetFoos();}
// add functionality of saving Foo (single item, not the whole list) here?
}
private List<Foo> GetFoos()
{
List<Foo> x = new List<Foo>();
return x;
}
public class Foo
{
public int Id { get; set; }
public string Name { get; set; }
// or maybe here?
}
}
Test class:
public class Test
{
public Test()
{
var main = new Main("hi!");
// usage 1
main.Foos.Find(p => p.Id == 1).Save(); // method visible here
var foo = new Main.Foo();
// usage 2
foo.Save(); // method not visible here
}
}
Comments in the code basically say everything:
1. I want to implement the Save() method of the object Foo.
2. Method can be called only if the Foo object is picked up from the list (usage 1).
3. Method can not be called from the Foo object created alone (usage 2).
4. Method must use private value of the property param passed during initialization of the main class.
You can use an interface to hide the method Save.
To do this, the Save method must be implemented explicitly.
Additionally you need a link to the main object. In your subclass Foo you can access the private attribute from Main directly.
Interface:
public interface IFoo
{
int Id { get; set; }
string Name { get; set; }
void Save();
}
Class:
public class Main
{
private string param;
private List<IFoo> foos = new List<IFoo>();
public Main(string param) { this.param = param; }
public List<IFoo> Foos
{
get { return this.foos; }
}
public void AddFoo(int pnId, string pnName)
{
this.foos.Add(new Foo(this) { Id = pnId, Name = pnName });
}
public class Foo : IFoo
{
private Main moParent;
public Foo() { }
public Foo(Main poParent)
{
this.moParent = poParent;
}
public int Id { get; set; }
public string Name { get; set; }
//Implement interface explicitly
void IFoo.Save()
{
if (this.moParent == null)
throw new InvalidOperationException("Parent not set");
Console.WriteLine($"Save with Param: {this.moParent.param}, Id: {this.Id} Name: {this.Name}");
//Save Item
}
}
}
Usage:
var main = new Main("hi!");
main.AddFoo(1, "Foo1");
// usage 1
main.Foos.Find(p => p.Id == 1).Save(); // method visible here
var foo = new Main.Foo();
// usage 2
//foo.Save(); // Save is not visible here

C# Static property in non-static class as indicator of main object of this class

I have class Important and some objects of this class created. I want allow user to choose main object of this class. Have a look at code below:
public class Program
{
public static void Main(string[] args)
{
Important imp1 = new Important("Important 1");
Important imp2 = new Important("Important 2");
Important imp3 = new Important("Important 3");
imp2.SetMostImportant();
Console.Write(Important.MostImportant.Name);
}
public class Important
{
public Important(string name)
{
Name = name;
if(MostImportant == null)
SetMostImportant();
}
public string Name { get; private set; }
public static Important MostImportant { get; private set; }
public void SetMostImportant()
{
MostImportant = this;
}
}
}
Is it good solution? If not, please tell me why not.
Before, to achieve this kind of things I just created boolean field named e.g. IsMainObject and, when I wanted to change main object, I iterated through all objects (or group of object) of specific class except element that I want to be main, and changed boolean to false, in my new candidate I simply set flag to true. Example below:
public class Program
{
public static void Main(string[] args)
{
Important imp1 = new Important("Important 1");
Important imp2 = new Important("Important 2");
Important imp3 = new Important("Important 3");
List<Important> list = new List<Important> { imp1, imp2, imp3 };
foreach(var item in list.Where(x => x.Name != "Important 2"))
{
item.SetMostImportant(false);
}
imp2.SetMostImportant(true);
Console.Write(list.FirstOrDefault(x => x.MostImportant == true).Name);
}
public class Important
{
public Important(string name)
{
Name = name;
}
public string Name { get; private set; }
public bool MostImportant { get; private set; }
public void SetMostImportant(bool val)
{
MostImportant = val;
}
}
}
I don't like this solution because:
I don't know if MostImportant is true for more than one objects without iterating.
I need to write extra-code to handle much more cases.
I don't have possibility to always iterate through all instances of specific class (groups not always are enough).
... and much more, but you got the idea.
public static Important MostImportant { get; private set; }
is a fine solution, and much better than
public bool MostImportant { get; private set; }
It's not uncommon to have a static property of the type that it's inside of when implementing "singleton" classes. I've written code that resembles this:
class MyClass
{
public static MyClass Instance { get; private set; }
public MyClass()
{
if (Instance == null)
{
Instance = this;
}
else
{
throw new Exception("MyClass already instantiated.");
}
}
}

Creating own Event for initialization of an object

So I was trying to create my own event for the initialization of a class called Car, which inherits from an Automobile object. Below is the same in C# code:
`
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Abc.Training.Artifacts;
namespace Abc.Training.Objects
{
public abstract class Automobile
{
public string Model { get; set; }
public string Manufacturer { get; set; }
public string YoM { get; set; }
}
public class Car : Automobile
{
public static event Delegates.ObjectInitHandler OnInit;
public string MarketSegment { get; set; }
public int BootSpace { get; set; }
public Car(string model, string manufacturer, string yom)
{
Model = model ;
Manufacturer = manufacturer;
YoM = yom;
ObjectInitEventArgs eArgs = new ObjectInitEventArgs();
eArgs.IsResidentObject = true;
eArgs.ObjectType = this.GetType();
if (OnInit != null) OnInit(this, eArgs);
}
}
}
`
The ObjectInitHandler and its args (the delegate type used here) is also created by me as:
`
public delegate void ObjectInitHandler(object sender, ObjectInitEventArgs e);
public class ObjectInitEventArgs:EventArgs
{
public Type ObjectType { get; set; }
public bool IsResidentObject { get; set; }
}
`
I am subscribing to the event as below:
`
Car.OnInit += new Delegates.ObjectInitHandler(Car_OnInit);//able to do this as event is static
Car c = new Car("Maruti", "Maruti", "2004");
void Car_OnInit(object sender, ObjectInitEventArgs e)
{
Console.WriteLine("Car object initialized");
}
`
I wanted to create an event OnInit for this class. However, if I put an instance event OnInit in the publisher (my Car class), I will have to initialize the class first before I can subscribe to this event. Since I would like to fire this event on initialization, this becomes a chicken and egg problem for me.
I solved it by creating a static event Object and doing the subscription before the object initialization as shown below (this is a snippet from the code above itself):
public static event Delegates.ObjectInitHandler OnInit;
However, in an ASP.NET application, this would mean if multiple users access this application, I will have the same delegate object that will have duplicate subscriptions of events (because its static), which is obviously not cool.
Is there a design pattern which I can follow to have the event also as an instance member but still I can subscribe to the event before instantiation?
I think you have to pass that function as a callback:
public class Car : Automobile
{
// public static event Delegates.ObjectInitHandler OnInit; remove this
public string MarketSegment { get; set; }
public int BootSpace { get; set; }
public Car(string model, string manufacturer, string yom,ObjectInitHandler OnInit) //add the callback as parameter.
{
Model = model ;
Manufacturer = manufacturer;
YoM = yom;
ObjectInitEventArgs eArgs = new ObjectInitEventArgs();
eArgs.IsResidentObject = true;
eArgs.ObjectType = this.GetType();
if (OnInit != null) OnInit(this, eArgs);
}
}
Pass a callback to the constructor when initializing an object:
Car c = new Car("Maruti", "Maruti", "2004",new Delegates.ObjectInitHandler(Car_OnInit));
void Car_OnInit(object sender, ObjectInitEventArgs e)
{
Console.WriteLine("Car object initialized");
}
Actually, I don't see a need for an initialization event in your code unless there are asynchronous operations inside your constructor.
here is a way to do it, it don't use statics, and i used Actions instead of event arguments. (you can use it your way!)
note that i passed the callback function to the object when creating!
class Program
{
static void Main(string[] args)
{
Car c = new Car("Maruti", "Maruti", "2004", Car_OnInit);
Console.WriteLine("Press a key to exit...");
Console.ReadKey();
}
static void Car_OnInit()
{
Console.WriteLine("Car object initialized");
}
}
public abstract class Automobile
{
public string Model { get; set; }
public string Manufacturer { get; set; }
public string YoM { get; set; }
}
public class Car : Automobile
{
public event Action OnInit;
public string MarketSegment { get; set; }
public int BootSpace { get; set; }
public Car(string model, string manufacturer, string yom, Action callBack)
{
this.OnInit += callBack;
Model = model;
Manufacturer = manufacturer;
YoM = yom;
if (OnInit != null) OnInit();
}
}
Also you can pass any argumenst if you want, just use Action<T> like Action<string> instead of Action. then your callback will be Car_OnInit(string)
There is no need (even if it were possible). You have everything you need.
Firstly, you wouldn't subscribe to the event each page load/per user. You would do it once.. in Application_Start for example.
Second.. you have everything you need in the event. Notice this line of code:
if (OnInit != null) OnInit(this, eArgs);
You pass this as the sender argument. this is an instance of Car. So, in your event.. you have the instance you care about:
void Car_OnInit(object sender, ObjectInitEventArgs e) {
var instance = sender as Car;
// use instance here.
}

MEF : How can I import a class which has a constructor marked with the ImportingConstructorFlag

My question title sounds a little bit difficult - sorry. I'm new in MEF :-).
My scenario:
public class MainClass
{
[ImportMany(typeof(ITest))]
private List<ITest> Tests { get; set; }
public MainClass()
{
Init();
}
private void Init()
{
DirectoryCatalog catalog = new DirectoryCatalog(#"./");
CompositionContainer container = new CompositionContainer(catalog);
container.ComposeParts(this);
}
}
[Export("BirthdayJob")]
[Export(typeof(ITest))]
public partial class BirthdayTest : ITest
{
[ImportingConstructor]
public BirthdayUserControl(IParameter parameter)
{
InitializeComponent();
this.Parameter = jobParameter;
}
public IParameter Parameter { get; set; }
}
[Export(typeof(IParameter))]
[Export("BirthdayParameter")]
public class BirthdayJobParameter : IParameter
{
public override string ToString()
{
return "Birthday Remember";
}
}
public interface IParameter : IMefInterface
{
}
public interface IMefInterface
{
}
In the generic list of test, I should have all possible ITest objects with the associated IParameter object. Unfortunately, there aren't any items in the generic list.
Can you help? What did I do wrong?
Thanks in advance.
Regards, pro
//Edit
So I have a compilable Class for my problem :
using System;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
namespace ObjectContracts
{
public class Program
{
static void Main(string[] args)
{
var container = new CompositionContainer(new TypeCatalog(typeof (IFoo), typeof (Bar), typeof(Foo)));
var bar = container.GetExportedValue<Bar>();
Console.WriteLine(bar.Foo.Message);
Console.ReadLine();
}
}
[InheritedExport]
public interface IFoo
{
string Message { get; set; }
}
[Export]
public class Bar
{
[ImportingConstructor]
public Bar([Import("Foo")]IFoo foo)
{
this.Foo = foo;
}
public IFoo Foo { get; set;}
}
[Export("Foo")]
public class Foo : IFoo
{
public Foo()
{
Message = ":-)";
}
public string Message { get; set; }
}
}
What do I do wrong? Please help me :-)
Regards, patrick
The point is that if you use a contract (in your case "BirthdayJob") in your export, you need to specify that in your import as well. Like so:
[Export("BirthdayJob",typeof(ITest))]
public partial class BirthdayTest : ITest
{
// class definition
}
And your import:
public class MainClass
{
[ImportMany("BirthdayJob",typeof(ITest))]
private List<ITest> Tests { get; set; }
// class definition
}
The great thing about contracts is that they allow you to group instances of certain objects of a specific type and filter out any unwanted instances of objects of a specific type.
MEF is the coolest!
[Export("PeopleLivingInEdmontonAlbertaCanada",typeof(IPerson))]
public Person KevinParkinson { get; set; }
I've found the solution. In the export class of the foo class should be a reference of the derived interface. The constructor which have the importingconstructor flag should have also a reference to the interface.
[Export]
public class Bar
{
[ImportingConstructor]
public Bar([Import("Foo", typeof(IFoo))]IFoo foo)
//public Bar([Import(typeof(IFoo))]IFoo foo)
{
this.Foo = foo;
}
public IFoo Foo { get; set;}
}
[Export("Foo", typeof(IFoo))]
public class Foo : IFoo
{
public Foo()
{
Message = ":-)";
}
public string Message { get; set; }
}
Taking a wild guess, it is possibly the working directory of your DirectoryCatalog (depending on how you run the app.)
To verify that this is the problem, replace:
DirectoryCatalog catalog = new DirectoryCatalog(#"./");
With either:
DirectoryCatalog catalog = new DirectoryCatalog(#"<full path to directory>");
or:
AssemblyCatalog catalog = new AssemblyCatalog(typeof(BirthdayTest).Assembly);
Are you exporting IParameter anywhere? In the code you posted, you are not, and this is why the Birthday test isn't being picked up.

Categories