Dimensioni del tempo di progettazione del controllo utente WPF
-
09-06-2019 - |
Domanda
Quando creo un UserControl in WPF, trovo conveniente assegnargli alcuni valori arbitrari di altezza e larghezza in modo da poter visualizzare le modifiche nella finestra di progettazione di Visual Studio.Quando eseguo il controllo, tuttavia, desidero che l'altezza e la larghezza non siano definite, in modo che il controllo si espanda per riempire qualunque contenitore lo inserisco.Come posso ottenere la stessa funzionalità senza dover rimuovere i valori di altezza e larghezza prima di creare il mio controllo?(O senza utilizzare DockPanel nel contenitore principale.)
Il codice seguente illustra il problema:
<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>
La seguente definizione di UserControl1
viene visualizzato in modo ragionevole in fase di progettazione ma viene visualizzato con dimensioni fisse in fase di esecuzione:
<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>
La seguente definizione di UserControl1
viene visualizzato come un punto in fase di progettazione ma si espande per riempire l'elemento principale Window1
in fase di esecuzione:
<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>
Soluzione
In Visual Studio aggiungi gli attributi Larghezza e Altezza al tuo UserControl XAML, ma nel code-behind inseriscilo
public UserControl1()
{
InitializeComponent();
if (LicenseManager.UsageMode != LicenseUsageMode.Designtime)
{
this.Width = double.NaN; ;
this.Height = double.NaN; ;
}
}
Ciò verifica se il controllo è in esecuzione in modalità progettazione.In caso contrario (ad es.runtime) imposterà Larghezza e Altezza su NaN (non un numero) che è il valore su cui lo imposti se rimuovi gli attributi Larghezza e Altezza in XAML.
Quindi in fase di progettazione avrai la larghezza e l'altezza preimpostate (anche se inserisci il controllo utente in un modulo) e in fase di esecuzione si ancorarà a seconda del contenitore principale.
Spero che aiuti.
Altri suggerimenti
Per Blend, un trucco poco conosciuto è aggiungere questi attributi al tuo controllo utente o finestra:
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"
Ciò imposterà l'altezza e la larghezza del disegno rispettivamente su 500 e 600.Tuttavia questo funzionerà solo per il progettista della fusione.Non la finestra di progettazione di Visual Studio.
Per quanto riguarda Visual Studio Designer, la tua tecnica è tutto ciò che funziona.Questo è il motivo per cui non utilizzo Visual Studio Designer.;)
Ecco un elenco di Attributi in fase di progettazione in Silverlight Designer.Sono gli stessi per la finestra di progettazione WPF.
Elenca tutti i d:
valori disponibili nel Designer come d:DesignHeight
, d:DesignWidth
, d:IsDesignTimeCreatable
, d:CreateList
e molti altri.
Lo faccio sempre.Imposta semplicemente i valori di larghezza e altezza su "auto" nel punto in cui crei un'istanza del controllo e questo sovrascriverà i valori della fase di progettazione per tale UserControl.
cioè: <loc:UserControl1 Width="auto" Height="auto" />
Un'altra opzione consiste nell'impostare una combinazione di MinWidth e MinHeight su una dimensione che consenta il lavoro in fase di progettazione, mentre Larghezza e Altezza rimangono "automatiche".Ovviamente, funziona solo se non è necessario che UserControl riduca le dimensioni inferiori ai valori minimi in fase di esecuzione.
Stavo cercando una soluzione simile come quella usata in Blend e con le tue menzioni ho creato una semplice classe di comportamento con due proprietà allegate Larghezza e Altezza che vengono applicate solo in 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 }
Quindi nel tuo UserControl imposti semplicemente queste proprietà in 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>
Utilizzare MinWidth e MinHeight sul controllo.In questo modo, lo vedrai nel designer e in fase di esecuzione verrà dimensionato nel modo desiderato.
Lo faccio in modo simile, ma la mia soluzione assicura che se aggiungi il tuo controllo a un contenitore in modalità progettazione, apparirà in modo ragionevole.
protected override void OnVisualParentChanged(DependencyObject oldParent)
{
if (this.Parent != null)
{
this.Width = double.NaN;
this.Height = double.NaN;
}
}
cosa ne pensi?
Grazie al risponditore originale per questa soluzione!Per coloro che sono interessati, eccolo in VB:
If LicenseManager.UsageMode <> LicenseUsageMode.Designtime Then
Me.Width = Double.NaN
Me.Height = Double.NaN
End If
Alcuni hanno suggerito di utilizzare la proprietà LicenseManager.UsageMode che non avevo mai visto prima, ma ho utilizzato il seguente codice.
if(!DesignerProperties.GetIsInDesignMode(this))
{
this.Width = double.NaN;
this.Height = double.NaN;
}
Eskar,
Voglio solo aggiungere che generalmente dovresti sempre chiamare il metodo della base quando sovrascrivi un metodo "On".
protected override void OnVisualParentChanged(DependencyObject oldParent)
{
base.OnVisualParentChanged(oldParent);
...
}
Ottima soluzione comunque, la sto usando anch'io adesso.