Ошибка привязки данных WPF в свойстве Tag

1
<UserControl xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:local="clr-namespace:son"
         x:Class="son.SonWindow">
    <Grid x:Name="myGrid">
        <Grid.Tag>
            <Label Content="{Binding ActualWidth, ElementName=myGrid}" />
        </Grid.Tag>
    </Grid>
</UserControl>

Как простой код выше, но привязка не может найти элемент myGrid. Во время выполнения ошибка отображается в окне вывода

"System.Windows.Data Error: 4: Не удается найти источник для привязки с ссылка 'ElementName = myGrid'. BindingExpression: Path = ActualWidth; DataItem = NULL; целевым элементом является" Метка "(Name= ''); целевое свойство" Содержимое "(тип" Объект ")"

Я использую версию сообщества Visual Studio 2015 с .Net Framework 4.5.2. Есть идеи? Заранее благодарю вас.

  • 0
    Почему вы помещаете Label в свойство Tag? Если вы переместите элемент Label за пределы тега, он будет работать.
  • 0
    @benPearce ya .. Я понимаю, что простое удаление тега заставит его работать, но мне интересно, почему приведенный выше код вызовет ошибку. Я просто хочу выяснить, связана ли ошибка с чем-то особенным из свойства Tag.
Теги:
wpf
data-binding

3 ответа

11
Лучший ответ

Элемент (свойство которого привязан) должен быть частью визуального дерева, чтобы можно было выполнить визуальный поиск дерева. При использовании привязки с ElementName или RelativeSource он выполняет некоторый внутренний поиск визуального дерева. Но в вашем коде Label отключен от визуального дерева с помощью Tag. Label - это просто объект в памяти, на который ссылается свойство Tag.

Начиная с .NET 4.0 вы можете использовать разметку {x:Reference}, например:

<Grid.Tag>
    <Label Content="{Binding ActualWidth, Source={x:Reference myGrid}}" />
</Grid.Tag>

Edit

Использование {x:Reference} может вызвать проблему циклической зависимости, если имя ссылки указывает на некоторый элемент, содержащий {x:Reference}. В вашем случае это myGrid (содержащий {x:Reference}). Поэтому его нельзя использовать в вашем случае. Вместо этого вам нужно использовать некоторый прокси. Этот метод кажется немного взломанным, но на самом деле он очень красив. Он также наверняка работает в любой версии .NET(поддерживающей WPF):

<Grid x:Name="myGrid">
    <Grid.Resources>
        <DiscreteObjectKeyFrame x:Key="proxy" Value="{Binding ElementName=myGrid}"/>
    </Grid.Resources>
    <Grid.Tag>
        <Label Content="{Binding Value.ActualWidth, Source={StaticResource proxy}}" />
    </Grid.Tag>
</Grid>

Как вы видите, Binding работает со своим Source, установленным на StaticResource, указывающим на DiscreteObjectKeyFrame. Это объект Freezable, поэтому довольно интересно, что все Bindings, установленные для любого DependencyProperty объекта Freezable, хорошо работают независимо от того, используете ли вы ElementName или RelativeSource. Поэтому мы привязываем его свойство Value к Grid (с именем myGrid). Позже мы привязываем свойство Content объекта Label к объекту Freezable, но с Path, установленным в Value.ActualWidth (Value указывает на Grid), поэтому нам нужно добавить ActualWidth, чтобы связать его до Grid.ActualWidth).

Фактически вы можете использовать любой объект Freezable, но для удобства мы используем DiscreteObjectKeyFrame, его Value принимает все типы object.

Существует еще один способ установки привязки в такой ситуации (отключенный контекст), но для этого требуется создать пользовательский MarkupExtension. Это, конечно, сложнее (но все же достаточно просто, как только вы знакомы с WPF).

  • 0
    Спасибо за вашу помощь. Я заменяю свой код на ваш. Однако во время разработки я получил ссылку на объект ошибки, не установленную для экземпляра объекта . А во время выполнения в окне «Вывод» отображается исключение.
  • 0
    Исключением является исключение: «System.Windows.Markup.XamlParseException» в PresentationFramework.dll. Необработанное исключение типа «System.Windows.Markup.XamlParseException» возникло в PresentationFramework.dll. Дополнительная информация: Невозможно вызвать MarkupExtension.ProvideValue из-за циклического зависимость. Свойства внутри MarkupExtension не могут ссылаться на объекты, которые ссылаются на результат MarkupExtension. Уязвимые расширения Markup: «System.Windows.Data.Binding», номер строки «7» и позиция строки «20».
Показать ещё 4 комментария
0

Я также пытаюсь реплицировать проблему, но ниже код работает нормально в VS 2010.

<Window x:Class="CustomEventHandlerClick.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:CustomEventHandlerClick"
    Title="MainWindow" Height="350" Width="525">
<Grid>
    <Grid x:Name="myGrid">
        <Grid.Tag>
            <Label Content="{Binding ActualWidth, ElementName=myGrid}"/>
        </Grid.Tag>
    </Grid>
   </Grid>

0

Я попытался найти фрагмент кода в WPF и его работу отлично.

<Window x:Class="WpfApplication1.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="525">
<Grid x:Name="myGrid">
    <Grid.Tag>
        <Label Content="{Binding ActualWidth, ElementName=myGrid}" />
    </Grid.Tag>
</Grid>

  • 1
    этот код выглядит точно так же, как и OP, поэтому вы должны предоставить некоторую информацию о вашей среде, например, о версии .NET, как вы узнали, что она работает? Единственная причина, по которой это может сработать, заключается в том, что в последней версии .NET он может вести себя по-другому (улучшено). По крайней мере, в .NET 4.5 (и более ранних версиях) это не будет работать.
  • 0
    я попробовал ваш фрагмент кода в WPF, но во время выполнения окно вывода снова выдает ту же ошибку, что и выше.
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню