2 votes

Le XAML chargé ne se lie pas correctement aux éléments existants

J'ai un bouton qui charge XAML à partir d'un fichier, crée un contrôle à partir de celui-ci et ajoute ce contrôle comme enfant à un canvas qui fait partie d'un modèle présent dans les ressources d'un dockpanel sur la fenêtre. La fenêtre dispose également d'une combobox nommée cboTColour et d'une combobox nommée cboBColour que j'utilise pour définir un simple dégradé de fond sur mon contrôle chargé.

Je charge le XAML et l'ajoute à mon canevas en utilisant le code suivant :

XmlReader xaml = XmlReader.Create(filename);
newControl = (Viewbox)XamlReader.Load(xaml);
((Canvas)(testButton.Template.FindName("MyCanvas", testButton))).Children.Clear();
((Canvas)(testButton.Template.FindName("MyCanvas", testButton))).Children.Add(newControl);

Et voici le XAML que je charge :

<?xml version="1.0" encoding="utf-8"?>
<Viewbox xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Name="Document" Stretch="Fill">
    <Canvas Height="64" Width="128" ClipToBounds="True">
        <Canvas.Background>
            <!--Horizontal Gradient-->
            <LinearGradientBrush StartPoint="1,0">
                <GradientStop Color="{Binding ElementName=cboTColour, Path=SelectedItem.Name}" Offset="0"></GradientStop>
                <GradientStop Color="{Binding ElementName=cboBColour, Path=SelectedItem.Name}" Offset="1"></GradientStop>
            </LinearGradientBrush>
        </Canvas.Background>
    </Canvas>
</Viewbox>

J'ai essayé de placer le XAML directement dans le concepteur et cela fonctionne parfaitement, ce n'est donc pas un problème. Lorsque je charge le XAML depuis un fichier, les contrôles sont créés et placés correctement, mais la liaison de données ne fonctionne pas - les couleurs ne changent pas. J'obtiens les erreurs suivantes :

System.Windows.Data Error: 4 : Cannot find source for binding with reference 'ElementName=cboTColour'. BindingExpression:Path=SelectedItem.Name; DataItem=null; target element is 'GradientStop' (HashCode=24393646); target property is 'Color' (type 'Color')
System.Windows.Data Error: 4 : Cannot find source for binding with reference 'ElementName=cboBColour'. BindingExpression:Path=SelectedItem.Name; DataItem=null; target element is 'GradientStop' (HashCode=23972246); target property is 'Color' (type 'Color')

Je suppose que ce qui se passe, c'est que lorsque le XAMLReader charge le xaml et crée un contrôle à partir de celui-ci, il n'est pas sûr du chemin vers mes combo-boxes, puisque le xaml ne fait pas encore partie de la fenêtre, et lorsque le contrôle est ajouté à la fenêtre, ce lien n'est pas mis à jour, mais je ne sais pas comment modifier mes liens dans le XAML pour refléter l'emplacement de mes combo-boxes par rapport à lui ou modifier le XAMLReader ou le contexte de données global pour prendre en compte mes contrôles. Je peux également vous assurer que les boîtes combo ont été créées à ce stade, car le code s'exécute lorsqu'on appuie sur un bouton dans la fenêtre où se trouvent les boîtes combo.

Je DOIS préciser que je ne peux pas modifier les liens eux-mêmes dans le code, car les liens apparaîtront à divers endroits et à divers moments dans les différents fichiers XAML que je vais charger.

Toute aide serait très appréciée.

1voto

Wallstreet Programmer Points 6086

Il semble que XamlReader impose des restrictions sur le xaml qu'il charge afin qu'il ne puisse pas contenir de noms d'éléments inconnus non définis dans le xml chargé. A la place, on utilise la liaison de données aux propriétés, ce qui fonctionne bien mais nécessite un peu de code derrière. Le code ci-dessous changera l'arrière-plan du contrôle chargé lorsque l'utilisateur change l'élément sélectionné dans les comboboxes. Vous devez ajouter un convertisseur de valeur qui convertit les couleurs en noms lisibles par l'homme à utiliser par les comboboxes.

XAML :

<StackPanel>
    <ComboBox 
        ItemsSource="{Binding Path=AvailableColors}" 
        SelectedValuePath="Color"
        SelectedValue="{Binding Path=SelectedColors[color0].Color}" />
    <ComboBox 
        ItemsSource="{Binding Path=AvailableColors}" 
        SelectedValuePath="Color"
        SelectedValue="{Binding Path=SelectedColors[color1].Color}" />
    <ContentControl Name="newControl" />
</StackPanel>

Code derrière :

using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Windows;
using System.Windows.Markup;
using System.Windows.Media;
using System.Xml;

namespace LoadTest
{
    public partial class Window1 : Window
    {
        public Window1()
        {
            InitializeComponent();

            SelectedColors = new Dictionary<string, ColorInfo>();
            SelectedColors.Add("color0", AvailableColors.First());
            SelectedColors.Add("color1", AvailableColors.Last());

            XmlReader xaml = XmlReader.Create("newcontrol.xml");
            newControl.Content = XamlReader.Load(xaml);
            newControl.DataContext = SelectedColors;

            DataContext = this;
        }

        public List<ColorInfo> AvailableColors
        {
            get
            {
                return new List<ColorInfo>()
                {
                    new ColorInfo() {Color = Colors.Red },
                    new ColorInfo() { Color = Colors.Green },
                    new ColorInfo() { Color = Colors.Blue },
                    new ColorInfo() { Color = Colors.Yellow }
                };
            }
        }

        public Dictionary<string, ColorInfo> SelectedColors { get; private set;}
    }

    public class ColorInfo : INotifyPropertyChanged
    {
        private Color _color;
        public Color Color
        {
            get { return _color; }
            set 
            {
                _color = value;
                if (PropertyChanged != null)
                {
                    PropertyChanged(this, new PropertyChangedEventArgs("Color"));
                }
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;
    }
}

Fichier XAML à charger (newcontrol.xml) :

<?xml version="1.0" encoding="utf-8"?>
<Viewbox
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  x:Name="Document" Stretch="Fill">
  <Canvas Height="64" Width="128" ClipToBounds="True">
    <Canvas.Background>
      <LinearGradientBrush StartPoint="1,0">
        <GradientStop Color="{Binding Path=[color0].Color}" Offset="0" />
        <GradientStop Color="{Binding Path=[color1].Color}" Offset="1" />
      </LinearGradientBrush>
    </Canvas.Background>
  </Canvas>
</Viewbox>

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X