Inference of second generic argument - c#

I have the class structure like below:
public interface IBinder<T>
where T : Control
{
T Control { get; }
}
public class ButtonBinder : IBinder<Button>
{
public ButtonBinder(Button control)
{
Control = control ?? throw new ArgumentNullException(nameof(control));
}
public Button Control { get; private set; }
}
Create instances of that Binder I want with help of a factory method like this:
public void Main()
{
// This line works.
var binder = RegisterBinder<ButtonBinder, Button>(new Button());
// But I want use type inference like this:
var binder2 = RegisterBinder<ButtonBinder>(new Button());
}
/// <summary>
/// My pseudo-factory.
/// </summary>
public T_Binder RegisterBinder<T_Binder, T_Control>(T_Control control)
where T_Binder : IBinder<T_Control>
where T_Control : Control
{
return (T_Binder)Activator.CreateInstance(typeof(T_Binder), control);
}
Because the class 'ButtonBinder' declares the generic control type 'Button' the Compiler should be able to infer it.
How I can tell the compiler that I want to use type inference?
Thank you.

Unfortunately C# cannot infer only one of multiple generic parameters.
However, if you do not mind capturing the inferable type in an intermediate class you can do something like this:
public class Factory
{
public void Main()
{
// This line works.
var binder = RegisterBinder<ButtonBinder, Button>(new Button());
// Now only T_Binder is needed
var binder2 = ForControl(new Button()).RegisterBinder<ButtonBinder>();
}
private BinderRegistration<T_Control> ForControl<T_Control>(T_Control control) where T_Control : Control
{
return new BinderRegistration<T_Control>(control);
}
/// <summary>
/// My pseudo-factory.
/// </summary>
public T_Binder RegisterBinder<T_Binder, T_Control>(T_Control control)
where T_Binder : IBinder<T_Control>
where T_Control : Control
{
return (T_Binder)Activator.CreateInstance(typeof(T_Binder), control);
}
}
internal class BinderRegistration<T_Control>
where T_Control : Control
{
private readonly Control _control;
public BinderRegistration(Control control)
{
_control = control;
}
public T_Binder RegisterBinder<T_Binder>()
where T_Binder : IBinder<T_Control>
{
return (T_Binder)Activator.CreateInstance(typeof(T_Binder), _control);
}
}

Related

How can I get the ToolTip on the Form that contains a control?

I have a class, Validator, which validates fields in all the Forms of a project.
I want to refer (from the function) the ToolTip on the form that contains the control which is being validated. This control is the function argument.
public static Boolean ValidateText(object sender)
{
//Error CS0039
ToolTip ttHelp = (sender as TextBox).FindForm().Controls["myToolTip"] as ToolTip;
if((sender as TextBox).Text == "") {
ttHelp.SetToolTIp(someControl,someMessage);
}
// [...]
}
Error CS0039 Cannot convert type 'System.Windows.Forms.Control' to 'System.Windows.Forms.ToolTip' via a reference conversion, boxing conversion, unboxing conversion, wrapping conversion, or null type conversion
A ToolTip is not a Control, it's a Component, so you won't find it in a Form's Controls collection.
It's instead part of the System.ComponentModel.IContainer components private Field, usually defined in the Form's Designer section of the partial class.
To find the ToolTip of a control, you can use the ToolTip.GetToolTip([Control]) method, then verify whether the string returned is empty.
If you can access the Form's components Field - i.e., the ValidateText() method is called from the Form that contains the Control to validate - you can pass the components container to the method:
► If the Form has no Components, container (in both methods) will be null.
► If the Form has no ToolTip components, var toolTip will be null.
→ Keeping object sender, then casting to Control, since here you want to access only common Properties, like Text, which belong to the common Control class. You don't need to know sender's type: Control is the base type of all controls and exposes all the common properties.
bool result = ValidateText(this.someControl, this.components);
// [...]
public static bool ValidateText(object sender, IContainer container)
{
if (container == null) {
/* no components, decide what to do */
// [...]
}
var ctrl = sender as Control;
var toolTip = container.Components.OfType<ToolTip>()
.FirstOrDefault(tt => !string.IsNullOrEmpty(tt.GetToolTip(ctrl)));
if (toolTip != null) {
string tooltipText = toolTip.GetToolTip(ctrl);
// [...]
if (ctrl.Text == "") { }
return true;
}
return false;
}
Otherwise, you can access the components collection via reflection, in case the Control instance passed to the ValidateText() method may have an undetermined origin.
With [form].GetType().GetField("components").GetValue([form]) as IContainer we can access the components Field value then continue as before.
→ Here, sender is of type Control already, since this is the real nature of sender.
→ ValidateText([Control]) overloads the previous method. You can call ValidateText(sender, container) when you have assigned a value to container.
bool result = ValidateText(someControl);
// [...]
using System.Reflection;
public static bool ValidateText(Control sender)
{
var flags = BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.GetField;
Form form = sender.FindForm();
var container = form.GetType().GetField("components", flags).GetValue(form) as IContainer;
if (container == null) {
/* no components, decide what to do */
// [...]
}
// You can call ValidateText(sender, container) or continue
var toolTip = container.Components.OfType<ToolTip>()
.FirstOrDefault(tt => !string.IsNullOrEmpty(tt.GetToolTip(sender)));
if (toolTip != null) {
string tooltipText = toolTip.GetToolTip(sender);
// [...]
return true;
}
return false;
}
Please read Jimi's answer to understand why your code doesn't work.
Plus your Validator class can be refactored as follows to validate the TextBox controls in different ways. A single control, group of controls hosted by a Form or other container, and the controls of the OpenForms.
Also The ErrorProvider component is recommended for tasks as such. The Validator class provides both, the ToolTip and ErrorProvider services. Note that, the base class of the target controls is the TextBoxBase class, so you can validate any control derives from this base class such as; TextBox, RichTextBox, ToolStripTextBox...etc.
Please read the explanatory comments of each member.
internal sealed class Validator
{
private static Validator Current;
//Each Form has its own ToolTip...
private readonly Dictionary<Form, ToolTip> ToolTips;
private readonly ErrorProvider ErrPro;
private Validator()
{
ToolTips = new Dictionary<Form, ToolTip>();
ErrPro = new ErrorProvider();
}
static Validator() => Current = new Validator();
/// <summary>
/// Enable/disable the ToolTip service.
/// </summary>
public static bool ToolTipEnabled { get; set; } = true;
/// <summary>
/// Enable/disable the ErrorProvider service.
/// </summary>
public static bool ErrorProviderEnabled { get; set; } = false;
/// <summary>
/// Set/get the ToolTip/ErrorProvider message.
/// </summary>
public static string Message { get; set; } = "Hello World";
/// <summary>
/// Validate a single TextBox or RichTextBox control.
/// </summary>
/// <param name="txt">TextBox/RichTextBox..etc.</param>
public static void Validate(TextBoxBase txt)
{
if (txt is null) return;
var f = txt.FindForm();
if (f is null) return;
//Add a Form into the Dictionary and create a new ToolTip for it.
if (!Current.ToolTips.ContainsKey(f))
{
Current.ToolTips.Add(f, new ToolTip());
Current.ToolTips[f].ShowAlways = true; //Optional...
//Cleanup. Remove the closed Forms and dispose the related disposables.
f.HandleDestroyed += (s, e) =>
{
Current.ToolTips[f].Dispose();
Current.ToolTips.Remove(f);
if (Current.ToolTips.Count() == 0) Current.ErrPro.Dispose();
};
}
if (txt.Text.Trim().Length == 0)
{
if (ToolTipEnabled)
Current.ToolTips[f].SetToolTip(txt, Message);
if (ErroProviderEnabled)
Current.ErrPro.SetError(txt, Message);
}
else
{
Current.ToolTips[f].SetToolTip(txt, null);
Current.ErrPro.SetError(txt, null);
}
}
/// <summary>
/// An overload that takes a container.
/// </summary>
/// <param name="container">Form/Panel/GroupBox...etc</param>
public static void Validate(Control container)
{
if (container is null) return;
foreach (var c in GetAllControls<TextBoxBase>(container))
Validate(c);
}
/// <summary>
/// Validates the open Forms.
/// </summary>
public static void ValidateOpenForms()
{
foreach (var f in Application.OpenForms.Cast<Form>())
Validate(f);
}
/// <summary>
/// Clear and remove the messages explicitly.
/// </summary>
public static void Clear()
{
Current.ToolTips.Values.ToList().ForEach(x => x.RemoveAll());
Current.ErrPro.Clear();
}
/// <summary>
/// A recursive function to get the controls from a given container.
/// </summary>
private static IEnumerable<T> GetAllControls<T>(Control container)
{
var controls = container.Controls.Cast<Control>();
return controls.SelectMany(ctrl => GetAllControls<T>(ctrl)).Concat(controls.OfType<T>());
}
}
Now you can use it as follows:
void TheCaller()
{
//Set the desired properties.
Validator.Message = "Hello World!";
Validator.ErrorProviderEnabled = true;
//Validate a single control.
Validator.Validate(textBox1);
//Or the controls of the current Form.
Validator.Validate(this);
//Or all the open Forms.
Validator.ValidateOpenForms();
}

How to maintain object in multiple instances - C#

I am maintaining one object(Parent) in my MainWindow class. That Parent Object is being passed to another object(objMyClass). Now If I update Parent Object in mainwindow, it is not reflecting it in objMyClass object. Below is the code.
using System.Windows;
namespace WpfApp2
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public Parent objParent;
public MyClass objMyClass;
public MainWindow()
{
InitializeComponent();
objParent = new Parent();
objMyClass = new MyClass(objParent);
}
private void Button_Click(object sender, RoutedEventArgs e)
{
if ((bool)checkPWB.IsChecked)
objParent = new Child1();
else
objParent = new Child2();
objParent.Display();
objMyClass.par.Display();
}
}
public class MyClass
{
public Parent par;
public MyClass(Parent p)
{
par = p;
}
}
public class Parent
{
public virtual void Display()
{
MessageBox.Show("I am Parent");
}
}
public class Child1 : Parent
{
public override void Display()
{
MessageBox.Show("I am Child1");
}
}
public class Child2 : Parent
{
public override void Display()
{
MessageBox.Show("I am Child2");
}
}
}
When I click the button, I am creating a new object (Child1) and assigning to my parent object which doesn't reflect it in ObjectMyClass.
Any help on this is appreciated.
To refer to the same field you can use Func<Parent> that would return current value of the filed:
public class MyClass
{
private Func<Parent> getParent = null;
public Parent par => getParent();
public MyClass(Func<Parent> getParent)
{
this.getParent = getParent;
}
}
and construct your class as
objMyClass = new MyClass(() => objParent);
This way instead of having its own reference to Parent object that contains copy of the original value of the parameter (as in code in the question) this MyClass will always return current value of objParent field and indeed reflect changes to that field.
Alternatively you can just change par property directly instead of changing objParent.

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

Using Unity I wish to check a bool flag before setting value to the properties in a Type?

I wish to implement suspend and resume binding in silverlight using a flag while doing heavy operation in a binding scenario.
My problem is in the existing project uses heavy binding drawing mechanismm.
Using UpdateTrigger() in silverlight we could achieve manual triggering of binding.
But its a huge product. Its not possible to update and find the locations for manual triggering of binding and so on and change the project.
So we planned to use Microsoft Unity to quickly fix by suspend and resume binding using a flag on heavy load drawing operation. This may be quick fix for the current performance issue while drawing binding objects.
I wish to check a bool flag before setting value to the properties for different Type?
I googled so much and tired to find Interception before property setter. But not found a way. Still fighting. This is my exact requirement.
Anybody to help?
Added the sample code trying,
//Empty Interface may be used in interface interception, not sure.
public interface ISetter
{
}
//Implementation of ISetter, this type needs to be intercepted while setting the FirstName //property
public class Man : ISetter
{
private string firstName;
public Man()
{
}
[NotifyHandler] //Expected: this handler should be called when FirstName property set
public string FirstName
{
get { return firstName; }
set { firstName = value; }
}
}
public class NotifyHandler : ICallHandler
{
public Boolean Before { get; set; }
public Boolean After { get; set; }
public String Message { get; set; }
int ICallHandler.Order { get; set; }
IMethodReturn ICallHandler.Invoke(IMethodInvocation input,
GetNextHandlerDelegate getNext)
{
if (this.Before == true)
{
Debug.WriteLine(this.Message);
}
IMethodReturn result = getNext()(input, getNext);
if (result.Exception != null)
{
Debug.WriteLine(result.Exception.Message);
}
else
{
if (this.After == true)
{
Debug.WriteLine(this.Message);
}
}
return (result);
}
}
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property
| AttributeTargets.Method)]
Public class NotifyHandlerAttribute : HandlerAttribute
{
public NotifyHandlerAttribute()
{
}
public override ICallHandler CreateHandler(IUnityContainer ignored)
{
return new NotifyHandler();
}
}
public abstract class HandlerAttribute : Attribute
{
/// Derived classes implement this method. When called, it creates a
/// new call handler as specified in the attribute configuration.
/// The parameter "container" specifies the IUnityContainer
/// to use when creating handlers, if necessary.
/// returns a new call handler object.
public abstract ICallHandler CreateHandler(IUnityContainer container);
private int executionorder;
/// <summary>
/// Gets or sets the order in which the handler will be executed.
/// </summary>
public int Order
{
get { return this.executionorder; }
set { this.executionorder = value; }
}
}
//Interception registered in the application start up
private void Application_Startup(object sender, StartupEventArgs e)
{
IUnityContainer container = new UnityContainer();
container.AddNewExtension<Interception>();
container.RegisterType<Man>().Configure<Interception>();
var m1 =container.Resolve<Man>();
m1.FirstName = "test";
Man m = new Man();
m.FirstName = "fine";
}
In above both the FirstName setter property does not call the NotifyHandler.

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

Categories

Resources