CRTP in c#/.NET?
-
I found different solutions to this sort of CRTP problem previously... but can't think of a way around it this time. The main form used by my current project allows for moving and resizing even when it doesn't have a border. I have seen other people ask about this particular need before (it seems like a fairly common need for custom forms) and I have developed a better solution than what I have seen for answers online. I would like to provide a more generic solution than the one I am using currently for myself and others if possible so hence... my asking this prerequisite question beforehand. I am needing to create several "controls" in my current project that have this same exact behavior so I want to write an inheritable class for all of them. Simple enough... just write a template that derives from Control. The problem is that none of the derived classes will look and perform like their actual base class in every other way without some way to use a CRTP. It would be nice not to have to write separate base classes for all the seperate possible control types, including forms. Is there a way to write a generic class to cover all controls that one would want to use? Something that effectively does what this would do if this were c++? (I realize that the where statement is c# but there are ways to accomplish the same basic idea in c++).
public class MovableControl : InheritedControl where InheritedControl : Control
{
//...
}In c# the above class definition doesn't compile because in .NET inheriting from a template parameter is not allowed (which is why I need an alternative solution.). Of course I will continue hunting on my own, or worst case, brute force it (by creating the separate classes) but I thought I would ask here in case someone already had an idea.
-
I found different solutions to this sort of CRTP problem previously... but can't think of a way around it this time. The main form used by my current project allows for moving and resizing even when it doesn't have a border. I have seen other people ask about this particular need before (it seems like a fairly common need for custom forms) and I have developed a better solution than what I have seen for answers online. I would like to provide a more generic solution than the one I am using currently for myself and others if possible so hence... my asking this prerequisite question beforehand. I am needing to create several "controls" in my current project that have this same exact behavior so I want to write an inheritable class for all of them. Simple enough... just write a template that derives from Control. The problem is that none of the derived classes will look and perform like their actual base class in every other way without some way to use a CRTP. It would be nice not to have to write separate base classes for all the seperate possible control types, including forms. Is there a way to write a generic class to cover all controls that one would want to use? Something that effectively does what this would do if this were c++? (I realize that the where statement is c# but there are ways to accomplish the same basic idea in c++).
public class MovableControl : InheritedControl where InheritedControl : Control
{
//...
}In c# the above class definition doesn't compile because in .NET inheriting from a template parameter is not allowed (which is why I need an alternative solution.). Of course I will continue hunting on my own, or worst case, brute force it (by creating the separate classes) but I thought I would ask here in case someone already had an idea.
I will be posting this as a Tip/Trick or Article here in the future with comments and explanations, but, I'm in a rush right now, and don't have time to revise/comment my extended version of this, but, this should give you some ideas. In a Form Load eventhandler, make some Controls movable like this: button1.SetMovable(); textBox1.SetMovable(); panel1.SetMovable(); The code:
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;namespace YOURNAMESPACE
{
public static class ControlMovableExtensions
{
private static Control currentControl = null;private static Control currentContainer= null; private static List MovableControls = new List(); private static Rectangle ClippingRect; private static Rectangle ContainerRect; private static Point lastGoodLocation; private static Point nextLocation; private static int mdx, mdy; private static bool IsMouseUp = true; // experiment with these settings private static bool UseClipping = false; private static bool UseCapture = false; public static void SetMovable(this Control control) { if (MovableControls.Contains(control)) { throw new ArgumentException("control already movable"); } MovableControls.Add(control); control.MouseDown += ControlOnMouseDown; control.MouseUp += ControlOnMouseUp; } public static void RemoveMovable(this Control control) { if (! MovableControls.Contains(control)) { throw new ArgumentException("control is not movable"); } control.MouseDown -= ControlOnMouseDown; control.MouseUp -= ControlOnMouseUp; } private static void ControlOnMouseMove(object sender, MouseEventArgs e) { if (IsMouseUp) return; nextLocation = new Point(currentControl.Left + e.X - mdx, currentControl.Top + e.Y - mdy); if (ContainerRect.Contains(new Rectangle(nextLocation, currentControl.Size))) { lastGoodLocation = nextLocation; } currentControl.Location = lastGoodLocation; } private static void ControlOnMouseUp(object sender, MouseEventArgs e) {
-
I will be posting this as a Tip/Trick or Article here in the future with comments and explanations, but, I'm in a rush right now, and don't have time to revise/comment my extended version of this, but, this should give you some ideas. In a Form Load eventhandler, make some Controls movable like this: button1.SetMovable(); textBox1.SetMovable(); panel1.SetMovable(); The code:
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;namespace YOURNAMESPACE
{
public static class ControlMovableExtensions
{
private static Control currentControl = null;private static Control currentContainer= null; private static List MovableControls = new List(); private static Rectangle ClippingRect; private static Rectangle ContainerRect; private static Point lastGoodLocation; private static Point nextLocation; private static int mdx, mdy; private static bool IsMouseUp = true; // experiment with these settings private static bool UseClipping = false; private static bool UseCapture = false; public static void SetMovable(this Control control) { if (MovableControls.Contains(control)) { throw new ArgumentException("control already movable"); } MovableControls.Add(control); control.MouseDown += ControlOnMouseDown; control.MouseUp += ControlOnMouseUp; } public static void RemoveMovable(this Control control) { if (! MovableControls.Contains(control)) { throw new ArgumentException("control is not movable"); } control.MouseDown -= ControlOnMouseDown; control.MouseUp -= ControlOnMouseUp; } private static void ControlOnMouseMove(object sender, MouseEventArgs e) { if (IsMouseUp) return; nextLocation = new Point(currentControl.Left + e.X - mdx, currentControl.Top + e.Y - mdy); if (ContainerRect.Contains(new Rectangle(nextLocation, currentControl.Size))) { lastGoodLocation = nextLocation; } currentControl.Location = lastGoodLocation; } private static void ControlOnMouseUp(object sender, MouseEventArgs e) {
Interesting approach using extensions. That may work. The one problem is overriding the WndProc as that is the best way to detect resizing attempts. I supposed the override can call a static method... but that is a bit strange unless we can successfully use aggressive inlining. Perhaps we can combine our ideas and write the article together since my approach is very efficient and almost works just like an ordinary window. (There is a bit of a flicker when resizing upward and left but it still works well).
-
Interesting approach using extensions. That may work. The one problem is overriding the WndProc as that is the best way to detect resizing attempts. I supposed the override can call a static method... but that is a bit strange unless we can successfully use aggressive inlining. Perhaps we can combine our ideas and write the article together since my approach is very efficient and almost works just like an ordinary window. (There is a bit of a flicker when resizing upward and left but it still works well).
Hi, Yes, it does work :) I am not sure why you are bringing in WndProc here, for me, use of WndProc is a last resort, and that's even more so now that .NET Core is evolving rapidly. I use different techniques to handle the rare case when a user needs to arbitrarily re-size a Control at run-time. I look forward to reading your article. cheers, Bill
«Where is the Life we have lost in living? Where is the wisdom we have lost in knowledge? Where is the knowledge we have lost in information?» T. S. Elliot
-
I found different solutions to this sort of CRTP problem previously... but can't think of a way around it this time. The main form used by my current project allows for moving and resizing even when it doesn't have a border. I have seen other people ask about this particular need before (it seems like a fairly common need for custom forms) and I have developed a better solution than what I have seen for answers online. I would like to provide a more generic solution than the one I am using currently for myself and others if possible so hence... my asking this prerequisite question beforehand. I am needing to create several "controls" in my current project that have this same exact behavior so I want to write an inheritable class for all of them. Simple enough... just write a template that derives from Control. The problem is that none of the derived classes will look and perform like their actual base class in every other way without some way to use a CRTP. It would be nice not to have to write separate base classes for all the seperate possible control types, including forms. Is there a way to write a generic class to cover all controls that one would want to use? Something that effectively does what this would do if this were c++? (I realize that the where statement is c# but there are ways to accomplish the same basic idea in c++).
public class MovableControl : InheritedControl where InheritedControl : Control
{
//...
}In c# the above class definition doesn't compile because in .NET inheriting from a template parameter is not allowed (which is why I need an alternative solution.). Of course I will continue hunting on my own, or worst case, brute force it (by creating the separate classes) but I thought I would ask here in case someone already had an idea.
-
Use a proxy. Move / resize the proxy; when done, copy the properties to the original target.
"(I) am amazed to see myself here rather than there ... now rather than then". ― Blaise Pascal
That's an interesting approach, one that seems like what goes on with drag-drop. In what kind of scenario would you use this rather than just move the Control ? thanks, Bill
«Where is the Life we have lost in living? Where is the wisdom we have lost in knowledge? Where is the knowledge we have lost in information?» T. S. Elliot
-
Use a proxy. Move / resize the proxy; when done, copy the properties to the original target.
"(I) am amazed to see myself here rather than there ... now rather than then". ― Blaise Pascal
I actually am using a proxy system. However, the main window also uses the same (similar in the case of move) system since it is a border-less form. That is why I posted this topic to begin with. I want to write one set of code for both forms and controls.