Размер времени разработки WPF UserControl
-
09-06-2019 - |
Вопрос
При создании 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);
...
}
Кстати, отличное обходное решение, сейчас я и сам им пользуюсь.