2010-07-16 7 views
0

Je suis nouveau sur ce forum. J'ai un contrôle utilisateur personnalisé défini en utilisant C# et xaml. Lorsque je dag et déposez ce contrôle dans la fenêtre WPF cela fonctionne. Même je peux éditer des étiquettes de code xaml et insérer mon contrôle. Mais quand j'utilise mon contrôle dans le code C#, ça ne marche pas.Pourquoi je ne peux pas utiliser mon contrôle WPF personnalisé dans le code C#

ici est ma définition de contrôle de XAML

<ResourceDictionary 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:local="clr-namespace:UserControl" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> 
    <!-- Resource dictionary entries should be defined here. --> 
    <Style TargetType="{x:Type local:WellImage}"> 
    <Setter Property="Focusable" Value="false" /> 
    <Setter Property="Template"> 
     <Setter.Value> 
     <ControlTemplate TargetType="{x:Type local:WellImage}"> 
      <Grid Width="Auto" Height="Auto"> 
      <Ellipse Stroke="{Binding Path=WellBorder, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}" 
        StrokeThickness="{Binding Path=WellBorderThickness, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}" 
        x:Name="Border" Width="Auto" Height="Auto" 
        HorizontalAlignment="Stretch" VerticalAlignment="Stretch" 
        Fill="{Binding Path=OuterBackGround, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}" /> 
      <Ellipse StrokeThickness="0" Margin="25,37,25,18" RenderTransformOrigin="0.5,0.5" 
        Fill="{Binding Path=InnerBackGround, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}"/> 
      </Grid> 
     </ControlTemplate> 
     </Setter.Value> 
    </Setter> 
    </Style> 
</ResourceDictionary> 

et voici ma c définition # contrôle

using System; 
using System.Collections.Generic; 
using System.Text; 
using System.Windows; 
using System.Windows.Controls; 
using System.Windows.Data; 
using System.Windows.Documents; 
using System.Windows.Input; 
using System.Windows.Media; 
using System.Windows.Media.Imaging; 
using System.Windows.Shapes; 

namespace UserControl 
{ 
    public class WellImage : System.Windows.Controls.Button 
    { 
    public static readonly DependencyProperty InnerBackGroundProperty = DependencyProperty.Register("InnerBackGround", typeof(RadialGradientBrush), typeof(WellImage)); 
    public static readonly DependencyProperty OuterBackGroundProperty = DependencyProperty.Register("OuterBackGround", typeof(RadialGradientBrush), typeof(WellImage)); 
    public static readonly DependencyProperty WellBorderProperty = DependencyProperty.Register("WellBorder", typeof(SolidColorBrush), typeof(WellImage)); 
    public static readonly DependencyProperty WellBorderThicknessProperty = DependencyProperty.Register("WellBorderThickness", typeof(double), typeof(WellImage)); 

    public WellImage() 
    { 
     // Insert code required on object creation below this point. 
     InnerBackGround = (RadialGradientBrush)this.Resources["WellSelectedInnerCircleBrush"]; 
     OuterBackGround = (RadialGradientBrush)this.Resources["WellSelectedOuterCircleBrush"]; 
     WellBorder = (SolidColorBrush)this.Resources["NormalBackgroundBrush"]; 
     WellBorderThickness =2; 
    } 

    static WellImage() 
    { 
     //This OverrideMetadata call tells the system that this element wants to provide a style that is different than its base class. 
     //This style is defined in themes\generic.xaml 
     DefaultStyleKeyProperty.OverrideMetadata(typeof(WellImage), new FrameworkPropertyMetadata(typeof(WellImage))); 
    } 

    public RadialGradientBrush InnerBackGround 
    { 
     get { return (RadialGradientBrush)GetValue(InnerBackGroundProperty); } 
     set { SetValue(InnerBackGroundProperty, value); } 
    } 

    public RadialGradientBrush OuterBackGround 
    { 
     get { return (RadialGradientBrush)GetValue(OuterBackGroundProperty); } 
     set { SetValue(OuterBackGroundProperty, value); } 
    } 

    public SolidColorBrush WellBorder 
    { 
     get { return (SolidColorBrush)GetValue(WellBorderProperty); } 
     set { SetValue(WellBorderProperty, value); } 
    } 

    public double WellBorderThickness 
    { 
     get { return (double)GetValue(WellBorderThicknessProperty); } 
     set { SetValue(WellBorderThicknessProperty, value); } 
    } 
    } 
} 

et voici comment tenté d'accéder à cette controll via C#

WellImage image = new WellImage();    
     image.Height = 40; 
     image.Width = 40; 
     image.Margin = new Thickness(30, 30, 30, 30); 
     image.VerticalAlignment = VerticalAlignment.Top; 
     image.HorizontalAlignment = HorizontalAlignment.Left; 
     image.Content = "WellButton"; 
     grid.Children.Insert(0, image); 
     grid.Background = Brushes.LightBlue; 
     grid.Width = 120; 
     grid.Height = 100; 
     grid.VerticalAlignment = VerticalAlignment.Top; 
     grid.HorizontalAlignment = HorizontalAlignment.Left; 
     gridPartialedMicroPlate.Children.Insert(0, grid); 

Pourquoi je n'arrive pas à accéder à mon contrôle?

+0

Quel est le message d'erreur que vous recevez lorsque vous essayez de l'appeler par programme? – Aaronontheweb

+0

Salut Peter, votre code compile-t-il? Je veux dire le code où vous montrez comment vous avez essayé d'y accéder, est-ce que cela compile? IntelliSense trouve-t-il l'objet image après l'avoir créé? Ou voulez-vous dire que si vous utilisez le débogueur, vous ne le voyez jamais construit? – jameschinnock

Répondre

3

Vous avez trois principaux problèmes:

  1. Votre InnerBackground, OuterBackground et WellBorder sont toujours nulles,
  2. Vous avez pas ContentPresenter dans votre modèle,
  3. Vos points de suspension sont nuls taille

Brosses nulles

La raison pour laquelle InnerBackground, OuterBackground et WellBorder sont null est que vous les définissez à null dans le constructeur. Par exemple, cette ligne est un problème:

InnerBackGround = (RadialGradientBrush)this.Resources["WellSelectedInnerCircleBrush"]; 

Il y a deux problèmes avec cette ligne:

  1. Il utilise this.Resoures [], qui ne regarde que dans le ResourceDictionary local. Pour faire l'équivalent de StaticResource, vous devez regarder dans ResourceDictionaries de vos ancêtres, ce qui signifie que vous devez appeler FindResource().
  2. Il est dans le constructeur, donc il s'exécute avant que le contrôle a un parent. Comme il n'y a pas d'ancêtre à ce stade, même FindResource() ne fonctionnerait pas pour vous.

La meilleure solution à ce problème est de définir ces propriétés dans le style plutôt que dans le constructeur:

<Style TargetType="{x:Type local:WellImage}"> 
    <Setter Property="Focusable" Value="false" /> 
    <Setter Property="InnerBackground" Value="{DynamicResource WellSelectedInnerCircleBrush}" /> 
    ... 

Si vous voulez vraiment faire dans le constructeur, vous pouvez construire une référence DynamicResource il:

SetValue(InnerBackgroundProperty, 
    new DynamicResourceExtension("WellSelectedInnerCircleBrush") 
    .ProvideValue()); 

manquant ContentPresenter

Si vous aviez inclus un ContentPresenter dans votre modèle, vous auriez vu la chaîne "WellButton" s'afficher même si les ellipses auraient été invisibles.

Vous devez envisager de modifier votre ControlTemplate pour inclure un ContentPresenter afin d'afficher la propriété Content. Il semble inutile d'assigner la propriété Content mais de ne pas l'afficher.

ellipses de taille nulle

Chaque ellipse est définie avec une largeur = "Auto" Hauteur = "Auto", ce qui signifie une ellipse taille zéro. Cela rendra vos ellipses invisibles même si elles ont des pinceaux.

La grille est également définie avec Width = "Auto" Height = "Auto", ce qui signifie que son contenu doit être comprimé dans le plus petit espace possible. Cela signifie que si le WellButton est défini avec VerticalAlignment = "Stretch" ou HorizontalAlignment = "Stretch", il refusera obstinément de s'étirer. C'est une mauvaise chose dans un contrôle personnalisé.

Supprimez les deux endroits où vous dites Largeur = "Auto" et Hauteur = "Auto", et laissez la hauteur et la largeur non définies.

Autres questions et nitpicks

Votre deuxième ellipse a StrokeThickness = « 0 » qui n'a aucun sens pour moi car il n'y a pas la course. Pourquoi ne pas le laisser de côté? Idem pour RenderTransformOrigin car il n'y a pas de RenderTransform.

Votre première ellipse n'a pas besoin de spécifier HorizontalAlignment = "Stretch" VerticalAlignment = "Stretch" car il s'agit de la valeur par défaut.

vos fixations sont beaucoup trop compliquées:

  1. Vous pouvez omettre le « Path = » à moins que le chemin contient des propriétés ci-joints.
  2. Vous pouvez omettre le "Mode = OneWay" puisque c'est la valeur par défaut, mais le plus important:
  3. Vous pouvez utiliser un TemplateBinding au lieu qui est beaucoup plus propre:

syntaxe TemplateBinding:

<Ellipse Stroke="{TemplateBinding WellBorder}" 
     ... /> 

Les marges sur votre deuxième ellipse sont si grandes que même si la largeur = "40" Hauteur = "40" dans votre code C# ont été honorées (parce que le problème Auto a été résolu), l'ellipse n'aurait toujours pas de taille. Aussi, il semble étrange d'avoir une ellipse avec une marge si inhabituelle. Nitpick: "Background" est un seul mot anglais, et il n'a pas un G majuscule au milieu.

+0

Excellente réponse !! +1 !! – jameschinnock

+0

Ouais c'est une excellente réponse. Merci Ray. – Peter

+0

@Peter: Content que je puisse aider. En passant, si vous pensez que c'est la meilleure réponse à votre question, vous devez cliquer sur la coche pour la marquer comme la meilleure réponse. Cela nous donne à la fois des points "rep", cela fait apparaître votre "réponse%", et cela aide les autres à reconnaître la meilleure réponse. –

Questions connexes