Polymorphism in WPF - c#

Here's my wish to create something abstract in WPF. You've got a main window (called main for example, even if it's not correct we don't care) with two buttons. Those two buttons have the same function : they open a new window, the same for both of them, but with different things inside. So I decided to create an abstract class to rule them like that :
public abstract (partial ?) class A : Window
{
public A()
{
InitializeComponent(); // Not sure about that, it's kinda weird to use it here no ?
}
...
}
public partial class B : A
{
public B()
{
InitializeComponent(); // Since it's already in A I shouldn't have to use it here right ?
}
...
}
public partial class C : A
{
public C()
{
InitializeComponent(); // Same thing here...
}
...
}
Debugging gives me something like : "error CS0263: Partial declarations of 'namespace.B' must not specify different base classes".
Removing 'partial' from A class gives : "error CS0260: Missing partial modifier on declaration of type 'namespace.A'; another partial declaration of this type exists".
I know that 'partial' specifies if a class has another part of her somewhere else (like the xaml file beside the cs one), so I guess the abstract class has to be partial too since it contains my controls. Maybe the B class shouldn't be partial ?
I know (memories) it works with Windows Forms, but there's no xaml files so it's easier, and I didn't find any useful tips. I think I understood that this problem occurs when I don't change something in my xaml file, which doesn't works as simply as "class : abstract class". Maybe the subclass thing ?
Please note that I'm a beginner in WPF apps, so I thank you in advance if your answer is as detailed as possible.
Thanks !

You need to define your base class all in code without using XAML :
Code for class A :
public abstract class A : Window { }
Code for class B :
public partial class B : A
{
public B()
{
InitializeComponent();
}
}
xaml for class B :
<yourNamespace:A x:Class="yourNamespace.B"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:yourNamespace="clr-namespace:yourNamespace"...

A C# partial class is one that is defined over two or more source files. The other 'part' of Window is generated by Visual Studio, and includes things like InitializeComponent()
If you want a base Window class, then it has to be defined entirely in code, and have no XAML component. It will then no longer be a partial class.
public abstract class WindowA : Window
{
// define base methods here
}
Then you can derive WindowB from WindowA:
public partial class WindowB : WindowA
{
public WindowB()
{
InitializeComponent();
}
}
But you also need to do it in the other 'part', i.e. in XAML, so in WindowB's XAML file, the root Window tag needs to be changed to:
<wpfApp:WindowA x:Class="WpfApp.WindowB"
wpfApp:WindowA ="clr-namespace:WpfApp"
(you'll need to change the namespace appropriately)
This will generate the other 'part' deriving from WindowA, so there will be no inconsistency.
The InitializeComponent() method should be called in each derived class' constructor, as it's specific to that class, i.e. in this case, the other 'part' is generated from the XAML, and defines an InitializeComponent() with resourceLocator code that specific to WindowB.

Related

How to add a object list as a property in a class? [duplicate]

You should be able to create a generic form:
public partial class MyGenericForm<T> :
Form where T : class
{
/* form code */
public List<T> TypedList { get; set; }
}
Is valid C#, and compiles. However the designer won't work and the form will throw a runtime exception if you have any images stating that it cannot find the resource.
I think this is because the windows forms designer assumes that the resources will be stored under the simple type's name.
Yes you can! Here's a blog post I made a while ago with the trick:
Designing Generic Forms
Edit: Looks like you're already doing it this way. This method works fine so I wouldn't consider it too hacky.
I have a hack to workaround this, which works but isn't ideal:
Add a new class to the project that inherits the form with its simple name.
internal class MyGenericForm:
MyGenericForm<object> { }
This means that although the designer is still wrong the expected simple type (i.e without <>) is still found.
You can do it in three steps.
1) Replace in Form1.cs File
public partial class Form1<TEntity, TContext> : Formbase // where....
2) Replace in Form1.Designer.cs
partial class Form1<TEntity, TContext>
3) Create new file : Form1.Generic.cs (for opening design)
partial class Form1
{
}
If paleolithic code doesn't affraid you
public static MyForm GetInstance<T>(T arg) where T : MyType
{
MyForm myForm = new MyForm();
myForm.InitializeStuffs<T>(arg);
myForm.StartPosition = myForm.CenterParent;
return myForm;
}
Use it
var myFormInstance = MyForm.GetInstance<T>(arg); myFormInstance.ShowDialog(this);

C# Constructor on type not found when loading Design [duplicate]

I have a Visual Studio 2010 Windows Forms app which includes a Form base class that other classes will inherit. The base class' constructor takes a parameter that the child classes will pass to the base class.
Example:
public partial class BaseForm : Form
{
public BaseForm(int number)
{
InitializeComponent();
}
}
public partial class ChildForm : BaseForm
{
public ChildForm(int number)
: base(number)
{
InitializeComponent();
}
}
The problem that I'm running into is, when I attempt to open the ChildForm in VisualStudio's Design View mode, I receive the following error:
Constructor on type 'MyProject.BaseForm' not found.
Note: regardless of the error, the project compiles and runs fine.
I can avoid the error if I overload the constructor with one that does not contain any parameters.
Example: (This gets rid of the error)
public partial class BaseForm : Form
{
public BaseForm(int number)
{
InitializeComponent();
}
public BaseForm()
{
InitializeComponent();
}
}
public partial class ChildForm : BaseForm
{
public ChildForm(int number)
: base(number)
{
InitializeComponent();
}
}
My question is, how can I create a base class that does not include a parameterless constructor and avoid the Design View error?
That is completely impossible.
The form you see in the design view is an actual instance of your base class.
If there is not default constructor, the designer cannot create that instance.
You can mark the constructor with the [Obsolete("Designer only", true)], and make it throw an exception if called when not in the designer, to prevent other people from calling it.
You need to adjust your BaseForm output type, In the properties for the project, change the Output type from Windows Application to Class Library.
ref:
https://learn.microsoft.com/en-us/dotnet/framework/winforms/advanced/walkthrough-demonstrating-visual-inheritance

Error inheriting UserControl base class while working with Visual Studio designer

Well the title should actually explain the problem quite well. Consider I create a new UserControl, however in my application many of those elements share a common code, and they are part of a "subgroup" of user controls.
The logical thing is to "inject" a class between the generated CustomUserControl and UserControl;
Something akin to:
public abstract class CommonCustomControl : UserControl
{
public CommonCustomControl(int v, string other) {
}
}
public partial class CustomUserControl : CommonCustomControl
{
CustomUserControl(int v, string other) : base(v, other) {
}
}
Now the problem with this is, is that the class is only "partially" generated by visual studio. So changing the generated CustomUserControl class gives an error:
"Base class differs from declared in other parts"
How can I prevent this error? While still being able to actually design my user control element in visual studio's gui designer?
I have tried already the answer provided by this question. But it seems to not work at all. (Maybe since that talks about winforms instead of the WPF version)
[TypeDescriptionProvider(typeof(AbstractControlDescriptionProvider<InterfaceHandler, UserControl>))]
public abstract class CommonCustomControl : UserControl
{
private readonly int _v;
private readonly string _other;
public CommonCustomControl(int v, string other) {
_v = v;
_other = other;
}
}
public partial class CustomUserControl : CommonCustomControl
{
public CustomUserControl(int v, string other) : base(v, other) {
}
}
What goes wrong?
You only have your C# code on view here but I'll take a punt at what this might be.
The UserControl you are declaring inherits from a base class.
The UserControl is also a partial class.
Partial classes normally mean that there is other code for this class elsewhere.
The error is stating that the base class is different between the two partial classes.
If you do not have your own second partial class for this UserControl (i.e. it is not just a class, but an actual User Control), then I assume the rest of the definition will be in the XAML.
Depending on how you are implementing your controls:
You may have this:
<UserControl x:Class="NamespaceHere.CustomUserControl"> ... </UserControl>
It should look like this:
<CommonCustomControl x:Class="NamespaceHere.CustomUserControl"> ... </CommonCustomControl>
If not, could you show your XAML too?

Using generic base class for WPF window

Why is this:
public abstract class WindowControls<T> : Window
not possible. I can't seem to figure it out.
public partial class AnglesteelWindow : WindowControls<AngleSteel> {
private UCListView uc;
public AnglesteelWindow() {
InitializeComponent();
uc = new UCListView();
uc.SubmitClick += new EventHandler(ButtonPressed);
this.uc.grid.PreviewMouseLeftButtonUp +=
new System.Windows.Input.MouseButtonEventHandler(
this.MousePressed14<AngleSteel>);
stkTest.Children.Add(uc);
uc.amountLabel.Content = "Milimeter";
uc.grid.ItemsSource = DatabaseLogic.MaterialTable("Anglesteel").DefaultView;
base.Material(uc, "Anglesteel");
}
}
I know how generics work, but don't know why it is not possible to make my AnglesteelWindow derive from WindowControls.
The error it gives me is the following:
Base class of 'Name of the solution' differs from declared in other parts.
When i look at the so called other part it is the following:
public partial class AnglesteelWindow :
WindowControls<AngleSteel> System.Windows.Markup.IComponentConnector {
This is made in the AnglesteelWindow.g.i.cs file. If i remove it from there it makes no difference at all.
Adding on #MichaelMairegger answer, you can reach your goal by creating another non-generic class that inherits from the generic class like this:
public abstract class WindowControlsOfAngleSteel : WindowControls<AngleSteel>
{
}
And make your window class inherit from it like this:
From XAML:
<ns:WindowControlsOfAngleSteel >
</ns:WindowControlsOfAngleSteel >
Where ns is the namespace where WindowControlsOfAngleSteel exists.
In code (optional):
public partial class AnglesteelWindow : WindowControlsOfAngleSteel
{
}
You cannot change the inheritance tree. AnglesteelWindow is partial because it is also declared in AnglesteelWindow.xaml where the root element is Window. If you want to inherit from another class you have to replace there the Window root by your base class.
public class MyDerivedBaseWindow : Window {}
<ns:MyDerivedBaseWindow >
<!-- WindowContent-->
</ns:MyDerivedBaseWindow >
But you cannot use a Generic class in XAML. You have to change your logic that the base-window-class that you want to use as window-root is non-generic.

Can you use generic forms in C#?

You should be able to create a generic form:
public partial class MyGenericForm<T> :
Form where T : class
{
/* form code */
public List<T> TypedList { get; set; }
}
Is valid C#, and compiles. However the designer won't work and the form will throw a runtime exception if you have any images stating that it cannot find the resource.
I think this is because the windows forms designer assumes that the resources will be stored under the simple type's name.
Yes you can! Here's a blog post I made a while ago with the trick:
Designing Generic Forms
Edit: Looks like you're already doing it this way. This method works fine so I wouldn't consider it too hacky.
I have a hack to workaround this, which works but isn't ideal:
Add a new class to the project that inherits the form with its simple name.
internal class MyGenericForm:
MyGenericForm<object> { }
This means that although the designer is still wrong the expected simple type (i.e without <>) is still found.
You can do it in three steps.
1) Replace in Form1.cs File
public partial class Form1<TEntity, TContext> : Formbase // where....
2) Replace in Form1.Designer.cs
partial class Form1<TEntity, TContext>
3) Create new file : Form1.Generic.cs (for opening design)
partial class Form1
{
}
If paleolithic code doesn't affraid you
public static MyForm GetInstance<T>(T arg) where T : MyType
{
MyForm myForm = new MyForm();
myForm.InitializeStuffs<T>(arg);
myForm.StartPosition = myForm.CenterParent;
return myForm;
}
Use it
var myFormInstance = MyForm.GetInstance<T>(arg); myFormInstance.ShowDialog(this);

Categories

Resources