Отладка WPF AvalonEdit привязка к свойству Document - PullRequest
1 голос
/ 07 июня 2010

весь день сижу и пытаюсь выяснить, почему не работает привязка к свойству AvalonEdits Document. AvalonEdit - это продвинутый текстовый редактор WPF - часть проекта SharpDevelop (он будет использоваться в SharpDevelop v4 Mirador).

Поэтому, когда я настраивал простой проект - один TextEditor (это реальное имя AvalonEdits в библиотеке) и создал простой класс с одним свойством - Document, и он возвращает фиктивный объект с некоторым статическим текстом, привязка работает отлично .

Однако в реальном решении я связываю коллекцию объектов SomeEditor с TabControl. TabControl имеет DataTemplate для SomeEditor, и есть объект TextEditor.

<TabControl Grid.Column="1" x:Name="tabControlFiles" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" >
 <TabControl.Resources>
  <DataTemplate DataType="{x:Type m:SomeEditor}">
   <a:TextEditor 
   Document="{Binding Path=Document, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, Converter={StaticResource NoopConverter}, IsAsync=True}" 
   x:Name="avalonEdit"></a:TextEditor> 
  </DataTemplate>  
 </TabControl.Resources>

 <TabControl.ItemContainerStyle>
  <Style BasedOn="{StaticResource TabItemStyle}" TargetType="{x:Type TabItem}">
   <Setter Property="IsSelected" Value="{Binding IsSelected}"></Setter>
  </Style>
 </TabControl.ItemContainerStyle>
</TabControl>

Это не работает. То, что я исследовал до сих пор:

  • DataContext из TextEditor установлен на правильный экземпляр SomeEditor
  • Свойство TextEditors Document установлено на другой экземпляр, чем свойство SomeEditor.Document
  • когда я устанавливаю точку останова для неконвертерного конвертера, который присоединен к этой привязке, он показывает мне правильное значение для Document (конвертер используется!)
  • Я также копался в VisualTree для получения ссылки на TextEditor и вызывал GetBindingExpression (TextEditor.DocumentProperty), и это ничего не возвращало

  • WPF выдает следующую информацию:

    System.Windows.Data Информация: 10: Невозможно получить значение, используя привязку, и допустимого запасного значения не существует; вместо этого используется значение по умолчанию. BindingExpression: Путь = Документ; DataItem = 'SomeEditor' (HashCode = 26280264); целевым элементом является TextEditor (Name = 'avalonEdit'); Свойство target - «Документ» (тип «TextDocument»)

  • Экземпляр SomeEditor, с которым связан, уже имеет созданную и кэшированную копию Document до того, как произойдет привязка. Получатель никогда не вызывается.

Кто-нибудь может сказать мне, что может быть не так? Почему BindingExpression не установлен? Почему собственность добытчика никогда не называется?

// edit: новые тесты и новые результаты

Я прочитал еще немного и установил привязку в коде. Когда я делаю это, это работает. Почему установка этого в XAML не работает и делает то же самое в коде?

// edit2: код также завершается неудачно при вызове сразу после добавления объекта в наблюдаемую коллекцию, которая используется в качестве источника данных более высокого уровня (это происходит вскоре после запуска привязки xaml). Это заставляет меня думать, что это вопрос времени. Кто-нибудь может что-то сказать по этому поводу?

// edit3: код привязки:

private List<T> GetObjectOfTypeInVisualTree<T>(DependencyObject dpob) where T : DependencyObject
{
    int count = VisualTreeHelper.GetChildrenCount(dpob);
    List<T> returnlist = new List<T>();

    for (int i = 0; i < count; i++)
    {
        DependencyObject child = VisualTreeHelper.GetChild(dpob, i);
        T childAsT = child as T;
        if (childAsT != null)
        {
            returnlist.Add(childAsT);
        }
        List<T> lst = GetObjectOfTypeInVisualTree<T>(child);
        if (lst != null)
        {
            returnlist.AddRange(lst);
        }
    }
    if (returnlist.Count > 0)
    {
        return returnlist;
    }
    return null;
}

private void RebindMenuItem_Click(object sender, RoutedEventArgs e)
{
    foreach (XHTMLStudioPrototypeFileEditor ed in CurrentProject.OpenedFiles)
    {

        List<ContentPresenter> cps = GetObjectOfTypeInVisualTree<ContentPresenter>(tabControlFiles);
        if (cps != null)
        {
            foreach (ContentPresenter cp in cps)
            {

                foreach (DataTemplate dt in tabControlFiles.Resources.Values)
                {
                    try
                    {
                        object o = dt.FindName("avalonEdit", cp);
                        TextEditor ted = (TextEditor)o;

                        bool isDataBound = BindingOperations.IsDataBound(ted, TextEditor.DocumentProperty);
                        if (!isDataBound)
                        {
                            BindingOperations.SetBinding(ted, TextEditor.DocumentProperty, new Binding("Document"));
                        }
                        Console.WriteLine(isDataBound);
                    }
                    catch (Exception)
                    {


                    }
                }
            }
        }
    }
}

Ответы [ 2 ]

2 голосов
/ 15 июня 2010

Вот еще шесть вещей, которые нужно попробовать:

Найдите в своем приложении все места, где вы непосредственно назначаете свойство Document TextEditor.Похоже, какой-то код где-то делает avalonEdit.Document = ..., который перезаписывает привязку.Я бы искал во всем вашем приложении строки целого слова "Document" и "DocumentProperty" в регистре совпадений и каждый раз задумывался, не может ли он установить это свойство.

Установить точку останова в TextEditor.OnDocumentChanged, чтобы увидеть, правильно ли привязан документ, а затем изменен позже.Проверка стеков вызовов с отключенным «Просто моим кодом» и показом внешнего кода.

Попробуйте установить точки останова в NoopConverter.Convert, SomeEditor.get_Document и TextEditor.OnDocumentChanged, чтобы выяснить точную последовательность операций.Также обратите внимание, когда отображается сообщение об ошибке Binding.

Временно измените конструктор TextEditor, чтобы сохранить ссылку на каждый экземпляр в открытом статическом поле List, чтобы вы могли определить, какие TextEditors когда-либо были созданы, затем напишите код, который просматриваетони показывают свои GetHashCode() и результаты BindingOperations.GetBindingExpression(editor, DocumentProperty).Убедитесь, что вы удалили общедоступное статическое поле, когда закончите!

Удалите "Path =" из вашего XAML, который создает Binding, чтобы он лучше соответствовал версии C #.(Однажды у меня возникла проблема, когда XAML интерпретировал путь, отличный от конструктора Binding, из-за ITypeDescriptorContext, переданного в PropertyConverter.) Точный эквивалент отправленного вами кода C #: Document="{Binding Document}".

Создание пользовательской трассировкипрослушиватель и установите в нем точку останова, чтобы получить стек вызовов при возникновении ошибки привязки, выполнить поиск кадров стека, чтобы найти задействованные объекты и дать им идентификаторы объектов отладчика (щелчок правой кнопкой мыши, Make Object ID), а затем исследовать фактические значениясвойств, чтобы убедиться, что они соответствуют ожиданиям.

Наслаждайтесь!

0 голосов
/ 31 августа 2010

Просто замечание: у меня была та же проблема, и я посмотрел источник AvalonEdit;похоже, проблема в том, что конструктор TextEditor перезаписывает свойство Document (создает новый TextDocument);если вы это закомментируете, привязки сработают;однако, если у вас нет привязки, вам нужно будет внести дополнительные изменения.Я постараюсь обсудить это с авторами и, возможно, предложить патч.

...