WPF用户控件设计时尺寸

52

在WPF中创建UserControl时,我发现给它一些任意的Height和Width值很方便,这样我就可以在Visual Studio设计器中查看我的更改。但是当我运行控件时,我希望Height和Width是未定义的,这样控件将扩展以填充我放置它的任何容器。如何在不必在构建控件之前删除Height和Width值的情况下实现相同的功能?(或者不使用父容器中的DockPanel)

以下代码演示了问题:

<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>
以下是UserControl1的定义,设计时可以正常显示,但运行时大小固定:
<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>

UserControl1的下面定义在设计时显示为一个点,但在运行时会展开以填充父级Window1:

<UserControl x:Class="ExampleApplication3.UserControl1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Grid Background="LightCyan" />
</UserControl>
9个回答

81

对于Blend来说,一个鲜为人知的诀窍是将这些属性添加到您的用户控件或窗口中:

 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"

这将把设计的高度和宽度分别设置为500和600。但是,这仅适用于混合设计器,而不适用于Visual Studio设计器。

就Visual Studio设计器而言,您的技术是唯一可行的。这就是为什么我不使用Visual Studio设计器的原因。 ;)


很不幸,这会导致Visual Studio设计器完全无法呈现内容 :( - Abe Heidebrecht
哦...我不使用它,我会更改答案。 - Brian Leahy
6
不再需要任何技巧,VS2012将会为一个新的空UserControl精确创建这种解决方案! - Martin Horatschek

39

在Visual Studio中,向你的UserControl XAML添加Width和Height属性,在代码后端插入以下内容:

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

这段代码检查控件是否在设计模式下运行。如果不是(即运行时),它会将宽度和高度设置为NaN(非数字)。如果您在XAML中删除了宽度和高度属性,则将其设置为此值。

因此,在设计时,您将拥有预设的宽度和高度(包括如果您将用户控件放在窗体中),而在运行时,它将根据其父容器进行停靠。

希望这可以帮助你。


这个能否以相反的方式完成?也就是说,当LicenseManager.UsageMode == LicenseUsageMode.Designtime时,我是否可以将用户控件XAML高度/宽度保留为未定义,并仅在构造函数中设置高度和宽度? - Patrick Szalapski
很遗憾,LicenseUsageMode不包含Designtime。 - jonatr
只是一个快速的提醒,如果您不想使用许可证管理器,有一个可用的附加属性。请参阅https://dev59.com/VHRA5IYBdhLWcg3wxA5N#834332或https://learn.microsoft.com/en-us/dotnet/api/system.componentmodel.designerproperties.getisindesignmode - Jan Wiesemann

9
这里是一份Silverlight 设计器中的 Design-Time 属性列表。WPF 设计器的属性也相同。
此列表列出了设计器中所有可用的 d: 值,例如 d:DesignHeightd:DesignWidthd:IsDesignTimeCreatabled:CreateList 等几个属性。

7
我经常这样做。只需在实例化控件时将宽度和高度值设置为“auto”,这将覆盖该UserControl的设计时值。
例如:<loc:UserControl1 Width="auto" Height="auto" /> 另一种选择是将MinWidth和MinHeight的组合设置为允许设计时工作的大小,而Width和Height保持“auto”。显然,只有当您不需要在运行时将UserControl调整为小于最小值时,才能使用此选项。

2
我正在寻找与Blend中使用的类似解决方案,通过您的提醒,我创建了一个简单的行为类,其中包含两个附加属性Width和Height,仅在DesinTime中应用。
public static class DesignBehavior 
{
    private static readonly Type OwnerType = typeof (DesignBehavior);
#region Width
public static readonly DependencyProperty WidthProperty = DependencyProperty.RegisterAttached( "Width", typeof (double), OwnerType, new FrameworkPropertyMetadata(double.NaN, new PropertyChangedCallback(WidthChangedCallback)));
public static double GetWidth(DependencyObject depObj) { return (double)depObj.GetValue(WidthProperty); }
public static void SetWidth(DependencyObject depObj, double value) { depObj.SetValue(WidthProperty, value); }
private static void WidthChangedCallback(DependencyObject depObj, DependencyPropertyChangedEventArgs e) { if (DesignerProperties.GetIsInDesignMode(depObj)) { depObj.SetValue(FrameworkElement.WidthProperty, e.NewValue); } }
#endregion
#region Height
public static readonly DependencyProperty HeightProperty = DependencyProperty.RegisterAttached( "Height", typeof (double), OwnerType, new FrameworkPropertyMetadata(double.NaN, new PropertyChangedCallback(HeightChangedCallback)));
public static double GetHeight(DependencyObject depObj) { return (double)depObj.GetValue(HeightProperty); }
public static void SetHeight(DependencyObject depObj, double value) { depObj.SetValue(HeightProperty, value); }
private static void HeightChangedCallback(DependencyObject depObj, DependencyPropertyChangedEventArgs e) { if (DesignerProperties.GetIsInDesignMode(depObj)) { depObj.SetValue(FrameworkElement.HeightProperty, e.NewValue); } }
#endregion
}
然后在您的UserControl中,您只需在Xaml中设置这些属性。
<UserControl x:Class="ExtendedDataGrid.Views.PersonOverviewView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:tool="http://schemas.microsoft.com/wpf/2008/toolkit"
    xmlns:b="clr-namespace:ExtendedDataGrid.Behaviors"
    b:DesignBehavior.Width="600" b:DesignBehavior.Height="200">
    <Grid>
         ...
    </Grid>
</UserControl>

0

有些人建议使用LicenseManager.UsageMode属性,但我以前从未见过它,不过我已经使用了以下代码。

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

esskar,

我想补充一点,当你重写一个"On"方法时,通常应该调用基类的方法。

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

    ...
}

顺便说一句,这是个很好的解决方法,我现在也在使用它。

请注意,到目前为止提供的解决方案以及其他解决方案都不能解决在另一个控件中使用此控件属性并且该控件在设计视图中显示的问题。希望在Visual Studio 2010中引入的新的DesignHeight和DesignWidth属性能够解决这个问题。 - jpierson

0

我也是这样做的,但我的解决方案可以确保如果您在设计模式下将控件添加到容器中,它会出现得比较合理。

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

你觉得呢?


如果你要进行覆盖,请记得调用基类。base.OnVisualParentChanged(oldParent); - David Waters

0

感谢原回答者提供此解决方案!对于那些有兴趣的人,下面是VB版本:

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

0

在控件上使用MinWidth和MinHeight。这样,您将在设计器中看到它,在运行时它将按您想要的大小调整。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接