2017-10-17 16 views
-1

Travailler sur une zone de liste déroulante qui affiche une liste des arrière-plans de tuiles disponibles. Ceci est juste un ComboBox simple avec un ensemble ItemSource à une collection d'objets MapTileBackground.La liaison WPF dans le modèle de données ne fonctionne pas pour la classe personnalisée

La classe MapTileBackground est définie entièrement avec des propriétés:

public partial class MapTileBackground 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
    public string Description { get; set; } 
    public byte[] Content { get; set; } 
    public Nullable<int> Color { get; set; } 
    public int StrokeColor { get; set; } 
    public byte StrokeThickness { get; set; } 
} 

qui est défini dans une bibliothèque séparée et je préférerais changer pas.

I ont défini une simple extension de forme pour dessiner le fond ::

public class MapTileBackgroundPreview : Shape 
{ 
    public static readonly DependencyProperty SizeProperty = DependencyProperty.Register("Size", typeof(Point), typeof(MapTileBackgroundPreview)); 
    public static readonly DependencyProperty TileBackgroundProperty = DependencyProperty.Register("TileBackground", typeof(MapTileBackground), typeof(MapTileBackgroundPreview)); 
    public MapTileBackgroundPreview() 
    { 
     layout = new Hex.Layout(Hex.Orientation.Flat, new Hex.Point(8, 8), new Hex.Point(4, 4)); 
     Size = new Point(8, 8); 
     TileBackground = null; 
    } 

    private Hex.Layout layout; 
    protected override Geometry DefiningGeometry 
    { 
     get 
     { 
      var points = layout.HexCorners(0, 0).ToArray(); 
      var path = new PathFigure(); 
      path.StartPoint = points[5].ToWin(); 
      for (var i = 0; i < 6; i++) 
       path.Segments.Add(new LineSegment(points[i].ToWin(), true)); 

      var geo = new PathGeometry(); 
      geo.Figures.Add(path); 
      return geo; 
     } 
    } 
    public Point Size 
    { 
     get 
     { 
      return (Point)GetValue(SizeProperty); 
     } 
     set 
     { 
      SetValue(SizeProperty, value); 
      layout.Size = value.ToHex(); 
      layout.Origin = new Hex.Point(layout.Size.X/2, layout.Size.Y/2); 
     } 
    } 

    public MapTileBackground TileBackground 
    { 
     get 
     { 
      return (MapTileBackground)GetValue(TileBackgroundProperty); 
     } 
     set 
     { 
      SetValue(TileBackgroundProperty, value); 

      if (value == null) 
      { 
       Fill = Brushes.Transparent; 
       Stroke = Brushes.Black; 
       StrokeThickness = 1; 
      } 
      else 
      { 
       Stroke = value.Stroke(); 
       StrokeThickness = value.StrokeThickness(); 
       Fill = value.Fill(layout.Orientation); 
      } 
     } 
    } 
} 

La disposition est tout simplement un utilitaire de conversion entre les coordonnées de pixels de l'écran et d'un système hexagonal. DefiningGeometry ajoute simplement 6 segments de ligne de l'hexagone. Le setter TileBackground, lorsqu'il reçoit un MapTileBackground non nul, met à jour le contour et le remplissage comme définit l'arrière-plan. J'ai testé ce contrôle avec succès (en dehors du modèle de données de la zone de liste déroulante).

Et en parlant de:

<DataTemplate x:Key="TileListItemRenderer"> 
    <Grid Width="225"> 
     <Grid.RowDefinitions> 
      <RowDefinition Height="Auto"/> 
     </Grid.RowDefinitions> 
     <Grid.ColumnDefinitions> 
      <ColumnDefinition Width="24"/> 
      <ColumnDefinition Width="75"/> 
      <ColumnDefinition /> 
     </Grid.ColumnDefinitions> 
     <local:MapTileBackgroundPreview Grid.Row="0" Grid.Column="0" Size="12,12" VerticalAlignment="Center" HorizontalAlignment="Center" TileBackground="{Binding /}"/> 
     <Label Grid.Row="0" Grid.Column="1" Content="{Binding Name}" HorizontalAlignment="Left" VerticalAlignment="Center" FontWeight="Bold"/> 
     <TextBlock Grid.Row="0" Grid.Column="2" Text="{Binding Description}" HorizontalAlignment="Stretch" VerticalAlignment="Top" TextWrapping="Wrap" /> 
    </Grid> 
</DataTemplate> 

Je viens donc de créer une forme, et deux étiquettes, lier la forme à l'objet MapTileBackground actuelle (zone de liste déroulante ItemSource est une collection d'objets MapTileBackground), et les étiquettes à Nom et description.

Mon problème est que la forme est toujours dessinée vide (comme dans TileBackground est null) et le setter n'est jamais invoqué. L'étiquette de nom et le TextBlock de description se comportent comme prévu (afficher le texte correct). Et pendant mes tentatives de débogage, j'ai créé une propriété id sur l'objet de prévisualisation qui invoque à son tour le Setter TileBackground et l'a lié à la propriété Id (éviter la liaison d'objet courante), encore une fois, le setter TileBackgroundId n'est jamais invoqué. J'ai même ajouté une nouvelle étiquette liée à Id pour voir si cela fonctionnait et elle affiche l'identifiant comme prévu. Voici les changements qui n'ont pas encore fonctionné. Les propriétés TileBackgroundId ou TileBackground ne sont jamais définies lors de l'ouverture de la liste déroulante.

<DataTemplate x:Key="TileListItemRenderer"> 
     <Grid Width="225"> 
      <Grid.RowDefinitions> 
       <RowDefinition Height="Auto"/> 
      </Grid.RowDefinitions> 
      <Grid.ColumnDefinitions> 
       <ColumnDefinition Width="24"/> 
       <ColumnDefinition Width="75"/> 
       <ColumnDefinition /> 
      </Grid.ColumnDefinitions> 
      <local:MapTileBackgroundPreview Grid.Row="0" Grid.Column="0" Size="12,12" VerticalAlignment="Center" HorizontalAlignment="Center" TileBackgroundId="{Binding Id}"/> 
      <Label Grid.Row="0" Grid.Column="0" Content="{Binding Id}" HorizontalAlignment="Left" VerticalAlignment="Center" FontWeight="Bold"/> 
      <Label Grid.Row="0" Grid.Column="1" Content="{Binding Name}" HorizontalAlignment="Left" VerticalAlignment="Center" FontWeight="Bold"/> 
      <TextBlock Grid.Row="0" Grid.Column="2" Text="{Binding Description}" HorizontalAlignment="Stretch" VerticalAlignment="Top" TextWrapping="Wrap" /> 
     </Grid> 
    </DataTemplate> 

    public static readonly DependencyProperty TileBackgroundIdProperty = DependencyProperty.Register("TileBackgroundId", typeof(int), typeof(MapTileBackgroundPreview)); 

    public int TileBackgroundId 
    { 
     get 
     { 
      return (int)GetValue(TileBackgroundIdProperty); 
     } 
     set 
     { 
      SetValue(TileBackgroundIdProperty, value); 
      TileBackground = TMapTileBackgroundTool.Get(value); 
     } 
    } 

TMapTileBackgroundTool.Get() renvoie l'objet correct en fonction de l'ID.

J'ai également testé des instances de MapTileBackgroundPreview en définissant TileBackgroundId en dehors du modèle de données.

Des idées sur ce qui se passe?

+0

Pouvez-vous partager la 'Hex'?ou l'enlever dans le code ci-dessus? – Iron

+0

Dans ce contexte, Hex est un alias d'espace de noms. – David

Répondre

1

Le poseur de l'emballage CLR pour la propriété de dépendance n'est pas censé être défini comme le moteur de liaison WPF appelle les GetValue et SetValue méthodes directement:

Setters not run on Dependency Properties?

Why are .NET property wrappers bypassed at runtime when setting dependency properties in XAML?

Le getter et setter de la propriété wrapper CLR seulement appeler respectivement la méthode GetValue et SetValue.

Si vous voulez faire quelque chose lorsque la propriété de dépendance est définie, vous devez enregistrer un rappel:

public static readonly DependencyProperty TileBackgroundIdProperty = DependencyProperty.Register("TileBackgroundId", typeof(int), typeof(MapTileBackgroundPreview), 
    new PropertyMetadata(0, new PropertyChangedCallback(TileBackgroundIdChanged))); 

public int TileBackgroundId 
{ 
    get 
    { 
     return (int)GetValue(TileBackgroundIdProperty); 
    } 
    set 
    { 
     SetValue(TileBackgroundIdProperty, value); 
    } 
} 

private static void TileBackgroundIdChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
{ 
    MapTileBackgroundPreview ctrl = (MapTileBackgroundPreview)d; 
    ctrl.TileBackground = TMapTileBackgroundTool.Get((int)e.NewValue); 
} 
+0

Je ne peux pas croire que je n'ai pas rencontré cela lors de la recherche d'une réponse ou de recherche de liaison de données, donc totalement ma faute. Appréciez la réponse rapide. Quoi qu'il en soit, j'ai ré-implémenté les trois propriétés en utilisant les événements de changement et lors de la liaison Id à TileBackgroundId tout fonctionne. Lors de la liaison à TileBackground, je n'ai toujours rien. Je peux vivre avec la propriété int basée, je me demande juste pourquoi cela ne fonctionne pas dans la deuxième voie. Merci. – David