wpf本地和外部绑定

Posted

技术标签:

【中文标题】wpf本地和外部绑定【英文标题】:wpf local and external binding 【发布时间】:2017-11-26 00:19:48 【问题描述】:

我有一个带有两个 DependencyProperties 的自定义控件。一种类型对象,允许用户像其他控件一样添加自定义内容,以及一种用于文本框的类型字符串:

public object NoResultContent

    get  return (object)GetValue(NoResultContentProperty); 
    set  SetValue(NoResultContentProperty, value); 


public static readonly DependencyProperty NoResultContentProperty =
    DependencyProperty.Register("NoResultContent", typeof(object), typeof(AdvancedAutoCompleteBox), new PropertyMetadata(null));

public string FilterText

    get  return (string)GetValue(FilterTextProperty); 
    set  SetValue(FilterTextProperty, value); 


public static readonly DependencyProperty FilterTextProperty =
    DependencyProperty.Register("FilterText", typeof(string), typeof(AdvancedAutoCompleteBox),
            new FrameworkPropertyMetadata(string.Empty, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault | FrameworkPropertyMetadataOptions.Journal,
                        new PropertyChangedCallback(OnFilterTextPropertyChanged), new CoerceValueCallback(CoerceText),
                        true, UpdateSourceTrigger.PropertyChanged));

ControlTemplate 看起来像:

<ControlTemplate
    TargetType="x:Type local:SpecialBox">
    <StackPanel>
        <TextBox
            Text="Binding RelativeSource=RelativeSource Mode=TemplatedParent, Path=FilterText" />
        <ContentPresenter
            ContentSource="NoResultContent" />
    </StackPanel>
</ControlTemplate>

我是这样使用的:

<Controls:SpecialBox
    Name="Box">
    <Controls:SpecialBox.NoResultContent>
        <Button
            Content="Add value"
            CommandParameter="Binding ElementName=Box, Path=FilterText"
            Command="Binding AddProject" />
    </Controls:SpecialBox.NoResultContent>
</Controls:SpecialBox>

<TextBlock Text="Binding ElementName=Box, Path=FilterText" />

WindowDataContext 设置为我的 ViewModel。所以绑定到ICommand 有效。提供一个常量字符串作为 CommandParameter 将根据需要将其传递给 ICommand。

CommandParameter="Binding RelativeSource=RelativeSource Mode=Self, Path=Content"

将“添加值”传递给我的 ICommand 实现。

ElementName 绑定,如上所述和以下代码 CommandParameter="Binding RelativeSource=RelativeSource AncestorType=Controls:SpeicalBox, Path=FilterText"

不起作用。找不到源。

CommandParameter="Binding RelativeSource=RelativeSource TemplatedParent, Path=FilterText"

不抛出警告,但总是返回 null。

更多信息: 每次更改都会触发我的 dp 的 OnFilterTextPropertyChanged 事件。所以这个值是可用的,这就是为什么 TextBlocks 文本绑定到 SpecialBox 工作得很好。

在我的 ViewModel 上为 FilterText 值提供第二个属性是一种解决方法,但我如何能够从第二个属性访问本地 dp?

【问题讨论】:

“不工作”是什么意思?你的命令得到的命令参数是什么? 绑定总是返回null。将常量字符串值作为参数写入效果很好 首先,您需要确定Button.CommandParameter 是否实际上是null(错误也可能是错误的ICommand 实现)。例如。添加Button.Click 处理程序,设置断点并检查Button ICommand 运行良好。实际的问题是,任何元素或相对绑定都不起作用:Cannot find source for binding with reference 'RelativeSource FindAncestor, AncestorType='Controls.SpecialBox', AncestorLevel='1'' 好的。在这种情况下,您提供的代码是您正在使用的实际模板(特别是ContentPresenter)?另外,您使用的是什么框架版本? 【参考方案1】:

这种情况下正确的绑定方式是在FindAncestor模式下使用RelativeSource

CommandParameter="Binding FilterText,
    RelativeSource=RelativeSource AncestorType=Controls:SpeicalBox"

另外,使用ElementName 应该可以正常工作。

现在为什么它不起作用是因为您在模板中的TextBox 上使用了TemplateBindingTemplateBinding 单向工作,因此无论您在 TextBox 中键入什么,都不会被推回您的 FilterText 属性(它旨在更有效地将 BackgroundBorderBrush 等属性转发到模板通过在编译时解析,与在运行时解析的普通绑定不同)。所以你需要做的是在你的模板中用RelativeSourceTemplatedParent模式下用普通绑定替换它:

<TextBox Text="Binding FilterText, RelativeSource=RelativeSource TemplatedParent" />

这至少解决了我根据您提供的代码设法重现的问题(这是我的第一个怀疑)。但是,它确实与您声称 TextBlock 上的绑定确实有效的说法相矛盾。因此,我建议您尝试一下,如果它不能解决您的问题,请返回。

【讨论】:

老实说,我通过 OnApplyTemplate() 中的 Template.FindName 访问 Control 模板的 Text 属性。我提供的示例只是为了缓解问题。但你是对的。它必须是 RelativeSource=RelativeSource TemplatedParent 才能获得工作示例。我的错,对不起。我将编辑我的问题。【参考方案2】:

将 ContenPresenter 更改为 ContentControl 成功了

<ContentControl
    Content="Binding RelativeSource=RelativeSource Mode=TemplatedParent, Path=NoResultContent" />

【讨论】:

以上是关于wpf本地和外部绑定的主要内容,如果未能解决你的问题,请参考以下文章

如何在 WPF 中的控件上绑定本地属性

wpf image控件 绑定本地磁盘的图片 绝对路径的应该怎么写

WPF入门教程系列十七——WPF中的数据绑定

绑定会在 WPF 中造成内存泄漏吗?

数据绑定到 WPF 中的 UserControl

基于 XAML 绑定到区域性名称属性,使用不同区域性在 WPF GridView 中本地化货币值