1

我整天坐着,试图找出为什么绑定到 AvalonEdits Document 属性不起作用。AvalonEdit 是一个高级 WPF 文本编辑器 - SharpDevelop 项目的一部分。(它将在 SharpDevelop v4 Mirador 中使用)。

因此,当我建立一个简单的项目时——一个 TextEditor(这是库中的 AvalonEdits 真实名称)并创建了一个具有一个属性的简单类——Document,它返回一个带有一些静态文本的虚拟对象,绑定工作得很好。

但是在现实生活中的解决方案中,我将 SomeEditor 对象的集合绑定到 TabControl。TabControl 具有 SomeEditor 的 DataTemplate 和 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>

这行不通。到目前为止我调查的内容:

  • TextEditor 的 DataContext 设置为 SomeEditor 的正确实例
  • TextEditors Document 属性设置为 SomeEditor.Document 属性以外的其他实例
  • 当我将断点设置为附加到该绑定的无操作转换器时,它会向我显示 Document 的正确值(使用了转换器!)
  • 我还挖掘了 VisualTree 以获取对 TextEditor 的引用并调用 GetBindingExpression(TextEditor.DocumentProperty) 但这并没有返回任何内容

  • WPF 产生以下信息:

    System.Windows.Data 信息:10:无法使用绑定检索值,并且不存在有效的备用值;改用默认值。绑定表达式:路径=文档;DataItem='SomeEditor' (HashCode=26280264); 目标元素是'TextEditor'(名称='avalonEdit');目标属性是“文档”(类型“文本文档”)

  • 绑定到的 SomeEditor 实例在绑定发生之前已经创建并缓存了 Document 的副本。getter 永远不会被调用。

谁能告诉我可能出了什么问题?为什么没有设置 BindingExpression ?为什么永远不会调用属性获取器?

//编辑:新测试和新结果

我已经阅读了更多内容并在后面的代码中设置了绑定。当我这样做时,它会起作用。为什么在 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)
                    {


                    }
                }
            }
        }
    }
}
4

2 回答 2

2

这里还有六件事可以尝试:

在您的应用程序中仔细搜索您直接分配给 TextEditor 的 Document 属性的任何位置。它看起来像一些代码,某处正在做一个avalonEdit.Document = ...会覆盖绑定的代码。我会在您的整个应用程序中搜索匹配大小写的全字字符串“Document”和“DocumentProperty”,并考虑一下每次出现是否可以设置此属性。

在 TextEditor.OnDocumentChanged 中设置断点以查看文档是否正确绑定,然后稍后再更改回来。检查禁用“仅我的代码”并显示外部代码的调用堆栈。

尝试在 NoopConverter.Convert、SomeEditor.get_Document 和 TextEditor.OnDocumentChanged 中设置断点,以确定操作的精确顺序。还要注意何时显示绑定错误消息。

临时修改 TextEditor 的构造函数以将对每个实例的引用存储在公共静态 List 字段中,以便您可以确定曾经创建过哪些 TextEditor,然后编写代码查看它们并显示它们GetHashCode()BindingOperations.GetBindingExpression(editor, DocumentProperty)结果。确保完成后取出公共静态字段!

从构造绑定的 XAML 中取出“Path=”,以便更好地匹配 C# 版本。(我曾经遇到过一个问题,即 XAML 解释的路径与 Binding 构造函数不同,因为 ITypeDescriptorContext 传递给 PropertyConverter。)与您发布的 C# 代码完全相同的是Document="{Binding Document}".

创建一个自定义跟踪侦听器并在其中设置断点以在产生绑定错误时获取调用堆栈,搜索堆栈帧以找到涉及的对象并为它们提供调试器对象ID(右键单击,制作对象ID),然后调查属性的实际值以确保它们符合预期。

享受!

于 2010-06-15T19:56:47.977 回答
0

只是一个观察:我遇到了同样的问题并查看了 AvalonEdit 源;似乎问题在于 TextEditor 构造函数覆盖了 Document 属性(实例化了一个新的 TextDocument);如果您对此进行注释,则绑定有效;但是,如果您没有绑定,则需要进行进一步的修改。我会尝试与作者讨论这个问题,也许会建议一个补丁。

于 2010-08-31T12:07:57.683 回答