tags:

views:

7953

answers:

6

When creating a UserControl in WPF, I find it convenient to give it some arbitrary Height and Width values so that I can view my changes in the Visual Studio designer. When I run the control, however, I want the Height and Width to be undefined, so that the control will expand to fill whatever container I place it in. How can I acheive this same functionality without having to remove the Height and Width values before building my control? (Or without using DockPanel in the parent container.)

The following code demonstrates the problem:

<Window x:Class="ExampleApplication3.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:loc="clr-namespace:ExampleApplication3"
    Title="Example" Height="600" Width="600">
    <Grid Background="LightGray">
        <loc:UserControl1 />
    </Grid>
</Window>

The following definition of UserControl1 displays reasonably at design time but displays as a fixed size at run time:

<UserControl x:Class="ExampleApplication3.UserControl1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Height="300" Width="300">
    <Grid Background="LightCyan" />
</UserControl>

The following definition of UserControl1 displays as a dot at design time but expands to fill the parent Window1 at run time:

<UserControl x:Class="ExampleApplication3.UserControl1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"&gt;
    <Grid Background="LightCyan" />
</UserControl>
+11  A: 

For Blend, a little known trick is to add these attributes to your usercontrol or window:

 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
mc:Ignorable="d"
       d:DesignHeight="500" d:DesignWidth="600"

This will set the design height and width to 500 and 600 respectively. However this will only work for the blend designer. Not the Visual Studio Designer.

As far as the Visual Studio Designer your technique is all that works. Which is why I don't use the Visual Studio Designer. ;)

Brian Leahy
Unfortunately, this causes the Visual Studio Designer to not render the content at all :(
Abe Heidebrecht
oh... i don't use it, i'll change the answer
Brian Leahy
This trick will work with VS2010.
wekempf
+19  A: 

In Visual Studio add the Width and Height attribute to your UserControl XAML, but in the code-behind insert this

public UserControl1()
{
    InitializeComponent();
    if (LicenseManager.UsageMode != LicenseUsageMode.Designtime)
    {
        this.Width = double.NaN; ;
        this.Height = double.NaN; ;
    }
}

This checks to see if the control is running in Design-mode. If not (i.e. runtime) it will set the Width and Height to NaN (Not a number) which is the value you set it to if you remove the Width and Height attributes in XAML.

So at design-time you will have the preset width and height (including if you put the user control in a form) and at runtime it will dock depending on its parent container.

Hope that helps.

AlexDuggleby
Can this be done in the inverse way? That is, can I leave the user control XAML height/width undefined and then set a height and width in the constructor ONLY when LicenseManager.UsageMode == LicenseUsageMode.Designtime ?
Patrick Szalapski
@Patrick: Apparently not. That is, it doesn't work for me.
Thomas
+4  A: 

I do this all the time. Simply set the width and height values to "auto" where you instantiate your control, and this will override the design-time values for that UserControl.

ie: <loc:UserControl1 Width="auto" Height="auto" />

Another option is to set a combination of MinWidth and MinHeight to a size that allows design-time work, while Width and Height remain "auto". Obviously, this only works if you don't need the UserControl to size smaller than the min values at runtime.

AndyL
A: 

I do it similar, but my solution assures that if you add your control to an container in design mode, it will appear reasonably.

protected override void OnVisualParentChanged(DependencyObject oldParent)
{
    if (this.Parent != null)
    {
       this.Width = double.NaN;
       this.Height = double.NaN;
    }
}

what do you think?

If you are going to override remeber to case base. base.OnVisualParentChanged(oldParent);
David Waters
A: 

Thanks to the original answerer for this solution! For those that are interested, here it is in VB:

If LicenseManager.UsageMode <> LicenseUsageMode.Designtime Then
    Me.Width = Double.NaN
    Me.Height = Double.NaN
End If
Paul
A: 

Some have suggested using the LicenseManager.UsageMode property which I've never seen before but I have used the following code.

if(!DesignerProperties.GetIsInDesignMode(this))
{
    this.Width = double.NaN;
    this.Height = double.NaN;
}

esskar,

I just want to add that you should generally always call the method of the base when overriding an "On" method.

protected override void OnVisualParentChanged(DependencyObject oldParent)
{
    base.OnVisualParentChanged(oldParent);

    ...
}

Great workaround by the way, I'm using it myself now too.

jpierson
Note that this solution as well as the others offered so far do not solve the problem of displaying this control property when it is used within another control and that control is viewed in the designer. Hopefully the new DesignHeight and DesignWidth properties will solve this is Visual Studio 2010.
jpierson