Avoid XAML Designer error with custom controls - c#

Let's say that I have a custom control that inherits from another control.
I want to set some properties of this control, so I add something like this inside the constructor, for example:
public class MyControl : Canvas
{
public MyControl()
{
if (getSomeTestValueFromAppSettings())
{
this.Background = ColorConverter.MyStaticBrushProperty1;
}
else
{
this.Background = ColorConverter.MyStaticBrushProperty2;
}
}
}
Now, everything works fine inside the app, so no problems there.
The point is that if I add something like this inside my control constructor, I get an error with the XAML designer, and it tells me it can't create an instance of the control.
That's ok, since of course the constructor is trying to access the app local settings, and it can't do that inside the XAML Designer.
I'm currently using this as a workaround: I simply wrap all my conde inside the constructor inside a try/catch block, and if I got an exception (that only happens inside the XAML Designer) I simply ignore it.
This way the code stillworks fine on the phone, and it doesn't crash the XAMl Designer.
I don't think that this is a good solution though, a try/block inside a class constructor is not something I think could be considered a good programming practice.
I was hoping there was something like a "compiler directive" that tells the compiler when it's not actually running on a device/emulator, but just inside the XAML Designer, but I didn't find anything like that.
Do you have suggestions or other better ideas on how to solve that problem?
Thanks!
Sergio

There is actually a build-in method for situations like this.
Just use this code
if (DesignerProperties.GetIsInDesignMode(this))
{
// Design-mode specific functionality
}

Related

Winforms User Control MissingMethodException

So essentially, I have a custom user control called ExcelDisplay. I try to drag it over in visual studio from the toolbox into my webform in the same project and I get a missing method exception. At one time the constructor was parameterized, but I changed it after deciding it was a bad design idea.
It looks like it is saying the constructor is missing, but its obviously there.
My winform to house the control is empty with the exception of the autogenerated code visual studio puts there.
The code for my ExcelDisplay's constructor looks like this.
namespace STS_Console.UserControls
{
public partial class ExcelDisplay : UserControl
{
public ExcelDisplay()
{
InitializeComponent();
DataDisplay.Columns[0].HeaderText = "Data";
//debug
string x = DataDisplay.Columns[0].GetType().ToString();
x.ToString();
}
The error message is this.
So that error occurs when do I drag and drop in the designer like this
Anyway so that is my problem. I am not sure what is causing it or how to fix it. I would be glad to post additional code upon request.
You should put your user controls in a class library of their own. For the designer to work, it needs a compiled version of your user control. If you cannot compile your user control before you compile your form, you will get into all kinds of trouble.
Rebuild Solution fixed it for me, although if your making regular changes to your user control, you should put them into a separate project.
My particular problem, was a user control, within a user control.

WPF user control throws design-time exception

I have a userControl which starts a timer. It looks like the XAML designer is trying to call that code, which links to some back-end database stuff. I keep getting an unhanded exception error in the design screen.
Any ideas how I can stop the designer trying to run the code?
XAML designer will call the UserControl's constructor when loading in designer. In order to avoid this you can place a if condition as follows in your UserControl constructor
if(System.ComponentModel.DesignMode) return;
You can also check in this way
if (!System.ComponenyModel.DesignProperties.GetIsInDesignMode(this))
{ // write constructor code here }

Winforms Designer: How to disable my usercontrol from being a container?

I have a relatively simple setup. I have a custom usercontrol that has a bunch of components on it, some text boxes, and a listview.
In the designer, I can drag and drop other controls into my usercontrol, and it adds them to the usercontrol instance. I don't want this.
How can I explicitly say "Don't allow additional controls to be added to this usercontrol?"
That's not the way it works. When you drop your user control on a form then adding controls to it isn't supported. That requires a special designer, this answer shows what is required. Maybe it looks like the controls get added but they merely overlap your user control. Their parent is still the form.
If a programmer opens your user control class itself in the designer then, sure, he can add controls as he pleases. The only way to stop that is to not ship the source code and use the sealed keyword to prevent deriving from it.
You could create a boolean property MyContainer.DisableAddControls or something.
If your MyContainer.Controls.Add(..) is overridden, then you can throw some custom exception in that Add() method as follows:
if(DisableAddControls)
{
throw new DisableAddControlsException();
}
If you are inheriting that method straight from ContainerControl, then you can handle the ControlAdded event and throw the exception there.
myContainer.ControlAdded += myContainerControlAdded;
private void Control_Added(object sender, System.Windows.Forms.ControlEventArgs e)
{
if(DisableAddControls)
{
throw new DisableAddControlsException();
}
}
On second thought, this won't throw out your designer at design time... nevermind.

Efficient Declaration/Creation of variables/controls

I'm working on cleaning up an app I'm almost finished with and I noticed something that made me curious as to why it's being done that way. While you can edit the .Designer.cs in your project for a form, there is a lot of autogenerated stuff in there, such as the creation of variables and controls. They have the Windows Form Designer generated code which hardly ever gets touched by me. But as I was making variables in the format I like them:
string strValue1,
strValue2;
As compared to:
string strValue1;
string strValue2;
I noticed that Windows declares the controls on the bottom of the file then creates/instantiates them in the InitializeComponent() function. Now, I knowI could take the "new" instances and put them where the declarations are and it seems to run fine. My question is what's the benefit of one over the other? Or is this the way it is so Windows can autogenerate them for us? If there's a possibility of better performance for doing it one way over another, I'd like to know. Thanks guys for the help.
Example 1:
private void InitializeComponent()
{
...
this.control1 = new System.Windows.Forms.Control();
...
}
...
System.Windows.Forms.Control control1;
Example 2:
private void InitializeComponent()
{
...
}
...
System.Windows.Forms.Control control1 = new System.Windows.Forms.Control();
Do not edit that code. It is auto-generated and the designer actually reads the code back to recreate the form in the designer. When you make changes like this, it is very likely you'll bomb the designer and your form becomes un-designable. Even if you do manage to avoid crashing it, your changes will simply disappear when you alter the form in the designer.
Anything in the region that's marked "Windows Forms Designer generated code" is hands-off.
There is no benefit whatsoever to changes like these. It generates the exact same code.
You can get some more control over stuff when its done in the InitializeComponent
If you open up your .cs file (not the designer) and look at the constructor
public Form1()
{
InitializeComponent();
}
this way you can have code execute before the controls are instantiated..
if you would just create the controls when they are declared then you would not be able to do this...

How to create a derived ComboBox with pre-bound datasource that is designer friendly?

I'd like to create a derived control from System.Windows.Forms.ComboBox that is bound to a list of objects that I retrieve from the database. Idea is other developers can just drop this control on their form without having to worry about the datasource, binding, unless they want to.
I have tried to extend combobox and then set the DataSource, DisplayMember, and ValueMember in the constructor.
public class CustomComboBox : ComboBox
{
public CustomComboBox()
{
this.DataSource = MyDAL.GetItems(); // Returns List<MyItem>
this.DisplayMember = "Name";
this.ValueMember = "ItemID";
}
}
Works when I run, but throws a lot of errors in Visual Studio's once it's added to any form. The error I get is:
"Code generation for property 'Items' failed. Error was: 'Object reference not set to an instance of an object"
What's the correct way to accomplish this (C#, Winforms, .NET 2.0+)?
The problem is that the designer actually does some compilation and execution in a slightly different context than normally running the program does.
In the constructor, you can wrap your code in:
if (!DesignMode)
{
//Do this stuff
}
That will tell the designer to not run any of your initialization code while it is being designed.
DesignMode property doesn't work in a constructor. From googling for a while, found this LicenseManager thing.
if (LicenseManager.UsageMode != LicenseUsageMode.Designtime)
{
// Do your database/IO/remote call
}
However LicenseManager only works in constructors. For eventhandlers use DesignMode.
Source: http://dotnetfacts.blogspot.com/2009/01/identifying-run-time-and-design-mode.html
Another reference: http://weblogs.asp.net/fmarguerie/archive/2005/03/23/395658.aspx
My usual comment here - DesignMode is not reliable in any situation other than if the control is placed directly on a design surface - i.e. if the control is placed on another control, DesignMode is not true even if you are in design mode. I have found NO reliable way to tell if you are in design mode - especially with inherited controls. Even variants using Site are not reliable if the control is inherited from a non-visual control (e.g. Common Dialog).
See http://keyofdflat.livejournal.com/5407.html (make sure to read the last comment).

Categories