【问题标题】:WPF Debugging AvalonEdit binding to Document propertyWPF 调试 AvalonEdit 绑定到 Document 属性
【发布时间】:2010-06-07 00:37:18
【问题描述】:

我整天坐着试图找出为什么绑定到 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 的正确实例
  • TextEditor 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:在将对象添加到用作更高级别 DataSource 的可观察集合后立即调用代码也会失败。(在 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)
                    {


                    }
                }
            }
        }
    }
}

【问题讨论】:

  • 您能否展示您用于以编程方式创建绑定的代码?另外,如果删除 IsAsync 会发生什么?
  • 如果我删除 IsAsync,什么都不会发生。我尝试了各种组合以使其发挥作用。

标签: wpf data-binding sharpdevelop avalonedit


【解决方案1】:

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

在您的应用程序中仔细搜索您直接分配给 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 ),然后调查属性的实际值以确保它们符合预期。

享受吧!

【讨论】:

  • 我将简要回答要点。 1) 完成,没有结果。 2)首先完成。 3)每次都有不同的结果——可能是不同的线程进行绑定,其余的。 4)&5) 创建文本编辑器没有问题。我已经检查过了。我总是得到一个新实例,而且我知道 C# 代码没问题——它有效。现在是最终结果:经过几次清理和构建后,它突然开始工作。我不知道是什么原因,但我的猜测仍然是线程安全和时间。我想并不是所有的代码都是线程安全的,这就是它表现得如此奇怪的原因。
  • 几天后我下载了 AvalonDock 并且需要用另一种方式重写它——现在我可以直接访问 AvalonEdit 实例,我可以做任何我想做的事情。它正在工作。非常感谢您的回答。它非常彻底,并且您介绍了有价值的调试技术。赏金是你的。
【解决方案2】:

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

【讨论】:

    猜你喜欢
    • 2011-02-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-07
    • 2010-10-05
    • 2023-03-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多