【问题标题】:Binding inside ContentControl not workingContentControl 内的绑定不起作用
【发布时间】:2012-12-20 02:43:58
【问题描述】:

我正在构建一个基于article by Sukram in CodeProject 的图形设计器。我现在正在尝试扩展它,以便画布上的每个项目都绑定到不同的 ViewModel 对象 - 即我正在为每个项目设置 DataContext。

设计器上的每个项目实际上都是一个 ContentControl,其中放置了一个不同的模板(基于将哪个工具箱项目拖到画布上)。所以我有一个包含 TextBox 的模板,我有一个包含 Name 属性的 ViewModel 对象,我将 TextBox 的 Text 属性绑定到 ViewModel 的 Name 属性,然后……什么都没有。我用 Snoop 检查了可视化树,它确认 TextBox 的 DataContext 是 ViewModel 对象。然而 TextBox 仍然是空的。如果我修改 TextBox 中的(空)Text,ViewModel 中的 Name 属性不会改变。所以看起来绑定没有被应用(或以某种方式被删除)。

我发现一些帖子讨论了 ContentControl 与 DataContext 和 Content 属性的关系,但我不确定它们的适用性如何。代码设置 ContentControl.Content 如下:

newItem = new ContentControl();
ControlTemplate template = toolbox.GetTemplate();
UIElement element = template.LoadContent() as UIElement;
ViewModelItem viewModel = new ViewModelItem() { Name = "Bob" };

newItem.Content = element;
newItem.DataContext = viewModel;

模板的 XAML 是:

<ControlTemplate>
    <Border BorderBrush="Black" BorderThickness="1" Width="100">
        <TextBox Text={Binding Name}/>
    </Border>
</ControlTemplate>

Snoop 显示 TextBox 有一个 DataContext,如果我深入研究该 DataContext,我可以看到它有一个 Name 属性,其值为“Bob”。那么为什么 TextBox 仍然是空的呢? Snoop 允许我更改 Name 属性,但 TextBox 保持为空。

我做错了什么?


更多细节。我已将 OutputWindow 的 VS2010 Debug DataBinding 选项设置为 Verbose,这似乎表明绑定正在尝试之前我设置了 DataContext。是否可能无法识别对 DataContext 的更改?


我刚刚发现这篇帖子 DataTemplate.LoadContent does not preserve bindings - 显然 DataTemplate.LoadContent 不保留绑定。所以看起来我必须编写自己的 LoadContent() 版本。


我已经意识到模板是通过 XamlWriter 实现的,它显然会剥离所有绑定。这不会有帮助。


我无法修复 DataTemplate.LoadContent(),但我意识到我实际上并不需要 DataTemplate,因为 XamlWriter / XamlReader 已经在实例化我所追求的 UI 元素。我找到了让 XamlWriter 写入所有绑定 here 的修复程序,然后一切正常。

感谢您的帮助。

【问题讨论】:

    标签: wpf binding


    【解决方案1】:

    也许您需要告诉ControlTemplate 中的绑定查看TemplatedParent,如this thread 中所述?

    <TextBox Text="{Binding Path=Name, RelativeSource={RelativeSource TemplatedParent}}"/>
    

    要么这样,要么尝试改用DataTemplate

    我目前无法对此进行测试,所以我可能只是在这里猜测。

    【讨论】:

    • 感谢您的建议,但没有奏效。我还尝试将 DataContext 绑定到 ContentControl 内的元素,Snoop 显示它会将其绑定到 TextBox,但这也不起作用。所有这一切的困难在于我不知道如何调试这个绑定问题。我可以看到 TextBox 的 DataContext 使用 Snoop 是正确的,但我不知道如何找出绑定不会绑定的原因 - 没有引发异常,并且“输出”窗口中没有任何内容。剩下的似乎就是随机尝试各种不同类型的绑定参数。
    • 是的,在 WPF 中调试绑定问题并不容易。除了 VS 中的 Output 窗口有时会显示绑定错误消息外,我不知道有任何工具可以帮助解决这个问题。如果您无法使控制模板正常工作,您可能不得不使用DataTemplate
    【解决方案2】:

    按照 bde 的建议,我会使用 DataTemplate

    您正在尝试将一些 UI 放在您自己的 data (ViewModel) 上,这就是 Data-模板的用途(ControlTemplate 通常是您如果你想change how e.g. a Button looks,请使用。

    更改您的代码以使用 ContentControl.ContentTemplateDataTemplate

    <DataTemplate>
        <Border BorderBrush="Black" BorderThickness="1" Width="100">
            <TextBox Text={Binding Name}/>
        </Border>
    </DataTemplate>
    

    代码隐藏:

    newItem = new ContentControl();
    //NOTE: .GetTemplate() needs to return a DataTemplate, and not a ControlTemplate:
    newItem.ContentTemplate = toolbox.GetTemplate();
    
    ViewModelItem viewModel = new ViewModelItem() { Name = "Bob" };
    
    newItem.Content = viewModel;
    newItem.DataContext = viewModel;
    

    【讨论】:

    • 感谢您的建议 - 这很有意义,所以我已经这样做了,但没有任何区别。 Snoops 显示 TextBox 具有正确的 DataContext,但仍不显示 Name。还有其他想法吗?
    • 如何在toolbox.GetTemplate() 中加载模板?你能把那个函数也发一下吗?
    • GetTemplate() 只是一个普通的附加属性,即:
    • public static readonly DependencyProperty DesignerElementProperty = DependencyProperty.RegisterAttached("DesignerElement", typeof(FrameworkElement), typeof(DesignerItem)); public static FrameworkElement GetDesignerElement(UIElement element) { Object value = element.GetValue(DesignerElementProperty); return (FrameworkElement)value; }
    • 这是一些DesignerElement 属性的代码,而不是GetTemplate() 方法。我不确定我是否理解您的解决方案,但是阅读您更新的问题后,我发现您已经修复了它,所以我想这一切都很好:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-09-27
    • 1970-01-01
    • 2018-06-14
    • 2013-04-02
    • 1970-01-01
    • 2013-02-01
    • 1970-01-01
    相关资源
    最近更新 更多