Загруженный XAML не привязан к существующим элементам правильно - PullRequest
2 голосов
/ 20 июля 2010

У меня есть кнопка, которая загружает XAML из файла, создает из него элемент управления и добавляет его в качестве дочернего элемента к холсту, который является частью шаблона, присутствующего в ресурсах панели док-станции в окне. В этом окне также есть поле со списком cboTColour и поле со списком cboBColour, которое я использую, чтобы установить простой градиентный фон в загруженном элементе управления.

Я загружаю XAML и добавляю его на свой холст, используя следующий код:

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);

А вот XAML, который я загружаю:

<?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>

Я попытался вставить XAML прямо в конструктор, и он отлично работает, поэтому с этим проблем нет. Когда я загружаю XAML из файла, элементы управления создаются и размещаются правильно, но привязка данных не работает - цвета не меняются. Я получаю следующие ошибки:

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')

Я предполагаю, что происходит, когда XAMLReader загружает объявление xaml, создает элемент управления из него, оно не уверено в пути к моим комбинированным спискам, поскольку xaml еще не является частью окна, и когда элемент управления При добавлении в окно эта привязка не обновляется, но я не знаю, как либо изменить свои привязки в XAML, чтобы отразить расположение моих комбо-боксов по отношению к нему, либо изменить XAMLReader или общий текстовый текст для принятия во внимание мои элементы управления. Я также могу заверить вас, что комбо-боксы были созданы к этому моменту, так как код запускается при нажатии кнопки в окне, в котором находятся комбо-боксы.

Я ДОЛЖЕН указать, что НЕ МОГУ изменить сами привязки в коде, так как привязки будут появляться в разных местах и ​​в разное время в разных файлах XAML, которые я буду загружать.

Любая помощь будет высоко ценится.

1 Ответ

1 голос
/ 21 июля 2010

Похоже, XamlReader наложил ограничения на загружаемый xaml, чтобы он не мог содержать неизвестные имена элементов, не определенные в загруженном xml Вместо этого используйте привязку данных к свойствам, которая работает нормально, но требует некоторого кода позади. Код ниже изменит фон на загруженном элементе управления, когда пользователь изменит выбранный элемент в выпадающих списках. Вам необходимо добавить конвертер значений, который преобразует цвета в удобочитаемые имена, которые будут использоваться в выпадающих списках.

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>

Код:

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;
    }
}

XAML-файл для загрузки (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>
...