Ошибка привязки в XmlDataProvider (невозможно привязать к объекту, отличному от XML)

У меня проблема с привязкой некоторых элементов управления к моему XML.
Мое приложение заполняет TabControl во время выполнения, загружая XAML для TAB с помощью DataTemplateSelector:

class TemplateSelector : DataTemplateSelector
{
  public override DataTemplate SelectTemplate(object item, DependencyObject container)
  {
    if (item != null)
    {
      string templateFile = string.Format("Templates/{0}", 
                                          Properties.Settings.Default.AppId + ".tmpl");
      if (File.Exists(templateFile))
      {
        FileStream fs = new FileStream(templateFile, FileMode.Open);
        DataTemplate template = XamlReader.Load(fs) as DataTemplate;

        Tab tab = item as Tab;
        XmlDataProvider xmlDataProvider = template.Resources["dataProvider"] as XmlDataProvider;
        xmlDataProvider.XPath = tab.BridgeObj.XmlFilePath;

        return template;
      }
    }
    return null;
  }
}

XAML:

<DataTemplate
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:EurocomCPS;assembly=EurocomCPS">

  <DataTemplate.Resources>
    <local:StringToBoolConverter x:Key="StrToBoolConverter" />
    <local:StringToIntConverter  x:Key="StrToIntConverter" />
    <XmlDataProvider x:Key="dataProvider" XPath="func/parametri/param/BLOCKS"/>
  </DataTemplate.Resources>

  <Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto" />
        <RowDefinition Height="Auto" />
        <RowDefinition Height="Auto" />
        <RowDefinition Height="Auto" />
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="100" />
        <ColumnDefinition Width="Auto" />
    </Grid.ColumnDefinitions>

    <Label Grid.Row="0" Grid.Column="0" Content="ITEM 1:"/>
    <Label Grid.Row="1" Grid.Column="0" Content="ITEM 2:"/>
    <Label Grid.Row="2" Grid.Column="0" Content="ITEM 3:"/>

    <TextBox  Name="TextBox1"
              Grid.Row="0" 
              Grid.Column="1" 
              Text="{Binding XPath='//BLOCK[@id=1]/ITEMS/ITEM[@id=1]/@value'}" />
    <CheckBox Grid.Row="1" 
              Grid.Column="1"
              IsChecked="{Binding XPath='//BLOCK[@id=1]/ITEMS/ITEM[@id=2]/@value',
                            Converter={StaticResource StrToBoolConverter}}"/>

    <CheckBox Grid.Row="2" 
              Grid.Column="1"
              IsChecked="{Binding XPath='//BLOCK[@id=1]/ITEMS/ITEM[@id=3]/@value',
                            Converter={StaticResource StrToBoolConverter}}"/>

  </Grid>
</DataTemplate>

Каждая страница содержит XmlDataProvider, который загружает следующий XML-файл:

<func id="A29086">
  <parametri>
    <param>
      <BLOCKS max_count="2" write_id="49" read_req_id="47" read_rep_id="48" session_id="7">
        <BLOCK id="1" frame="1" framelen="61">
          <ITEMS max_count="14">
            <ITEM id="1" type="CHAR" size="1" value="0" />
            <ITEM id="2" type="CHAR" size="1" value="1" />
            <ITEM id="3" type="CHAR" size="1" value="0" />
            ...
          </ITEMS>
        </BLOCK>
        <BLOCK id="2" frame="1" framelen="61">
          <ITEMS max_count="14">
            <ITEM id="1" type="CHAR" size="1" value="0" />
            <ITEM id="2" type="CHAR" size="1" value="1" />
            ...
          </ITEMS>
        </BLOCK>
      </BLOCKS>
    </param>
  </parametri>
</func>

При запуске я получаю эту ошибку:

System.Windows.Data Error: 44 : BindingExpression with XPath cannot bind to non-XML object.; XPath='//BLOCK[@id=1]/ITEMS/ITEM[@id=1]/@value' BindingExpression:Path=/InnerText; DataItem='Tab' (HashCode=57706919); target element is 'TextBox' (Name=''); target property is 'Text' (type 'String') Tab:'EurocomCPS.Tab'
System.Windows.Data Error: 44 : BindingExpression with XPath cannot bind to non-XML object.; XPath='//BLOCK[@id=1]/ITEMS/ITEM[@id=2]/@value' BindingExpression:Path=/InnerText; DataItem='Tab' (HashCode=57706919); target element is 'CheckBox' (Name=''); target property is 'IsChecked' (type 'Nullable`1') Tab:'EurocomCPS.Tab'
System.Windows.Data Error: 44 : BindingExpression with XPath cannot bind to non-XML object.; XPath='//BLOCK[@id=1]/ITEMS/ITEM[@id=3]/@value' BindingExpression:Path=/InnerText; DataItem='Tab' (HashCode=57706919); target element is 'CheckBox' (Name=''); target property is 'IsChecked' (type 'Nullable`1') Tab:'EurocomCPS.Tab'

--- РЕДАКТИРОВАТЬ ---

Я добавляю DataContext к своим элементам управления, но у меня все еще есть проблемы.
Во-первых, я получаю следующее:

System.Windows.Data Error: 44 : BindingExpression with XPath cannot bind to non-XML object.; XPath='//BLOCK[@id=1]/ITEMS/ITEM[@id=1]/@value' BindingExpression:Path=/InnerText; DataItem='Tab' (HashCode=46144604); target element is 'TextBox' (Name=''); target property is 'Text' (type 'String') Tab:'EurocomCPS.Tab'
System.Windows.Data Error: 44 : BindingExpression with XPath cannot bind to non-XML object.; XPath='//BLOCK[@id=1]/ITEMS/ITEM[@id=1]/@value' BindingExpression:Path=/InnerText; DataItem='Tab' (HashCode=46144604); target element is 'TextBox' (Name='TextBox1'); target property is 'Text' (type 'String') Tab:'EurocomCPS.Tab'

И я не понимаю, что такое первое "безымянное" текстовое поле, которое нигде не определено.

Во-вторых, если я добавлю конвертер в привязку TextBox (например, тот, который я использую для CheckBox), я не получу ошибку.

В третьих функции конвертера не называются.

3 ответа

Решение

Предполагая, что вы как-то загружаете XML в XmlDataProviderкак я не вижу Source определяется где угодно, ваш XPath хорошо, но вы не предоставляете Source для вашей привязки. Это должно работать, если вы измените его на что-то вроде этого:

<TextBlock Text="{Binding Source={StaticResource dataProvider}, XPath='//BLOCK[@id=1]/ITEMS/ITEM[@id=2]/@value'}"/>

если вы не укажете источник по умолчанию, он будет выглядеть в DataContext,

Проблема заключалась в методе, используемом для назначения файла XML!

xmlDataProvider.XPath = tab.BridgeObj.XmlFilePath;

Меняя его на

xmlDataProvider.Source = new Uri(tab.BridgeObj.XmlFilePath);

решил.

Я думаю, что '@id=1' не является правильным способом сделать это в соответствии с блогом.

Другие вопросы по тегам