When creating a new UserControl in UWP the following code behind xaml.cs file is generated.
public sealed partial class MyUserControl: UserControl
{
public MyUserControl()
{
this.InitializeComponent();
}
}
I would like to update this file so we can have better logging when things like the xaml fails to parse correctly.
public sealed partial class MyUserControl: UserControl
{
public MyUserControl()
{
try
{
this.InitializeComponent();
}
catch (Exception e)
{
//do all the logging
}
}
}
Whether this is done by extending UserControl or just doing the above (or some other option), I would like to avoid having to do this manually for all future user controls that are created. Is there any way that I can update/extend the code that is generated when we create a new user control / xaml.cs file so that I don't have to manually add the extra logging each time?
Thanks.
No you can't.
UserControl is part of the uwp SDK and you can not edit that class itself. However you can create a child from usercontrol, within its constructor call constructor of its parent ( base ). Then you can create child of this new class to create your user controls and then work on wiring it up to the UI part as well which can be more complicated. So the simplest way to error log your xaml parsing right now is the way you are already doing it. You have to put that try catch. You can just create a snippet and every time you create a new user control just use that snippet on its constructor maybe that can save you some time.
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 am trying to add several controls like Labels, pictureboxes etc. to a Panel in c# Windows Forms. My code looks like this:
this.panel1.Controls.Add(this.label1);
Every time I put this in the panel1 section in my Designer.cs, it gets deleted after I switch between classes and forms. I am doing this so that I can "transform" the Panel into a Bitmap with all the other controls in it.
Well, as you can see, you are trying to modify code within
#region Windows Form Designer generated code
...
// Designer is supposed to put (or/and remove) any code within this region
// Do not put any custom code here manually
this.panel1.Controls.Add(this.label1);
...
#endregion
and you have a conflict with Designer. Just let it generate its code in the area which specially designed (and marked out) for that; put yours into, say, constructor:
public MyForm() {
// Let .Net initialize the form, create all constrols etc. first
InitializeComponent();
// Then, run your code here
this.panel1.Controls.Add(this.label1);
}
Try :
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
this.panel1.Controls.Add(this.label1);
}
}
I'm following this tutorial on winforms, and so far the tutorial is coding the form without using the toolbox. I believe it'll introduce the toolbox in more depth shortly.
Following the tutorial, I've made a partial class in the following two pieces of code:
First file:
using System;
using System.Windows.Forms;
public class Numeric : System.Windows.Forms.TextBox
{
public Numeric()
{
}
}
public partial class Exercise
{
private Numeric txtbox;
System.ComponentModel.Container components;
}
Second file:
using System;
using System.Windows.Forms;
public partial class Exercise : Form
{
private void InitializeComponent()
{
txtbox = new Numeric();
Controls.Add(txtbox);
}
public Exercise()
{
InitializeComponent();
}
}
public class program
{
public static int Main()
{
Application.Run(new Exercise());
return 0;
}
}
When I run the code with F5, everything looks fine: The form pops up with the textbox.
But for some reason, when I right-click on the second file and choose "View Designer", I get an error which says "The variable 'txtbox' is either undeclared or was never assigned". I can choose to "Ignore and Continue", which leads me to a form with no textbox on it.
Why does this occur? I know some of you think I should just use the toolbox, and it's probably the most sensible thing to do, but I would still like to understand why this happens.
How does the Windows Forms Designer work?
When you open a Form in windows forms designer, the designer looks into the first class in the file. If the file has a Designer.cs containing the other partial part of the class, also includes it and tries to deserialize those file contents. In the process of deserialization and loading the design time of your form, it creates an instance of the base class of your form and looks in those files for component declarations and InitializeComponents method. If find them creates components and sets properties of them using deserialized codes and add components to the instance of base class which created.
Some useful facts:
Codes in constructor of your Form will not execute at design-time, but the constructor of base class of your form will execute in design-time.
Codes in InitializeComponent will not execute at design-time, but those codes will be deserialized and will be used to create designer of the form.
The designer can not show a form which has an abstract base class. (solution)
The designer can not show a form which has generic class. For example it can not show MyForm:SomeForm<SomeClass>, but it can show SomeForm<T>:Form. (solution)
If you define a new property for your form, the properties will not show in properties window. The properties window, shows the properties of base class but with values of your form.
When a file contains 2 class, if the form was not the first class the designer can not load and you receive a warning that says the form should be first class to show in designer.
Above rules will apply also to UserControls.
Example
Take a look at below code, which has some serious problems:
The class has different constructor than class name
The statement int i="x";
There is no semicolons while this is a C# class
The InitializeComponent method didn't call in constructor
But the interesting news is you can see the form in designer, even with those errors!
Just create a file in your project and put below codes in the file and save the file and close it. Then without trying to build the solution, open the form in designer. Here is code:
using System
using System.Windows.Forms
namespace SampleApplication
{
public class MyForm:Form
{
public NotMyForm()
{
}
public void InitializeComponent()
{
int i="x";
textBox1 = new TextBox()
textBox1.Text = "Hi"
this.Controls.Add(textBox1)
}
private TextBox textBox1
}
}
And here is screenshot of designer:
More information
To find more information, take a look at this link:
How does the Windows Forms designer in Visual Studio load a Form? (The original website is off - You can find the archive here)
Solution for your question
As a solution, it is enough for you to move private Numeric txtbox; and put it your seccond file in Exercise class.
The declaration of the controls should be put into Designer.cs files in order Visual Studio can just compile this unit and display it.
When you launch the app, the compiler takes into account all parts of your partial class then it finds txtBox declaration.
Try leave only the form class with its graphical declarations in a single file.
This single file should have InitializeComponent methdod, construcutor and field declarations of UI components initialized in InitializeComponent().
I've created a custom UserControl using the GUI, and I can't get it to accept dynamically added events from within a custom class.
Sorry if I get the exact code wrong, going from memory, but you get the gist.
C# .NET 2008, Winform
I have a "container class" that stores all my information.
The main WinForm has an array of these, and they each have a summary panel.
The main form also has a "work zone" that will let you access the container class.
The idea is, interacting with the CustomUserControl will cause stuff to happen within the ContainerClass. The control uses info from there, and I want it to update from within there.
ContainerClass
{
CustomUserControl tempControl;
public ContainerClass()
{
//do stuff
tempControl = new CustomUserControl([send information]);
tempControl.Click += new Event(localClickEvent);
}
public void localClickEvent(object sender, Event e)
{
//do stuff
}
}
.
public class Form1
{
public Form1()
{
//create several container objects
//for each container object, get it's SummaryPanel
//and add it to the FlowLayoutPanel
CustomUserControl tempControl = ContainerObject.GetCustomControl();
flp_summaryPanel.Controls.Add(tempControl);
}
}
When I execute this code, the dynamic event never fires.
I've done this sort of thing before, but it was always with custom classes that inherited the control I needed. I've never inherited UserControl, so I suspect I left something out.
I susepct this is an protection issue, but the compiler isn't catching it.
MORE INFO
This somehow got labeled as an ASP.net question. It's not, I'm using Winforms, though I never specifically said so.
One other thing that may be important: The dynamic event isn't in another control. It's in a custom class that functions as a large container object.
.
.
As always, thanks so much for your help! :)
Try attaching event handler after adding control to Controls collection
public ParentControl()
{
CustomUserControl tempControl = new CustomUserControl();
this.Controls.Add(tempControl);
tempControl.Click += new Event(localClickEvent);
}
It may be related to the fact that unless the control is added to NamingContainer the ClientID cannot be generated properly.
Which version of C# are you using? Try this:
public void ParentControl_Init()
{
CustomUserControl tempControl = new CustomUserControl();
this.Controls.Add(tempControl);
tempControl.Click += localClickEvent;
}
public void localClickEvent(object sender, EventArgs e)
{
//do stuff
}
You don't want to add controls and attach events in the constructor. Look at how ASP.NET does it and you'll see why.
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