Ошибки привязки xaml

I’m getting this in my output Window:

System.Windows.Data Error: 4 : Cannot find source for binding with reference ‘RelativeSource FindAncestor, AncestorType=’System.Windows.Controls.ItemsControl’, AncestorLevel=’1». BindingExpression:Path=VerticalContentAlignment; DataItem=null; target element is ‘ListBoxItem’ (Name=»); target property is ‘VerticalContentAlignment’ (type ‘VerticalAlignment’)

This is my XAML, which when run looks correct

        <GroupBox Header="Grant/Deny Report">
            <ListBox ItemsSource="{Binding  Converter={StaticResource MethodBinder}, ConverterParameter=GrantDeny, Mode=OneWay}">
                <ListBox.ItemTemplate>
                    <DataTemplate>
                        <StackPanel Orientation="Horizontal">
                            <Label Content="{Binding Entity}"/>
                            <Label Content="{Binding HasPermission}"/>
                        </StackPanel>
                    </DataTemplate>
                </ListBox.ItemTemplate>
            </ListBox>
        </GroupBox>

asked Jun 5, 2010 at 18:36

Jonathan Allen's user avatar

Jonathan AllenJonathan Allen

68.5k70 gold badges260 silver badges447 bronze badges

I was also going to recommend Bea Stollnitz’s article but Jonathan Allen got his post in while I was still typing this one. I also recommend the links in this blog entry.

In this particular case you can see that somewhere a ListBoxItem has a FindAncestor binding to an ItemsControl that is failing. That tells you right away there is a ListBoxItem somewhere that is either:

  1. Not in the visual tree, or
  2. Not under an ItemsControl (a ListBox is an ItemsControl)

In addition, you know that someone, somewhere, is binding a ListBoxItem’s VerticalContentAlignment property to FindAncestor.

Looking at the system themes (shipped with Expression Blend and also available through NET Reflector’s BAMLViewer Add-in), we see this:

<Style x:Key="{x:Type ListBoxItem}">
  <Setter Property="VerticalContentAlignment"
          Value="{Binding Path=VerticalContentAlignment,RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}" />

This explains where the binding comes from. The next question is, how is a ListBoxItem being created that is not under a ListBox (or other ItemsControl)?

Some things to look for:

  • Are you constructing ListBoxItems in code anywhere?
  • Is there any ListBoxItem explicitly specified in your XAML?
  • Do you have any code that manually manipulates the items in ListBox?

Hopefully this will head you in the right direction.

answered Jun 5, 2010 at 19:17

Ray Burns's user avatar

Ray BurnsRay Burns

62.2k12 gold badges140 silver badges141 bronze badges

2

I ran into a similar problem with the TreeView (though my data binding errors showed up as being Informational).

I solved the problem by defining an implicit style in the TreeView resource for TreeViewItem. Within that style I defined the missing vertical and horizontal content alignment properties.

<TreeView.Resources>
     <Style TargetType="{x:Type TreeViewItem}" >
          <Setter Property="VerticalContentAlignment" Value="Stretch"/>
          <Setter Property="HorizontalContentAlignment" Value="Stretch"/>
     </Style>
</TreeView.Resources>

answered Oct 31, 2011 at 15:12

miko's user avatar

1

kotelok

1029 / 645 / 215

Регистрация: 08.08.2014

Сообщений: 2,042

1

10.01.2020, 21:54. Показов 5257. Ответов 6

Метки нет (Все метки)


Студворк — интернет-сервис помощи студентам

Работает, все элементы отрисовывает в ожидаемых позициях, но при этом каждый раз сообщает:

System.Windows.Data Error: 2 : Cannot find governing FrameworkElement or FrameworkContentElement for target element. BindingExpression: (no path); DataItem=null; target element is ‘EllipseGeometry’ (HashCode=29135240); target property is ‘Center’ (type ‘Point’)

Подскажите, в чём суть и как это исправить? Наугад попробовал разные комбинации ‘ElementName’ и ‘RelativeSource’, не помогло.

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
    public partial class MainWindow : Window
    {
        public CompositeCollection Shapes { get; set; }
 
        public MainWindow()
        {
            InitializeComponent();
 
            this.DataContext = this;
 
            var points = new List<Point>();
            points.Add(new Point(100, 100));
            points.Add(new Point(200, 200));
 
            Shapes = new CompositeCollection();
            Shapes.Add(new CollectionContainer() { Collection = points });
        }
    }
XML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<Window x:Class="WpfBindingGeometry.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <ItemsControl ItemsSource="{Binding Shapes}">
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <Canvas/>
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
            <ItemsControl.Resources>
                <DataTemplate DataType="{x:Type Point}">
                    <Path Stroke="Black" Fill="LightBlue">
                        <Path.Data>
                            <EllipseGeometry Center="{Binding}" RadiusX="6" RadiusY="6" />
                        </Path.Data>
                    </Path>
                </DataTemplate>
            </ItemsControl.Resources>
        </ItemsControl>
    </Grid>
</Window>



0



управление сложностью

1687 / 1300 / 259

Регистрация: 22.03.2015

Сообщений: 7,545

Записей в блоге: 5

10.01.2020, 22:52

2

Биндинг возможен к открытым свойствам контекста данных



0



Элд Хасп

Модератор

Эксперт .NET

15036 / 10262 / 2708

Регистрация: 21.04.2018

Сообщений: 30,422

Записей в блоге: 2

11.01.2020, 11:41

3

Лучший ответ Сообщение было отмечено kotelok как решение

Решение

Цитата
Сообщение от kotelok
Посмотреть сообщение

Подскажите, в чём суть и как это исправить?

kotelok, если я правильно понял, вам нужно отобразить кружочки по заданным координатам.
Если так, то вы совершено неверно реализовали как XAML, так и C#.

Объявите класса VM

C#
1
2
3
4
5
    public class PointsVM
    {
        public ObservableCollection<Point> Points { get; }
        = new ObservableCollection<Point>();
    }

CB окна полностью очистите

C#
1
2
3
4
    public partial class MainWindow : Window
    {
        public MainWindow() => InitializeComponent();
    }

И вот такая разметка XAML:

  • Инициализируете Контекст Данных окна новым экземпляром ViewModel
  • В свойство Points VM добавляете нужные вам точки
  • ItemsControl привязываете к этому свойству
  • В стиле элемента задаёте привязку позиции к точке в коллекции
  • В шаблоне элемента задаёте каким образом отображать точку. В данной разметки это кружок и координаты точки.
XML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
<Window
    x:Class="CyberForum.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:local="clr-namespace:CyberForum"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:sys="clr-namespace:System;assembly=mscorlib"
    Title="MainWindow"
    Width="600"
    Height="600"
    mc:Ignorable="d">
    <Window.DataContext>
        <local:PointsVM>
            <local:PointsVM.Points>
                <Point X="100" Y="100" />
                <Point X="200" Y="200" />
            </local:PointsVM.Points>
        </local:PointsVM>
    </Window.DataContext>
    <Grid>
        <ItemsControl ItemsSource="{Binding Points}">
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <Canvas/>
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
            <ItemsControl.ItemContainerStyle>
                <Style TargetType="ContentPresenter">
                    <Setter Property="Canvas.Left" Value="{Binding X}"/>
                    <Setter Property="Canvas.Top" Value="{Binding Y}"/>
                </Style>
            </ItemsControl.ItemContainerStyle>
            <ItemsControl.ItemTemplate>
                <DataTemplate DataType="{x:Type Point}">
                    <StackPanel Orientation="Horizontal">
                        <Ellipse Stroke="Black" Fill="LightBlue" Width="10" Height="10" />
                        <TextBlock Margin="5,0,0,0">
                            <Run Text="{Binding X}"/><Run Text=","/>
                            <Run Text="{Binding Y}"/>
                        </TextBlock>
                    </StackPanel>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>
    </Grid>
</Window>



1



1029 / 645 / 215

Регистрация: 08.08.2014

Сообщений: 2,042

11.01.2020, 13:42

 [ТС]

4

Элд Хасп
Мне нужно отобразить коллекцию произвольных объектов по заданным координатам. Потому и использовал ‘CompositeCollection’.
Эллипсы там не подходят, т.к. они к точке привязываются левым верхним углом, а мне нужно чтобы центрировались.



0



Модератор

Эксперт .NET

15036 / 10262 / 2708

Регистрация: 21.04.2018

Сообщений: 30,422

Записей в блоге: 2

11.01.2020, 13:49

5

Цитата
Сообщение от kotelok
Посмотреть сообщение

Эллипсы там не подходят, т.к. они к точке привязываются левым верхним углом, а мне нужно чтобы центрировались.

Это не проблема. Я просто показал пример реализации.

Цитата
Сообщение от kotelok
Посмотреть сообщение

Мне нужно отобразить коллекцию произвольных объектов по заданным координатам. Потому и использовал ‘CompositeCollection’.

Но у вас в шаблоне только EllipseGeometry !
Как вы собираетесь показывать иные фигуры?

Вы вопросы свои толком объясняйте.



1



1029 / 645 / 215

Регистрация: 08.08.2014

Сообщений: 2,042

11.01.2020, 14:03

 [ТС]

6

Цитата
Сообщение от Элд Хасп
Посмотреть сообщение

Как вы собираетесь показывать иные фигуры

Для каждого типа фигуры свой <DataTemplate DataType="{x:Type Point}"> со своим ‘DataType’ (каждый из которых отдельная VM со своим набором свойств).

Просто изначальный вопрос был именно про ошибку. Т.е. не понятно, почему пример работает корректно, но при этом в дебаг каждый раз выдаёт ошибку. Потому свёл пример к самому минимуму.



0



Элд Хасп

Модератор

Эксперт .NET

15036 / 10262 / 2708

Регистрация: 21.04.2018

Сообщений: 30,422

Записей в блоге: 2

11.01.2020, 15:00

7

Лучший ответ Сообщение было отмечено kotelok как решение

Решение

Цитата
Сообщение от kotelok
Посмотреть сообщение

Т.е. не понятно, почему пример работает корректно, но при этом в дебаг каждый раз выдаёт ошибку.

DataItem=null; — нет контекста данных.
Обратите внимание как я инициализирую свойство Points.

C#
3
4
        public ObservableCollection<Point> Points { get; }
        = new ObservableCollection<Point>();

Это свойство только для чтения и инициализируется ещё до работы конструктора экземпляра.

У вас свойство неинициализировано

C#
3
public CompositeCollection Shapes { get; set; }

Инициализируется оно после вызова InitializeComponent();.
Но первое обращение в привязке к этому свойству происходит внутри InitializeComponent(); когда обрабатывается XAML. И на этом обращении возникает ошибка привязки.
После инициализации свойства элементы получают его новое значение и нормально его обрабатывают.



1



How can I figure out what line of xaml contains the troublesome binding When my debug output is full of lines like the following:

System.Windows.Data Error: 5 : Value produced by BindingExpression is not valid for target property.; Value='UW.Entities.ProgramModel.UWProgram' BindingExpression:Path=; DataItem='RuntimeType' (HashCode=24995901); target element is 'DataGridCollectionViewSource' (HashCode=60976864); target property is 'Source' (type 'Object')

I don’t know how to interpret this in a way that can let me find the responsible line of xaml. I can’t even figure out what xaml file the error is coming from. Is there some way to get more information when these errors occur?

‘UW.Entities.ProgramModel.UWProgram’ is just a type — I don’t know what the object being bound to is. I also have lots of DataGridCollectionViewSources in various bits of xaml, all who’s property ‘Source’ is bound to something which may or may not have that type (again — no easy way to tell).

asked Dec 12, 2011 at 20:43

Alain's user avatar

If you do not know which binding fails

I would use the Snoop utility for this purposes. In short — at the top-left corner above the visual tree, you’ll find a drop-down list which allows filtering visuals, just select Visuals with binding Error. See online documentation for more details.

If you know which binding fails

Sometime you know which binding fails but was not able to find a source fo the problem since binding is pretty tricky, for instance TemplateBindings, bindings which refer to a DataContext of another control, etc.. I found helpful putting a TextBlock which Text property is bound to the same binding source in this way you can see what exactly bound since TextBlock will display a type name of a bound object.

For instance you have following failed binding:

<ItemsControl ItemsSource="{Binding Parent.DataContext.ActiveItem.DataContext}" />

<!-- See what is bound, if failed - try previous level  -->
<TextBlock Text="{Binding Parent.DataContext}" />
<TextBlock Text="{Binding Parent.Inner.Items}" />
<TextBlock Text="{Binding Parent.Inner}" />

Useful links:

  • Debugging Data Bindings in a WPF or Silverlight Application
  • Nice trick using special DebugConverter which allows break a debugger whilst doing a binding, see Debugging WPF DataBinding article

Clonkex's user avatar

Clonkex

3,3927 gold badges38 silver badges55 bronze badges

answered Dec 12, 2011 at 20:51

sll's user avatar

sllsll

61.6k22 gold badges104 silver badges156 bronze badges

3

I have been happily using the wonderful snippet from ‘Switch on the Code’ to detect and report binding errors since it was first published in 2009…

http://www.switchonthecode.com/tutorials/wpf-snippet-detecting-binding-errors

edit: still works excellently on VS2012 (Sept 2013)

Update 25 Jan 2016

The link appears broken, so I’ll paste in the relevant snippets…

using System.Diagnostics;
using System.Text;
using System.Windows;

namespace SOTC_BindingErrorTracer
{
    public class BindingErrorTraceListener : DefaultTraceListener
    {   //http://www.switchonthecode.com/tutorials/wpf-snippet-detecting-binding-errors
        private static BindingErrorTraceListener _Listener;
        public static void SetTrace()
        { SetTrace(SourceLevels.Error, TraceOptions.None); }
        public static void SetTrace(SourceLevels level, TraceOptions options)
        {
            if (_Listener == null)
            {
                _Listener = new BindingErrorTraceListener();
                PresentationTraceSources.DataBindingSource.Listeners.Add(_Listener);
            }
            _Listener.TraceOutputOptions = options;
            PresentationTraceSources.DataBindingSource.Switch.Level = level;
        }
        public static void CloseTrace()
        {
            if (_Listener == null)
            { return; }
            _Listener.Flush();
            _Listener.Close();
            PresentationTraceSources.DataBindingSource.Listeners.Remove(_Listener);
            _Listener = null;
        }
        private StringBuilder _Message = new StringBuilder();
        private BindingErrorTraceListener()
        { }
        public override void Write(string message)
        { _Message.Append(message); }
        public override void WriteLine(string message)
        {
            _Message.Append(message);

            var final = _Message.ToString();
            _Message.Length = 0;

            MessageBox.Show(final, "Binding Error", MessageBoxButton.OK,
              MessageBoxImage.Error);
        }
    }
}

And to set it up/initialize it…

namespace WpfListeningForTraceErrors
{
    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>
    public partial class Window1 : Window
    {
        public Window1()
        {
            BindingErrorTraceListener.SetTrace();
            InitializeComponent();
        }
    }
}

answered Dec 12, 2011 at 21:19

Gayot Fow's user avatar

Gayot FowGayot Fow

8,7101 gold badge35 silver badges48 bronze badges

5

You can add this to every control that binds

  PresentationTraceSources.TraceLevel="High" 

And run the program in debug, the detailed binding information will appear in your Output window. It may help a bit. You can also create a pass though converter to catch an error (catches the problem some times but not always). There are no good tools for debugging XAML in general that I am aware of.

slugster's user avatar

slugster

49.5k14 gold badges96 silver badges145 bronze badges

answered Dec 12, 2011 at 20:54

paparazzo's user avatar

paparazzopaparazzo

44.5k23 gold badges105 silver badges176 bronze badges

You can download a tool called Snoop that will allow you to debug bindings. It provides a view of your WPF applications visual tree higlighting any binding errors that it finds.

You can get some basic information about binding errors in the Output Window in Visual Studio. It will show the binding expression path error and the line on which the error occured.

answered Dec 12, 2011 at 20:51

Ryan Spears's user avatar

Ryan SpearsRyan Spears

2,9612 gold badges31 silver badges39 bronze badges

In VisualStudio goto Tools->Extentions and Updates->(download Output Enhancer). When you build your solution you will get the exact kind of error message you posted in Red color if there is a binding error.

Output enhancer

answered Aug 3, 2018 at 0:13

nikhil's user avatar

nikhilnikhil

1,5943 gold badges24 silver badges52 bronze badges

While developing WPF applications, you will notice a lot of binding errors being displayed in output window; like this

System.Windows.Data Error: 4 : Cannot find source for binding with reference 
'RelativeSource FindAncestor, AncestorType='System.Windows.Controls.DataGrid', 
AncestorLevel='1''. BindingExpression:Path=CellsPanelHorizontalOffset; DataItem=null; 
target element is 'Button' (Name=''); target property is 'Width' (type 'Double')

System.Windows.Data Error: 4 : Cannot find source for binding with reference 
'RelativeSource FindAncestor, AncestorType='System.Windows.Controls.ItemsControl', 
AncestorLevel='1''. BindingExpression:Path=HorizontalContentAlignment; DataItem=null; 
target element is 'ComboBoxItem' (Name=''); target property is 
'HorizontalContentAlignment' (type 'HorizontalAlignment')

System.Windows.Data Error: 4 : Cannot find source for binding with reference 
'RelativeSource FindAncestor, AncestorType='System.Windows.Controls.ItemsControl', 
AncestorLevel='1''. BindingExpression:Path=VerticalContentAlignment; DataItem=null; 
target element is 'ComboBoxItem' (Name=''); target property is 
'VerticalContentAlignment' (type 'VerticalAlignment')

I also faced this problem and tried a lot of things to get to the root cause of the problem. It was very frustrating as AncestorLevel is not used anywhere in code! and I was not able to find the place in code which is responsible for these errors.

Even after searching the various forums and articles there was no solution for this problem; but this was a very common issue and cause of this problem as mentioned on various forums:

This is a «known» issue, and happens to all controls that contain dynamically created lists (all item controls i.e. ComboBox, menu, ListBox etc.).
ControlTemplate of items in these controls (specifically MenuItem, ComboBoxItem etc.)
try to find the nearest ItemsControl and bind to the VerticalAlignment and HorizonalAlignment properties and raises this error on not finding the source.

Microsoft guys mention here and here that “This error has already been handled internally, so you can just leave it alone.” But, still I wanted some sort of solution so as not to have so many irritating error messages in my output window;

Solution 1:

So, I tried one of the workaround provided for this problem i.e. to explicitly set the properties which cause problems like this —

<ComboBox
    Name="control">
    <ComboBox.ItemContainerStyle>
        <Style
            TargetType="ComboBoxItem">
            <Setter
                Property="HorizontalContentAlignment"
                Value="Left" />
            <Setter
                Property="VerticalContentAlignment"
                Value="Center" />
        </Style>
    </ComboBox.ItemContainerStyle>
</ComboBox>

This works but it’s very hard task to set these properties across the whole solution for each problematic control(i.e. ListBox, Menu, ContextMenus etc.).

Solution 2:

Another workaround is to suppress these errors (actually, it seems more appropriate to call them warnings) by setting the data binding source switch level as critical in constructor of the class or a top level window —

#if DEBUG 
    System.Diagnostics.PresentationTraceSources.DataBindingSource.Switch.Level = System.Diagnostics.SourceLevels.Critical;
#endif

I find this one line workaround more appropriate as it works for all such controls (like Menus, ListBox etc.) and that too across the whole project  —

Ref.: How to suppress the System.Windows.Data Error warning message

 

Связывание данных:

Отладка связывания данных

Поскольку вычисление привязки данных осуществляется во время исполнения программы, и в случае неудачи ошибки не генерируются, иногда становится очень сложно отследить неправильную привязку. Эта проблема может возникать по разным причинам, но чаще всего, если вы пытаетесь привязать несуществующее свойство либо потому что вы неправильно запомнили его название, либо просто допустили ошибку в его написании. Вот пример:

<Window x:Class="WpfTutorialSamples.DataBinding.DataBindingDebuggingSample"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="DataBindingDebuggingSample" Height="100" Width="200">
    <Grid Margin="10" Name="pnlMain">
		<TextBlock Text="{Binding NonExistingProperty, ElementName=pnlMain}" />
	</Grid>
</Window>

Окно вывода

Прежде всего вам необходимо посмотреть на Окно вывода (Output window) Visual Studio. Оно должно быть расположено в нижней части главного окна Visual Studio (вы можете сделать его активным используя сочетание клавиш [Ctrl+Alt+O]. Здесь отображаются выходные данные, полученные от отладчика, но при запуске вышеупомянутого примера, среди этих данных вам нужно обнаружить строку, похожую на эту:


System.Windows.Data ошибка: 40: BindingExpression ошибка пути: ‘NonExistingProperty’ свойство не найдено в объекте Grid, имя которого ‘pnlMain’.
Исключение BindingExpression:Path=NonExistingProperty; DataItem=’Grid’ (Name=’pnlMain’);
целевой элемент ‘TextBlock’ (Name=»); целевое свойство ‘Text’ (тип ‘String’)

Это громоздкое сообщение может показаться избыточным, в основном из-за того что в нём отсутствуют разрывы строк, но самая важная часть содержится вот здесь:

Свойство «NonExistingProperty» не найдено в «объекте» «Grid» (Name = «pnlMain») ».

Это говорит о том, что вы попытались применить свойство с именем «NonExistingProperty» для объекта типа Grid с именем pnlMain. Теперь сообщение стало достаточно понятным, и оно должно помочь вам исправить имя свойства либо привязать существующий объект, если возникла проблема такого рода.

Изменение уровня диагностической информации (trace level)

Ошибку в вышеприведённом примере легко исправить, так как для WPF было понятно, что мы пытались сдеалать и почему это не сработало. Но давайте рассмотрим следующий пример:

<Window x:Class="WpfTutorialSamples.DataBinding.DataBindingDebuggingSample"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="DataBindingDebuggingSample" Height="100" Width="200">
    <Grid Margin="10">
		<TextBlock Text="{Binding Title}" />
	</Grid>
</Window>

Здесь мы пытаемся сделать привязку к свойству «Title», но какого объекта? Как обсуждалось в главе, посвящённой контексту данных, WPF использует свойство DataContext элемента TextBlock, которое наследуется вниз по иерархии элементов управления, но в этом примере мы забыли задать контекст данных. Это фактически означает, что мы пытаемся получить свойство объекта NULL. WPF предположит, что эта привязка абсолютно корректна, но объект просто пока не был инициализирован, и не будет сообщать об этом. Если вы запустите этот пример и посмотрите на окно Output, вы не увидите ошибок привязки данных.

Однако в случаях, если это поведение программы вам не подходит, существует возможность заставить WPF сообщать вам о возникающих проблемах привязки данных. Этого можно добиться установкой TraceLevel объекта PresentationTraceSources, которые находятся в пространстве имён System.Diagnostics:

<Window x:Class="WpfTutorialSamples.DataBinding.DataBindingDebuggingSample"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:diag="clr-namespace:System.Diagnostics;assembly=WindowsBase"
        Title="DataBindingDebuggingSample" Height="100" Width="200">
    <Grid Margin="10">
		<TextBlock Text="{Binding Title, diag:PresentationTraceSources.TraceLevel=High}" />
	</Grid>
</Window>

Обратите внимание, мы добавили ссылку на пространство имён System.Diagnostics в заголовке окна и затем задали свойство для привязки данных. В результате WPF будет выводить информацию об этой привязке в окне Output:

System.Windows.Data Warning: 55 : Created BindingExpression (hash=2902278) for Binding (hash=52760599)
System.Windows.Data Warning: 57 :   Path: 'Title'
System.Windows.Data Warning: 59 : BindingExpression (hash=2902278): Default mode resolved to OneWay
System.Windows.Data Warning: 60 : BindingExpression (hash=2902278): Default update trigger resolved to PropertyChanged
System.Windows.Data Warning: 61 : BindingExpression (hash=2902278): Attach to System.Windows.Controls.TextBlock.Text (hash=18876224)
System.Windows.Data Warning: 66 : BindingExpression (hash=2902278): Resolving source
System.Windows.Data Warning: 69 : BindingExpression (hash=2902278): Found data context element: TextBlock (hash=18876224) (OK)
System.Windows.Data Warning: 70 : BindingExpression (hash=2902278): DataContext is null
System.Windows.Data Warning: 64 : BindingExpression (hash=2902278): Resolve source deferred
System.Windows.Data Warning: 66 : BindingExpression (hash=2902278): Resolving source
System.Windows.Data Warning: 69 : BindingExpression (hash=2902278): Found data context element: TextBlock (hash=18876224) (OK)
System.Windows.Data Warning: 70 : BindingExpression (hash=2902278): DataContext is null
System.Windows.Data Warning: 66 : BindingExpression (hash=2902278): Resolving source
System.Windows.Data Warning: 69 : BindingExpression (hash=2902278): Found data context element: TextBlock (hash=18876224) (OK)
System.Windows.Data Warning: 70 : BindingExpression (hash=2902278): DataContext is null
System.Windows.Data Warning: 66 : BindingExpression (hash=2902278): Resolving source
System.Windows.Data Warning: 69 : BindingExpression (hash=2902278): Found data context element: TextBlock (hash=18876224) (OK)
System.Windows.Data Warning: 70 : BindingExpression (hash=2902278): DataContext is null
System.Windows.Data Warning: 66 : BindingExpression (hash=2902278): Resolving source  (last chance)
System.Windows.Data Warning: 69 : BindingExpression (hash=2902278): Found data context element: TextBlock (hash=18876224) (OK)
System.Windows.Data Warning: 77 : BindingExpression (hash=2902278): Activate with root item <null>
System.Windows.Data Warning: 105 : BindingExpression (hash=2902278):   Item at level 0 is null - no accessor
System.Windows.Data Warning: 79 : BindingExpression (hash=2902278): TransferValue - got raw value {DependencyProperty.UnsetValue}
System.Windows.Data Warning: 87 : BindingExpression (hash=2902278): TransferValue - using fallback/default value ''
System.Windows.Data Warning: 88 : BindingExpression (hash=2902278): TransferValue - using final value ''

Изучив данный список событий, мы сможем понять весь процесс, который происходит в WPF при поиске нужного значения для элемента TextBlock. Мы видим несколько безуспешных попыток определить контекст данных (DataContext), что в конечном итоге приводит к использованию значения по умолчанию {DependencyProperty.UnsetValue}, которое транслируется в пустую строку.

Использование настоящего отладчика

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

<Window x:Class="WpfTutorialSamples.DataBinding.DataBindingDebuggingSample"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:self="clr-namespace:WpfTutorialSamples.DataBinding"
        Title="DataBindingDebuggingSample" Name="wnd" Height="100" Width="200">
	<Window.Resources>
		<self:DebugDummyConverter x:Key="DebugDummyConverter" />
	</Window.Resources>
    <Grid Margin="10">
		<TextBlock Text="{Binding Title, ElementName=wnd, Converter={StaticResource DebugDummyConverter}}" />
	</Grid>
</Window>
using System;
using System.Windows;
using System.Windows.Data;
using System.Diagnostics;

namespace WpfTutorialSamples.DataBinding
{
	public partial class DataBindingDebuggingSample : Window
	{
		public DataBindingDebuggingSample()
		{
			InitializeComponent();
		}
	}

	public class DebugDummyConverter : IValueConverter
	{
		public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
		{
			Debugger.Break();
			return value;
		}

		public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
		{
			Debugger.Break();
			return value;
		}
	}
}

В файле Code-behind мы создаём конвертер DebugDummyConverter. В методах Convert() и ConvertBack() мы вызываем метод Debugger.Break(), что приводит к такому же эффекту, что и установка точки прерывания программы в Visual Studio, с последующим возвратом неизменённого значения, полученного нами ранее.

В файле разметки мы добавляем ссылку на наш конвертер в ресурсах окна и затем используем его для привязки данных. В реальном приложении следует описывать конвертер в отдельном файле и добавлять ссылку на него в файле App.xaml, чтобы его можно было использовать в разных окнах приложения без необходимости создания ссылки в каждом окне, но для данного примера нам подойдёт и используемый подход.

Если вы запустите этот пример, вы увидите, что отладчик остановится , как только WPF попытается получить значение заголовка Window (Title). Вы можете проверить значение, переданное методу Convert(), или даже изменить его перед обработкой, используя стандартные возможности отладки Visual Studio.

Если отладчик не останавливается в нужной точке, это означает, что конвертер не используется. Обычно это означает, что у вас неправильная привязка, которую можно диагностировать и исправить с помощью методов, описанных в начале этой статьи. Трюк с фиктивным конвертером предназначен только для проверки правильности выражения привязки.


This article has been fully translated into the following languages:

  • Bulgarian

  • Chinese

  • Danish

  • French

  • German

  • Italian

  • Japanese

  • Polish

  • Portuguese

  • Russian

  • Spanish

  • Swedish

  • Turkish

  • Vietnamese

Is your preferred language not on the list? Click here to help us translate this article into your language!

Понравилась статья? Поделить с друзьями:
  • Ошибки привода кемрон
  • Ошибки при утеплении чердачного перекрытия
  • Ошибки при шитье на швейной машинке
  • Ошибки привода дорхан
  • Ошибки при утеплении чердака