wpf
Creazione di UserControls personalizzati con associazione dati
Ricerca…
Osservazioni
Si noti che un controllo utente è molto diverso da un controllo. Una delle differenze principali è che UserControl utilizza un file di layout XAML per determinare dove posizionare più controlli individuali. Un controllo, d'altra parte, è solo un codice puro - non c'è alcun file di layout. In qualche modo, la creazione di un controllo personalizzato può essere più efficace della creazione di un controllo utente personalizzato.
ComboBox con testo predefinito personalizzato
Questo UserControl personalizzato apparirà come una normale casella combinata, ma diversamente dall'oggetto ComboBox incorporato, può mostrare all'utente una stringa di testo predefinita se non ha ancora effettuato una selezione.
Per fare ciò, il nostro UserControl sarà composto da due controlli. Ovviamente abbiamo bisogno di un vero ComboBox, ma useremo anche un'etichetta regolare per mostrare il testo predefinito.
CustomComboBox.xaml
<UserControl x:Class="UserControlDemo.CustomComboBox"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:cnvrt="clr-namespace:UserControlDemo"
x:Name="customComboBox">
<UserControl.Resources>
<cnvrt:InverseNullVisibilityConverter x:Key="invNullVisibleConverter" />
</UserControl.Resources>
<Grid>
<ComboBox x:Name="comboBox"
ItemsSource="{Binding ElementName=customComboBox, Path=MyItemsSource}"
SelectedItem="{Binding ElementName=customComboBox, Path=MySelectedItem}"
HorizontalContentAlignment="Left" VerticalContentAlignment="Center"/>
<Label HorizontalAlignment="Left" VerticalAlignment="Center"
Margin="0,2,20,2" IsHitTestVisible="False"
Content="{Binding ElementName=customComboBox, Path=DefaultText}"
Visibility="{Binding ElementName=comboBox, Path=SelectedItem, Converter={StaticResource invNullVisibleConverter}}"/>
</Grid>
</UserControl>
Come puoi vedere, questo singolo UserControl è in realtà un gruppo di due controlli individuali. Questo ci consente una certa flessibilità che non è disponibile in un singolo ComboBox da solo.
Ecco alcune cose importanti da notare:
- Lo stesso UserControl ha un
x:Name
. Questo perché vogliamo associare le proprietà che si trovano nel code-behind, il che significa che ha bisogno di un modo per fare riferimento a se stesso. - Ciascun legame del ComboBox ha il nome UserControl come
ElementName
. Questo è così che UserControl sa guardare se stesso per localizzare i collegamenti. - L'etichetta non è hit-test visibile. Questo per dare all'utente l'illusione che l'etichetta faccia parte del ComboBox. Impostando
IsHitTestVisible=false
,IsHitTestVisible=false
all'utente di passare con il mouse sopra o facendo clic sull'etichetta: tutto l'input viene passato attraverso il ComboBox di seguito. - L'etichetta utilizza un convertitore
InverseNullVisibility
per determinare se deve mostrarsi o meno. Puoi trovare il codice per questo in fondo a questo esempio.
CustomComboBox.xaml.cs
public partial class CustomComboBox : UserControl
{
public CustomComboBox()
{
InitializeComponent();
}
public static DependencyProperty DefaultTextProperty =
DependencyProperty.Register("DefaultText", typeof(string), typeof(CustomComboBox));
public static DependencyProperty MyItemsSourceProperty =
DependencyProperty.Register("MyItemsSource", typeof(IEnumerable), typeof(CustomComboBox));
public static DependencyProperty SelectedItemProperty =
DependencyProperty.Register("SelectedItem", typeof(object), typeof(CustomComboBox));
public string DefaultText
{
get { return (string)GetValue(DefaultTextProperty); }
set { SetValue(DefaultTextProperty, value); }
}
public IEnumerable MyItemsSource
{
get { return (IEnumerable)GetValue(MyItemsSourceProperty); }
set { SetValue(MyItemsSourceProperty, value); }
}
public object MySelectedItem
{
get { return GetValue(MySelectedItemProperty); }
set { SetValue(MySelectedItemProperty, value); }
}
}
Nel code-behind, stiamo semplicemente esponendo quali proprietà vogliamo essere disponibili al programmatore usando questo UserControl. Purtroppo, perché non abbiamo accesso diretto al ComboBox dall'esterno questa classe, abbiamo bisogno di esporre le proprietà duplicati ( MyItemsSource
per il ComboBox ItemsSource
, per esempio). Tuttavia, questo è un compromesso minore considerando che ora possiamo utilizzarlo in modo simile a un controllo nativo.
Ecco come si può usare CustomComboBox
UserControl:
<Window x:Class="UserControlDemo.UserControlDemo"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:cntrls="clr-namespace:UserControlDemo"
Title="UserControlDemo" Height="240" Width=200>
<Grid>
<cntrls:CustomComboBox HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" Width="165"
MyItemsSource="{Binding Options}"
MySelectedItem="{Binding SelectedOption, Mode=TwoWay}"
DefaultText="Select an option..."/>
<Grid>
</Window>
E il risultato finale:
Ecco l'Inverse NullVisibilityConverter necessario per l'etichetta su UserControl, che è solo una leggera variazione della versione di lll :
public class InverseNullVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return value == null ? Visibility.Visible : Visibility.Hidden;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}