Contravariance isn't working - c#

public interface IMyControl<in T> where T : ICoreEntity
{
void SetEntity(T dataObject);
}
public class MyControl : UserControl, IMyControl<DataObject> // DataObject implements ICoreEntity
{
void SetEntity(T dataObject);
}
All fine so far, but why does this create null?
var control = LoadControl("~/Controls/MyControl.ascx"); // assume this line works
IMyControl<ICoreEntity> myControl = control;
myControl is now null...

You cannot have dataObject as parameter for this to work. Methods could only return it.
public interface ICoreEntity { }
public class DataObject: ICoreEntity { }
public interface IMyControl<out T> where T : ICoreEntity
{
T GetEntity();
}
public class MyControl : IMyControl<DataObject> // DataObject implements ICoreEntity
{
public DataObject GetEntity()
{
throw new NotImplementedException();
}
}
Now you can:
MyControl control = new MyControl();
IMyControl<ICoreEntity> myControl = control;

Related

AccessibleObject implementation for custom controls

I have a very simple controls library for Windows Forms and I am getting problems to implement accessibility.
I have a very simple Form with a member that contains a list of controls of my library, and I have overriden the CreateAccessibilityInstance:
public partial class Form1 : Form
{
protected override AccessibleObject CreateAccessibilityInstance()
{
return new AccessibleForm(this);
}
public MyContainer MyContainer;
public Form1()
{
InitializeComponent();
MyContainer = new MyContainer();
MyContainer.Controls.Add(new MyButton());
}
}
The AccessibleForm class looks like:
public class AccessibleForm: Control.ControlAccessibleObject
{
private Form1 form1;
public AccessibleForm(Form1 owner):base(owner)
{
this.form1 = owner;
}
public override AccessibleObject GetChild(int index)
{
return this.form1.MyContainer.Controls[index].AccessibilityObject;
}
public override int GetChildCount()
{
return this.form1.MyContainer.Controls.Count() ;
}
}
MyContanier and MyButton classes inherits from BaseControl, they are very easy:
public class BaseControl : Control
{
protected override AccessibleObject CreateAccessibilityInstance()
{
return new AccessibleObject();
}
}
public class MyContainer:BaseControl
{
public List<BaseControl> Controls { get; set; }
public MyContainer()
{
this.Controls = new List<BaseControl>();
}
}
public class MyButton:BaseControl
{
}
The point is that when I run the UIVerify tool to see if my controls are generating the correct structure I can not see them:
Another point is, that if I modify the GetChild method from AccessibleForm class in this way:
public override AccessibleObject GetChild(int index)
{
return new AccessibleObject();
////return this.form1.MyContainer.Controls[index].AccessibilityObject;
}
I can see a node on the UIVerify:
But modifying the GetChild method to return a custom accessible object it shows me nothing.
Why are not my controls on the tree?
I do not know what I am missing.
Override Name,value,Role in AccessibleForm class

Encapsulating property and interface in C#

I have a class:
public class A
{
private IB link;
public IB Link
{
get { return link; }
set
{
link = value;
b.Link = this;
}
}
...
}
and an interface:
public interface IB
{
A Link { get; set; }
}
I will use it like this:
public class B1 : IB, Button
{
public A Link { get; set; }
...
}
public class B2 : IB, TextBox
{
public A Link { get; set; }
...
}
b1 = new B1();
b2 = new B2();
A a = new A();
a.Link = b1;
...
a.Link = b2;
But I have to encapsulate the IB.Link property, it should changed only in the A class (along with the A.Link property). Is this possible?
Update:
Sorry for ambiguity of this example. My real code is too large and not finished: I have a structure of nodes. Each node has a link to Control. So, visual structure of controls can be constructed. We can manage the controls from nodes, but not get access to node from control, for example, from OnMouseClick method. We need have back reference - the IMyControl.OwnerNode property. IMyControl is interface that contains only this property. So, we can create "MyControl : IMyControl, Control" class and implement into it mouse click logic. When we assign control to node, both references must be created, direct and back, but it take place in code of node class, not in MyControl and IMyControl code. Property field in IMyControl interface must be accessible for write from NodeClass and unaccessible for write from derived classes. That i am trying to accomplish here.
If I understand you correctly, you can use this draft:
class Node
{
public ControlWrapper Link { get; set; }
}
abstract class ControlWrapper
{
private readonly Node _node;
private readonly Control _control;
public Node Node
{
get { return _node; }
}
public Control Control
{
get { return _control; }
}
public ControlWrapper(Node node, Control control)
{
if (node == null)
throw new ArgumentNullException("node");
if (control == null)
throw new ArgumentNullException("control");
_node = node;
_control = control;
}
}
class ControlWrapper<TControl> : ControlWrapper
where TControl : System.Windows.Forms.Control
{
public TControl Control
{
get { return (TControl)base.Control; }
}
public ControlWrapper(Node node, TControl control)
: base (node, control)
{
}
}
class Program
{
static void Main(string[] args)
{
Node n1 = new Node();
n1.Link = new ControlWrapper<TextBox>(n1, new TextBox());
Node n2 = new Node();
n2.Link = new ControlWrapper<Button>(n2, new Button());
}
}
Abstract class ControlWrapper provides you with back-link to node (you can't encapsulate logic in interface, so abstract class goes here), typed derived generic class provides constructor for creating actual implementations of control-wrappers.
If you want this relation automatically force its consistency, you should write code like this:
class Program
{
static void Main(string[] args)
{
Node n1 = new Node();
n1.SetControl(new TextBox());
Node n2 = new Node();
n2.SetControl(new Button());
}
}
class Node
{
private ControlWrapper _link;
public ControlWrapper Link
{
get { return _link; }
}
public void SetControl<TControl>(TControl control)
where TControl : System.Windows.Forms.Control
{
ControlWrapper prevLink = Link;
if (prevLink != null)
prevLink.Dispose();
_link = new ControlWrapper<TControl>(this, control);
}
}
// microsoft basic dispose pattern
// http://msdn.microsoft.com/en-us/library/b1yfkh5e(v=vs.110).aspx#basic_pattern
abstract class ControlWrapper : IDisposable
{
private readonly Node _node;
private readonly Control _control;
public Node Node
{
get { return _node; }
}
public Control Control
{
get { return _control; }
}
public ControlWrapper(Node node, Control control)
{
if (node == null)
throw new ArgumentNullException("node");
if (control == null)
throw new ArgumentNullException("control");
_node = node;
_control = control;
}
#region IDisposable Members
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
#endregion
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
if (_control != null)
_control.Dispose();
}
}
}
class ControlWrapper<TControl> : ControlWrapper
where TControl : System.Windows.Forms.Control
{
public TControl Control
{
get { return (TControl)base.Control; }
}
public ControlWrapper(Node node, TControl control)
: base (node, control)
{
}
}

In C#, the interface can be instantiated?

I'm reading the code in here. I find that private ITreeModel _model; in TreeList.cs:
namespace Aga.Controls.Tree
{
public class TreeList: ListView
{
#region Properties
//...
private ITreeModel _model;
public ITreeModel Model
{
//...
}
//...
}
}
and the ITreeModel is a interface in ITreeModel.cs:
namespace Aga.Controls.Tree
{
public interface ITreeModel
{
/// <summary>
/// Get list of children of the specified parent
/// </summary>
IEnumerable GetChildren(object parent);
/// <summary>
/// returns wheather specified parent has any children or not.
/// </summary>
bool HasChildren(object parent);
}
}
the _model is a instantiated object?
Edited:
TreeList.cs:
namespace Aga.Controls.Tree
{
public class TreeList: ListView
{
#region Properties
/// <summary>
/// Internal collection of rows representing visible nodes, actually displayed in the ListView
/// </summary>
internal ObservableCollectionAdv<TreeNode> Rows
{
get;
private set;
}
private ITreeModel _model;
public ITreeModel Model
{
get { return _model; }
set
{
if (_model != value)
{
_model = value;
_root.Children.Clear();
Rows.Clear();
CreateChildrenNodes(_root);
}
}
}
private TreeNode _root;
internal TreeNode Root
{
get { return _root; }
}
//....
}
}
}
Edited2:
Somewhere:
public partial class RegistrySample : UserControl
{
public RegistrySample()
{
InitializeComponent();
_tree.Model = new RegistryModel();
}
}
class RegistryModel : ITreeModel
Of course you can do this, but underlying object must implement this Interface. So you can do something like
ITreeModel _model = new TreeModel();
Where
public class TreeModel:ITreeModel
{
...
}
You can never instantiate an interface in C# directly, but yes you can instantiate a subclass implementing that interface. For example:
interface IShape
{
//Method Signature
void area(int r);
}
public class Circle : IShape
{
//method Implementation
void area(int r)
{
float area;
area = 3.14 * r * r;
Console.WriteLine("The area of the circle is: {0}",area);
}
}
public class Shapes
{
public static void Main() {
//Uncommenting the following line will cause compiler error as the
// line tries to create an instance of interface.
// interface i = new IShape();
// We can have references of interface type.
IShape i = new Circle();
i.area(10);
}
}
It's implemented somewhere else in the code. If you call _model.GetType().ToString() you will see it is not just an interface.
But to answer your question correctly, YES, an interface can be instantiated. Some of you may think "no it can't", but it can be done (with some COM hacks):
class Foo : IFoo
{
readonly string name;
public Foo(string name)
{
this.name = name;
}
string IFoo.Message
{
get
{
return "Hello from " + name;
}
}
}
// these attributes make it work
// (the guid is purely random)
[ComImport, CoClass(typeof(Foo))]
[Guid("d60908eb-fd5a-4d3c-9392-8646fcd1edce")]
interface IFoo
{
string Message {get;}
}
//and then somewhere else:
IFoo foo = new IFoo(); //no errors!
Here is my source.
That _model should contain an instance of a class that implements that ITreeModel interface (or it's null).
From Interfaces (C# Programming Guide)
An interface can't be instantiated directly. Its members are
implemented by any class or struct that implements the interface.
No _model is an interface reference to instance of a class object which implements ITreeModel
_model is a member of TreeList and that means that you can create an instance of a class and then it will contain an instance of some class. for example
_model = new TreeModel();
will make _model contain an instance
but you cannot do
_model = new ITreeModel();
because ITreeModel is and interface and you cannot create an instance of an interface

Why overriden ToString() do not return what I want when item added to ComboBox?

public partial class TestConrol : UserControl
{
public TestConrol()
{
InitializeComponent();
}
public override string ToString()
{
return "asd";
}
}
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
TestConrol tc1 = new TestConrol();
comboBox1.Items.Add(tc1);
TestConrol tc2 = new TestConrol();
comboBox1.Items.Add(tc2);
}
}
When form loaded, I see combobox has two items with empty names, instead of "asd" :/
But this work if I override ToString() in common class, not derived from anything:
public class TestClass
{
public override string ToString()
{
return "bla bla bla";
}
}
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
TestClass tcl = new TestClass();
comboBox1.Items.Add(tcl);
}
}
After that I see in combobox "bla bla bla"
Create a property in you control and map the DisplayMember of the combobox to that property, it should work.
I tried to understand the source code(!). This is not a simple call to ToString().
There's an internal class System.Windows.Forms.Formatter doing some stuff. It eventually creates a converter. This is roughly equivalent to saying:
var conv = System.ComponentModel.TypeDescriptor.GetConverter(tc1.GetType());
where tc1 is the TestContol from your question. Now, had we used the TestClass tcl which doesn't implement any interfaces, this would have given us a converter which would eventually call ToString().
But in this example we use tc1, and it is a System.ComponentModel.IComponent. Our conv therefore becomes a System.ComponentModel.ComponentConverter. It uses the Site of the IComponent. When we say:
string result = conv.ConvertTo(tc1, typeof(string));
and the Site is null, we get the empty string "" you saw in your combo box. Had there been a Site it would have used its Name instead.
To demonstrate that, put the following into your TestControl instance constructor:
public TestConrol()
{
InitializeComponent();
Site = new DummySite(); // note: Site is public, so you can also
// write to it from outside the class.
// It is also virtual, so you can override
// its getter and setter.
}
where DummySite is something like:
class DummySite : ISite
{
public IComponent Component
{
get { throw new NotImplementedException(); }
}
public IContainer Container
{
get { throw new NotImplementedException(); }
}
public bool DesignMode
{
get { throw new NotImplementedException(); }
}
public string Name
{
get
{
return "asd"; // HERE'S YOUR TEXT
}
set
{
throw new NotImplementedException();
}
}
public object GetService(Type serviceType)
{
return null;
}
}
Use comboBox1.Items.Add(tc1.ToString()); instead of comboBox1.Items.Add(tcl);
This worked for me:
comboBox1.FormattingEnabled = false
In your UserControl, add a property, and call it FriendlyName for example, as such
namespace project
{
public partial class CustomUserControl : UserControl
{
public CustomUserControl()
{
InitializeComponent();
}
public String FriendlyName { get => "Custom name"; }
}
}
And then set the DisplayMember property of your ComboBox to "FriendlyName", as such
myComboBox.DisplayMember = "FriendlyName";
And to me, this was a very clean solution and gut tells me it is the intended way to do it.

How to get "new" parameter of base class?

I'm deriving a class from a parameterless-constructor class like this:
public class Base
{
public Base(Panel panel1)
{
}
}
public class Derived : Base
{
public Derived() : base(new Panel())
{
//How do I use panel1 here?
}
}
How can I refer to panel1 in Derived?
(Simple workarounds welcome.)
Adil's answer assumes that you can modify Base. If you can't, you can do this:
public class Derived : Base
{
private Panel _panel;
public Derived() : this(new Panel()) {}
private Derived(Panel panel1) : base(panel1)
{
_panel = panel1;
}
}
You need to define Panel in Base, you can use protected instead of public as well. Read more aboud access speicifiers here
public class Base
{
public Panel panel {get; set;};
public Base(Panel panel1)
{
panel = panel1;
}
}
public class Derived : Base
{
public Derived() : base(new Panel())
{
// this.panel
}
}
public class Base
{
// Protected to ensure that only the derived class can access the _panel attribute
protected Panel _panel;
public Base(Panel panel1)
{
_panel = panel1;
}
}
public class Derived : Base
{
public Derived() : base(new Panel())
{
// refer this way: base.panel
}
}
Further if you want to provide only a get and not a set for the derived classes you can do this:
public class Base
{
// Protected to ensure that only the derived class can access the _panel attribute
private Panel _panel;
public Base(Panel panel1)
{
_panel = panel1;
}
protected Panel Panel
{ get { return _panel; } }
}
public class Derived : Base
{
public Derived() : base(new Panel())
{
// refer this way: base.Panel (can only get)
}
}
Two ways:
public class Derived : Base
{
Panel aPanel;
public Derived() : this(new Panel()) {}
public Derived(Panel panel) : base(aPanel)
{
//Use aPanel Here.
}
}
OR
public class Base
{
protected Panel aPanel;
public Base(Panel panel1)
{
aPanel = panel1
}
}

Categories

Resources