I am truly destroyed by this principle that I will now explain. I did use the code for the answer mentioned in this article (Combo box drop down width on suggest).
The code works fine when it comes to inheriting a ComboBox. Exactly as in the following code:
public class ComboBoxEx : ComboBox
{
... //(See the code in the post: https://stackoverflow.com/questions/4820429/combo-box-drop-down-width-on-suggest)
private class ACWindow : NativeWindow
{
....
}
}
Well, as I said above, if I use the ComboBoxEx class in my Forms, this works fine: I can handle the size of the AutoComplete window.
But if I use the ComboBoxEx class in a UserControl and then insert UserControl into my Form, it will no longer work.
From various attempts I understand (perhaps) that the WndProc method of the ACWindow class is not executed for any reason.
Why are not Windows messages forwarded to UserControl's children controls?
In other words, the code I use is almost the following:
// UserCOntrol class declaration
public class MyCmbControl : UserControl
{
ComboBoxEx ExtendedCombo = new ComboBoxEx();
....
}
// Form class declaration
public class MyForm : Form
{
protected ComboBoxEx Cmb1 = new ComboBoxEx(); //-- This work fine!!
protected MyCmbControl Cmb2 = new MyCmbControl(); //-- This will no longer work
}
NOTE:
The UserControl control has the ComboBoxEx control as the only child
I tried to move the ACWindows class at UserControl level
I tried sending a 0x0047 (WM_WINDOWPOSCHANGED) message to the ComboBoxEx member of MyCmbControl
All this without getting good results...
I thank you in advance for the help you will give me and I apologize for the incorrect english I'm using in this post !!!
Related
I have to work on a project on which there are several Form which have 80% of the code the same. So I try to create a generic class to make inheritate all my Forms of the UserControl class (the basic one) and my own class. But .Net doesn't support multi classs inheritance. So I create a middle class to do the inheritance chain like I can see on the net but I think I miss another step. Each class is in a different file for information.
The problem is I can't open anymore the designer for my initial Forms, because "Visual Studio cannot open a designer for the file because the class within it does not inherit from a class that can be visually designed".
Other information, I have a Mainwindow which inherite from "Form" and call one or another UserControl I design to show it.
What I had at the beginning :
namespace i2SIMDCProduction
{
public partial class MyForm1 : UserControl
{
public MyForm1(MyOwnClass myClass)
{
InitializeComponent();
this.myClass = myClass;
}
}
}
namespace i2SIMDCProduction
{
public partial class MyForm2 : UserControl
{
public MyForm2(MyOwnClass myClass)
{
InitializeComponent();
this.myClass = myClass;
}
}
}
What I have now :
namespace i2SIMDCProduction
{
public partial class MyForm1 : MyMiddleClass
{
public MyForm1(MyOwnClass myClass)
{
InitializeComponent();
this.myClass = myClass;
}
}
}
namespace i2SIMDCProduction
{
public partial class MyForm2 : MyMiddleClass
{
public MyForm2(MyOwnClass myClass)
{
InitializeComponent();
this.myClass = myClass;
}
}
}
namespace i2SIMDCProduction
{
public partial class MyMiddleClass : UserControl
{
public void MethodForAllChild()
{
}
}
}
Thank you in advance for any kind of help. I tried different things already (create a third class at the top of the file of my Forms for example, create empty constructor, ...) but nothing which works for now. The more frustrating is it is compiling and working but only the designer is KO.
If you want different forms to share the same visual controls on the screen then you set up inheritance between the forms.
Use the inherited form option in Visual Studio
For example, Form1 has a group box, with a label and two text boxes
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
public void CommonMethod()
{
}
}
and Form2 inherits from From1 and adds a list box
public partial class Form2 : Form1
{
public Form2()
{
InitializeComponent();
}
public void SpecificMethod()
{
base.CommonMethod();
}
}
As you can see the controls from Form1 show up on Form2 also with a little icon to indicate that they are inherited.
If instead you just need to share code (like business logic) and not visual controls, then you create a separate class to hold the code with a link to the parent form, and then each form should contain an instance of this class.
What you want to do is a Model-View-Controler setup, where the Model is only data-related classes, View is only UI code, and the controller goes between the two doing the heavy lifting with processing user inputs and updating values.
The inheritance and designer in Windows Forms is a problem.
I have a Form with an splitter, two listboxes and some other controls. That form is used to translate (map) some items. You select one item at left, one at right and click button to match. They are the same item in different providers.
I have another provider that require some extra controls to do the translation. May be 90% or more of the code is the same, but I need some extra for this provider.
The options that I saw:
Add these extra controls (protected or public) to the Form, hidden by default and without use. In Form derived class, you use them. You haven't the designer in derived Form, but you don't need because controls are in base Form. The problem with this approach is that the designer part of inheritance of derived Form is in base Form. It's a nonsense. I don't recomend this option.
Don't use the designer in derived Form. Starting in the previous point, copy the designer code added for your derived Form into your derived Form and leave your base Form as at first stage, without nothing of derived Form. You don't use the designer but you can use it temporary, copy/paste and have a good inheritance... without the designer in derived Form. It's a good option if your derived Forms has few changes, few maintenance in the designer part.
You can "Add" some logic to your base Form to allow extensions. For example, below of the ListBox, I can add a Panel (hidden by default) and some methods like ShowLeftPanel/ShowRightPanel. By default, these panels aren't used, but in derived class I can add an UserControl in left panel and show it. And that UserControl show the properties that I need to show in the special provider. Add some virtual methods for listbox selection changed, to update the UserControl. In this way, your UserControl has designer and also the base Form. You only need add some "extension points" in your form (a Panel, a Splitter...) and give some methods to interact with this parts of the base Form. And this is ok with inheritance because is something generic, like Tag property in controls.
UPDATE
Check this solution and tell me about it. Make your Forms like this:
public partial class MyForm1 : UserControl, IMyUserControl
{
private readonly MyOwnClass myClass;
public MyForm1(MyOwnClass myClass, MyMiddleClass myMiddle)
{
InitializeComponent();
this.myClass = myClass;
this.MyMiddle = myMiddle;
}
public MyMiddleClass MyMiddle { get; }
}
In this way, all your panel's forms are IMyUserControl:
public class MyUserControl : IMyUserControl
{
public MyMiddleClass MyMiddle { get; }
}
So, having any of your panel's form, you can cast to IMyUserControl and get the related MyMiddleClass having access to methods like MethodForAllChild:
public class MyMiddleClass
{
public void MethodForAllChild()
{
}
}
In your main form, you may have some property or method that give you access to your UserControl. Create a method that give you the middle instance of the current UserControl:
private MyMiddleClass GetMyMiddle()
{
UserControl userControl = GetYourMainFormCurrentUserControl();
IMyUserControl myUserControl = userControl as IMyUserControl;
return myUserControl?.MyMiddle;
}
And use it in your main form when you need:
MyMiddleClass myMiddle = GetMyMiddle();
if (myMiddle != null)
{
myMiddle.MethodForAllChild();
}
In this way, you only need implement the interface and add a property in your forms/usercontrols. In the main form you can get this middleclass and the code to reuse is only in that class and shared in all places. You don't need copy/paste if you add or change something in the middle class.
UPDATE 2
I'm going to explain in other form how it works because the code is written above. The goal is having the code only in one place, without duplicate it.
You define an interface in a very similar way as a class but without implementation (this is not really true in lastest C# versions but we can suppose that is without code). C# don't allow multiple inheritance but you can derive from a class and implement as many interfaces as you want.
When we define IMyUserControl we are telling that every class that implements IMyUserControl, has a property MyMiddle. When MyForm1 implements IMyUserControl, if you don't add the MyMiddle property, you get a compiler error. The key with this solution is that add and implement this interface in each form is very easy: add IMyUserControl, the property and a parameter in the constructor to set the property.
So, all your forms implements now IMyUserControl. I don't know where are your forms but it's sure that you have a way to get access to your UserControl. Maybe a variable or an array in which you add your user controls. You are working with them, so you can access to your user controls. Well, if you have an UserControl instance, and you know that your UserControl implements IMyUserControl, you can cast your UserControl to IMyUserControl and after the cast, you have access to the interface, in this case, to the MyMiddle property.
And we put in MyMiddle all the code that you want to share.
If you add some code of your main form, where you work with your forms, I can help you with the code. I haven't more code than existing in my answer.
I have a project that has forms that inherit properties from a base form (called frmBase). I have run into an issue that is really confusing me:
I want the program to center on the user screen, so I added
this.CenterToScreen();
to frmBase_Load(). That works great when I run the app, BUT, when I try to design any of the forms that inherit from frmBase, they all get moved to the very bottom right corner of the designer screen and I have to use scrollbars to see them.
If I move the
this.CenterToScreen();
to the frmBase() code, the app defaults to the top-left of the screen when it runs, but the designer displays the form correctly for me. Any idea what is going on? I searched, but can't seem to find a similar question, although I know I can't be the first person this has happened to. . . . .
As indicated by Hans and Reza your base class is being instantiated by the Visual Studio Form Designer so the code in the constructor and its Load event run as well. See this great answer for a detailed explanation of the parse behavior of the designer. Using the property DesignMode you can either prevent code being executed or make a distinction. The following code sample demonstrates its use:
Base form
The baseform sets the background color to Red when in DesignMode and Green when not in DesignMode.
// Form1 inherits from this class
public class MyBase : Form
{
public MyBase()
{
// hookup load event
this.Load += (s, e) =>
{
// check in which state we are
if (this.DesignMode)
{
this.BackColor = Color.Red;
}
else
{
this.BackColor = Color.Green;
}
};
}
}
Form1 that inherits the base form
No magic in the code, but notice the use of MyBase instead of Form
// we inherit from MyBase!
public partial class Form1 : MyBase
{
public Form1()
{
InitializeComponent();
}
}
Leading to the following result:
I just started fiddling around with C# and WPF.
Let's say that I want to instantiate a Black grid and that I want to randomly move around a red square in said Grid.
Currently I can basically do whatever I want as long as I keep everything in "MainWindow.xaml.cs"...
Now, my problem is that if I create a new class (e.g., "MakeStuffHappen.cs") and from it I try to access the Grid (named "MyGrid") that will be instantiated by MainWindow's constructor, intellisense doesn't "see" it.
I tried making a getter that returns "MyGrid" but then the compiler says that "an object reference is required for the non-static field, method, or property 'ProjectName.MainWindow.getGrid()'.
Obviously I cannot define MainWindow as a static class...
Any tips on how to solve this?
Thanks!
P.S. Since I'm evidently no programmer I'm not necessarily aware of the technical terms to use when looking up information... so I apologize in advance if this question has been already asked.
P.P.S. I saw this: Access MainWIndow Control from a class in a separate file but it doesn't help.
Once your view is initialized (when the OnInitialized event fires) you can pass the initialized Grid into your helper class:
MainWindow.xaml.cs:
public partial class MainWindow
{
MakeStuffHappen helper = null;
public MainWindow()
{
OnInitialized += (s,e)=> { helper = new MakeStuffHappen(this.MyGridName); }
}
}
MakeStuffHappen.cs
public class MakeStuffHappen
{
Grid theGrid = null;
public MakeStuffHappen(Grid grid)
{
theGrid = grid;
// Do stuff with the grid.
}
}
I was wondering if it is possible to have a user control open a winform that allows a user to select options on it and then when he closes the form - the options / values he selected are returned to the user control?
Why not create some public properies on your dialog form, and access them from the UserControl once the dialog has been closed?
public class OptionsForm : Form
{
// ...
public string Option1 { get; set; }
public bool Option2 { get; set; }
}
And then, within the UserControl:
public void ShowOptionsForm()
{
using (var form = new OptionsForm())
{
if (form.ShowDialog() == DialogResult.OK)
{
var option1Value = form.Option1;
var option2Value = form.Option2;
// use option values...
}
}
}
Please consider this answer as an "extended comment" on Steve Greatrex's now-accepted answer : it's too long for a comment, and I want to demonstrate a few options, add a few "flavours" to the taste. This is not at all a "criticism" of Steve's answer which, imho, hit the "bullseye."
Assumptions : if I had read the question earlier, I would have queried the OP via a comment on each of these points :
the OP did not specify whether the Form to be "shown" was to be shown modally or not.
the OP did not specify whether the Form was to be re-created each time it was shown, or whether one instance of it should be created and re-used.
the OP wrote "open a winform that allows a user to select options on it ... snip ... "options / values he selected are returned" : Steve's code does not show exactly how the Properties exposed as Public are set, but I'm going to assume that the OP probably intended to mean that the user interacted with some Controls on the shown Form, and that the "options / values" he refers to are Properties of Controls on the Form : like the end-user typing some text in a TextBox, or the selected indexes in a ListBox with its SelectionMode set to allow one of two choices of multiple selection.
the OP does not say if it's desireable that the Form (if used repeatedly) retain the results of the last interactions of the end-user with the Controls on the Form as described above.
the OP says nothing about whether the Form shown by the UserControl has its Parent property set to some other valid container : I'll assume they meant the Form to be displayed "parent-less."
Comments :
if the OP intended the Form to be shown modally : in order for Steve's code to work, the 'ControlBox of the Form would have to eliminated as an option, and a Button put on the Form whose 'DialogResult property was set to "OK," and whose 'Click Event closed the Form : without those conditiions being met the result of ShowDialog in Steve's code would never return "OK," and the properties' values would never be set. Note : closing a Form via the 'ControlBox will return a DialogResult of "Cancel."
re-use of the shown Form : if we assume the Form will probably be re-used, then why not create it once and 'Show and 'Close as necessary ? Let's consider the possibility that there may be good reasons to expose the created Form as a Public member of the UserControl.
Consider the following alternative idea : trying to present a solution as "different" as possible from Steve's : just to demonstrate, explore, the options.
Our "shown Form" will have a TextBox and a ListBox that allows multiple selections : our goal is to expose the Text in the TextBox and the current selection of Indices in the ListBox.
Form has a ControlBox : does not require a Button to close as described above.
it doesn't matter if the Form is shown modally or not : will set properties the same way in either case.
the Public properties to be set are to be based on reading the current state of Controls on the shown Form.
the Form is created once and exposed as Public : because of this a "side-effect" is that when the Form is re-displayed it will retain the previous results of what the user selected, etc. Of course there are other ways you could easily control that in your code to make one or all of the Controls "virgin" again.
in The "shown Form" which we have named 'DataEntryForm :
Just as Steve shows we define public properties to expose ;
public string TextEntered { get; set; }
public ListBox.SelectedIndexCollection LBSelection { get; set; }
In the Form Closing Event we update the properties based on the state of the Controls :
private void DataEntryForm_FormClosing(object sender, FormClosingEventArgs e)
{
TextEntered = textBox1.Text;
LBSelection = listBox1.SelectedIndices;
}
in the UserControl we create a public property of type 'DataEntryform (reason why to be explained)
public DataEntryForm theDataEntryForm { get; set; }
We create an instance of the DataEntryForm in the Load Event of the UserControl and assign it to the public Property
private void UserControl1_Load(object sender, EventArgs e)
{
theDataEntryForm = new DataEntryForm();
}
At this point we will leave it to the OP's (and your) imagination to picture when the instance of the DataEntryForm is shown. But of course we want to demonstrate how you would access the properties after the Form has been closed : so we put a Button on the UserControl :
private void button2_Click(object sender, EventArgs e)
{
Console.WriteLine(theDataEntryForm.TextEntered);
Console.WriteLine(theDataEntryForm.LBSelection.ToString());
}
Note : we didn't do any "fancy" analysis of the ListBox selected indices : but we could have written out whether it was null, or how many items had been selected, etc.
Also : we didn't deal with the issue of what if the OP wants to take some action the moment the "shown Form" is closed : that's so simple : you just subscribe to the FormClosed event of the Form in the UserControl, and do what you need to do in your Event Handler code.
Finally we come to the question of why make a Public Property of type 'DataEntryForm :
Well, just consider that by exposing that "shown Form" via a Public Property in the UserControl : we allow the potential containers (probably a Form) of the UserControl instances to also have access to the values of the Controls on the "shown Form" ... which may be valuable, may save us some duplication of properties.
So, if UserControl1 is on Form1, and Form1 wants to know the Text value of the TextBox on the "shown Form" : it could be accessed like so :
this.userControl11.theDataEntryForm.TextEntered
Edit : A friend of mine wrote me to express his opinion that allowing a "higher-level" container to directly access a "component" embedded in a UserControl was a "violation" of good OOD practicem and breaks encapsulation : he issued me a moving violation ticket :) So, keep his warning in mind. From his point of view the properies should be duplicated in the UserControl with different names, and only those UserControls properties made available to the UserControl Container. My bias is to see the "UserContro/Form" as one "compound object" here, which, since the Form is exclusively used by the UserForm, justifies not duplicating the Properties /Edit
Of course we've left out checking for possibly null values of everything-under-the-sun as we all do so religiously.
here's a short example on how you could do it. It's not complete you'll have to fill in some of the blanks but it should give you an idea of how to solve your problem.
this code goes where you construct your control and you form
MyUserControl ctrl = new MyUserControl();
Action<typeYouPassBack> callBack = myUserControl.FormCallBack;
MyOptionForm form = new MyOptionForm(callBack);
the form class would then have to look something like this: (important part is the action argument)
class MyOptionForm : Form
{
private readonly Action<typeYouPassBack> _callBack;
public MyOptionForm(Action<typeYouPassBack> callBack)
{
_callBack = callBack;
Close += form_Close;
}
privatre void form_close(object sender, EventARgs e)
{
typeYouPassBack postBackData = //populate the postback data
_callBack(postBackData);
}
}
the type Action is simply a delegate with the signature void f(T arg). In the above code it's expected for the user control to have amethod called 'FormCallBack' which of course can be named anything you like as long as you use the correct name when assigning it to the 'callback' variable
I have a question about extending a custom control which inherits from UserControl.
public partial class Item : UserControl
{
public Item ()
{
InitializeComponent();
}
}
and I would like to make a control which inherits from Item
sg like that
public partial class ItemExtended : Item
{
public ItemExtended():base()
{
InitializeComponent();
}
}
This works perfectly of course and the heritage works but my problem is in the designer
I just cannot open this ItemExtended in Design....
it says : Constructor on Type "Item" not found.
Does sy have an explanation?
is the best way to do it?
Thx
I'm of course using c# on .NET Winform :)
you invoke InitializeComponent() twice with calling InitializeComponent() on the very derived usercontrol.
This may lead to problem.
And there is some help property callad IsDesign or Design (something similar) of UC, which helps to avoid unnecessary UI operations on design time (in VS).
Edit: it is DesignMode. You can avoid to run RT functions by Design. Like if (!this.DesignMode) InitializeComponents();
You can also check this forumpost. http://www.c-sharpcorner.com/Forums/ShowMessages.aspx?ThreadID=41254