Вопрос

При создании UserControl в WPF я нахожу удобным присвоить ему некоторые произвольные значения высоты и ширины, чтобы я мог просматривать свои изменения в Visual Studio designer.Однако, когда я запускаю элемент управления, я хочу, чтобы высота и ширина были неопределенными, чтобы элемент управления расширялся, заполняя любой контейнер, в который я его помещаю.Как я могу реализовать эту же функциональность без необходимости удалять значения высоты и ширины перед созданием моего элемента управления?(Или без использования 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>
Это было полезно?

Решение

В Visual Studio добавьте атрибут Width и Height в ваш UserControl XAML, но в коде, лежащем в основе, вставьте это

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

При этом проверяется, запущен ли элемент управления в режиме разработки.Если нет (т. е.время выполнения) он установит ширину и высоту равными NaN (не числу), которые являются значением, на которое вы их устанавливаете, если вы удалите атрибуты Width и Height в XAML.

Таким образом, во время разработки у вас будут заданные ширина и высота (в том числе, если вы поместите пользовательский элемент управления в форму), а во время выполнения он будет закреплен в зависимости от его родительского контейнера.

Надеюсь, это поможет.

Другие советы

Для Blend малоизвестный трюк заключается в добавлении этих атрибутов в ваш пользовательский элемент управления или 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"

При этом высота и ширина конструкции будут установлены равными 500 и 600 соответственно.Однако это будет работать только для дизайнера blend.Не дизайнер Visual Studio.

Что касается дизайнера Visual Studio, то ваша техника - это все, что работает.Вот почему я не использую Visual Studio Designer.;)

Вот список Атрибуты времени разработки в Silverlight Designer.Они одинаковы для разработчика WPF.

В нем перечислены все d: значения, доступные в Конструкторе, такие как d:DesignHeight, d:DesignWidth, d:IsDesignTimeCreatable, d:CreateList и еще несколько других.

Я делаю это постоянно.Просто установите значения ширины и высоты в "auto", где вы создаете свой элемент управления, и это переопределит значения времени разработки для этого UserControl.

т. е.: <loc:UserControl1 Width="auto" Height="auto" />

Другой вариант - установить комбинацию MinWidth и minHeight на размер, который позволяет выполнять работу во время разработки, в то время как ширина и Высота остаются "автоматическими".Очевидно, что это работает только в том случае, если вам не нужно, чтобы размер UserControl был меньше минимальных значений во время выполнения.

Я искал похожее решение, подобное тому, которое используется в 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>

Используйте MinWidth и minHeight для элемента управления.Таким образом, вы увидите его в конструкторе, и во время выполнения он будет иметь нужный вам размер.

Я делаю это аналогично, но мое решение гарантирует, что если вы добавите свой элемент управления в контейнер в режиме разработки, он будет выглядеть разумно.

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

а ты как думаешь?

Спасибо оригинальному ответчику за это решение!Для тех, кому интересно, вот это в VB:

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

Некоторые предлагали использовать LicenseManager.Свойство UsageMode, которое я никогда раньше не видел, но я использовал следующий код.

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

эск - кар,

Я просто хочу добавить, что обычно вы всегда должны вызывать базовый метод при переопределении метода "On".

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

    ...
}

Кстати, отличное обходное решение, сейчас я и сам им пользуюсь.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top