Contrôle personnalisé OnApplyTemplate appelé après la propriété de dépendance de rappel
Je suis le développement de mon premier WPF contrôle personnalisé et je suis confronté à quelques problèmes, voici une version simplifiée du code que j'utilise actuellement:
using System.Windows;
using System.Windows.Controls;
namespace MyControls
{
[TemplatePart(Name = "PART_Button", Type = typeof (Button))]
public class MyControl : Control
{
public static readonly DependencyProperty ContentProperty = DependencyProperty.Register("Content", typeof (object), typeof (MyControl), new PropertyMetadata(null, OnLabelPropertyChanged));
private Button _buttonElement;
public object Content
{
get { return this.GetValue(LabelProperty); }
set { this.SetValue(ContentProperty, value); }
}
static MyControl()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof (MyControl), new FrameworkPropertyMetadata(typeof (MyControl)));
}
private static void OnContentPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
MyControl myControl = sender as MyControl;
if (myControl != null && myControl._buttonElement != null)
myControl._buttonElement.Content = e.NewValue;
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
this._buttonElement = this.Template.FindName("PART_Button", this) as Button;
}
}
}
C'est le modèle pour mon contrôle personnalisé:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:MyControls">
<Style TargetType="{x:Type local:MyControl}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:MyControl}">
<Button x:Name="PART_Button" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
Puis je l'ai mis à l'intérieur d'une Grille et d'essayer de définir sa propriété de Contenu:
<Grid x:Name="layoutRoot">
<controls:MyControl x:Name="myControl" />
</Grid>
Voici le code behind:
using System.Windows;
namespace MyControls
{
///<summary>
///Interaction logic for MainWindow.xaml
///</summary>
public partial class MainWindow : Window
{
public MainWindow()
{
this.InitializeComponent();
this.myControl.Content = "test";
}
}
}
Cela ne fonctionne pas, pour une raison quelconque, le OnContentPropertyChanged callback est appelée avant OnApplyTemplate, donc myControl._buttonElement est attribué trop tard et c'est toujours null lorsque vous tentez de définir son contenu. Pourquoi est-ce qui se passe et comment puis-je changer ce comportement?
J'ai également besoin de fournir à plein temps pour la conception de soutien, mais je ne peux pas trouver un moyen de faire mon contrôle personnalisé accepter certains additionnelle, à l'instar de la Grille de contrôle avec ColumnDefinitions:
<Grid x:Name="layoutRoot">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
</Grid>
Toute aide serait grandement appréciée!
Mise à JOUR
J'ai trouvé un document qui explique pourquoi le OnApplyTemplate méthode est appelée après contrôle properies sont définies:
http://msdn.microsoft.com/en-us/library/dd351483%28v=vs.95%29.aspx
La question est donc: comment puis-je suivre les propriétés qui sont définies (en XAML ou par programmation) et les méthodes qui sont appelées lorsque le contrôle n'a pas été initialisé, de sorte que je peux/les appeler quand le OnApplyTemplate méthode est appelée? Comment peut-on le même rappel de méthode, de travail à la fois avant et après l'initialisation du contrôle sans dupliquer le code?
OriginalL'auteur Kupido | 2012-08-06
Vous devez vous connecter pour publier un commentaire.
Mise à JOUR:
À la place de votre "propriété" de pousser des changements dans la valeur des éléments de votre modèle en la recherche de Pièces, il est préférable d'avoir votre modèle de lier les propriétés sur le contrôle basé sur un modèle.
Normalement, cela est fait en utilisant les présentateurs à l'intérieur d'un modèle par exemple
ContentPresenter
lie à la propriété désignée comme le "contenu" (ce qu'il découvre que nom par la recherche de la[ContentProperty]
attribut), et en utilisant des liaisons dans votre modèle qui utilisentTemplateBinding
ouTemplatedParent
connecter les propriétés de votre contrôle personnalisé.Alors il n'y a aucune question à propos de quel ordre vous définissez vos propriétés et lorsque le modèle est appliqué....parce que c'est le modèle qui offre le "look" pour les données/le jeu de propriétés sur votre contrôle.
Un contrôle personnalisé ne devrait vraiment besoin de connaître et d'interagir avec les "parties" s'il est nécessaire de fournir un certain comportement/fonctionnalités par exemple accroche de l'événement de clic sur un bouton "partie".
Dans ce cas, au lieu de définir le Contenu dans le constructeur dans le code-behind, vous devriez obtenir votre modèle à lier à la propriété. L'exemple que j'ai donné ci-dessous a montré comment cela se fait généralement avec un Contenu bien.
Sinon, vous pouvait tirer de propriétés plus explicitement, par exemple, ce pourrait être à l'intérieur de votre modèle.
Je pense qu'il serait préférable de désigner votre "contenu" à l'aide de [ContentProperty] attribut, puis à l'aide d'un ContentPresenter dans votre modèle de sorte qu'il peut être injecté à l'intérieur de votre Bouton, plutôt que de vous accrocher votre Contenu DependencyProperty. (si vous héritez de ContentControl alors que fournit le "contenu" du comportement).
et
Que pour vous qui veulent être en mesure de préciser certaines données au moment du design via XAML comme Grille avec ColumnDefinition....eh bien, c'est juste l'aide de la Propriété de l'Élément de syntaxe pour spécifier les éléments à remplir un IList/ICollection tapé propriété.
Donc tout simplement créer votre propre propriété qui peut contenir une collection de type, vous acceptez par exemple
Honnêtement, à l'aide de l'événement Chargé ne semble pas la bonne façon de le faire... pourquoi n'est-ce pas nécessaire lors de l'utilisation de Microsoft ou de tiers, les contrôles?
En utilisant objet templatebinding n'est pas toujours possible pour moi, lors de l'ajout d'axes et de série I ont besoin pour accéder au sous-jacents au contrôle de graphique, de sorte que le modèle de partie doit déjà être disponible. J'ai partiellement résolu en utilisant l'astuce expliqué ici stackoverflow.com/questions/1298898/..., mais maintenant je vais avoir des problèmes avec les liaisons parce que les contrôles enfants ne sont pas ajoutés à l'arborescence logique. J'appelle AddLogicalChild/RemoveLogicalChild dans les axes/série événement CollectionChanged gestionnaire, mais ce n'est pas de travail.
OriginalL'auteur Colin Smith
J'ai rencontré le même problème,
OnApplyTemplate
a été appelé avantOnLoaded
.Le problème était dû à la liaison dans le code xaml. J'ai lié propriété booléenne à
Checked
au lieu deIsChecked
sur l'un de mes cases à cocher.OriginalL'auteur JanBrus