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" />
Window
的 DataContext
设置为我的 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 事件。所以这个值是可用的,这就是为什么 TextBlock
s 文本绑定到 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
上使用了TemplateBinding
。 TemplateBinding
单向工作,因此无论您在 TextBox
中键入什么,都不会被推回您的 FilterText
属性(它旨在更有效地将 Background
、BorderBrush
等属性转发到模板通过在编译时解析,与在运行时解析的普通绑定不同)。所以你需要做的是在你的模板中用RelativeSource
在TemplatedParent
模式下用普通绑定替换它:
<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本地和外部绑定的主要内容,如果未能解决你的问题,请参考以下文章