问题描述
我想像这样进行链式绑定:我在一个窗口内有一个具有依赖属性的用户控件,该窗口具有类似的依赖属性.我想将usercontrol的dependencyproperty绑定到window的dependencyproperty.
I want to make a chain binding like this: I have a usercontrol with a dependencyproperty inside a window with similar dependencyproperty. I want to bind the dependencyproperty of the usercontrol to the dependencyproperty of the window.
我创建了一个示例项目来演示我的问题:
I created a sample project to demonstrate my problem:
UserControl1 XAML:
UserControl1 XAML:
<UserControl x:Class="WpfApplication1.UserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300" DataContext="{Binding RelativeSource={RelativeSource Self}}">
<Grid>
<Label Content="{Binding Caption}"/>
</Grid>
</UserControl>
UserControl1 C#:
UserControl1 C#:
public partial class UserControl1 : UserControl
{
public static readonly DependencyProperty CaptionProperty = DependencyProperty.Register("Caption", typeof(string), typeof(UserControl1));
public string Caption
{
get { return (string)GetValue(CaptionProperty); }
set { SetValue(CaptionProperty, value); }
}
public UserControl1()
{
InitializeComponent();
}
}
主窗口 XAML:
<Window xmlns:WpfApplication1="clr-namespace:WpfApplication1" x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525" DataContext="{Binding RelativeSource={RelativeSource Self}}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<Label Content="{Binding Caption, Mode=OneWay}"/>
<WpfApplication1:UserControl1 x:Name="uc" Caption="{Binding Caption, Mode=OneWay}" Grid.Row="1"/>
</Grid>
</Window>
主窗口 C#:
public partial class MainWindow : Window
{
public static readonly DependencyProperty CaptionProperty = DependencyProperty.Register("Caption", typeof(string), typeof(MainWindow));
public string Caption
{
get { return (string)GetValue(CaptionProperty); }
set { SetValue(CaptionProperty, value); }
}
public MainWindow()
{
InitializeComponent();
(new Thread(() => { Thread.Sleep(2000); Dispatcher.Invoke(() => { uc.Caption = "YYY"; Caption = "XXX"; }); })).Start();
}
}
问题是,当我将 Caption 设置为(窗口的)XXX"时,我希望它也会通知用户控件并更新其 Caption,但事实并非如此.我想避免附加依赖属性并尽可能避免代码落后.有什么想法吗?
The thing is that when I set Caption to "XXX" (of the Window) I would expect it to also notify the usercontrol and update its Caption, but it doesn't. I would like to avoid Attached dependency properties and avoid code behind as much as possible. Any ideas?
感谢您的努力.
推荐答案
你可以创建一个用户控件...
You can create a user control along the lines of...
<UserControl x:Class="ChainBinding.CaptionGuy"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
>
<Grid>
<Label Name="CaptionLabel"/>
</Grid>
</UserControl>
...并像这样使用您的依赖属性对其进行检测...
...and instrument it with your dependency property like this...
#region Caption (DependencyProperty)
public string Caption
{
get { return (string)GetValue(CaptionProperty); }
set { SetValue(CaptionProperty, value); }
}
public static readonly DependencyProperty CaptionProperty =
DependencyProperty.Register("Caption", typeof(string), typeof(CaptionGuy),
new PropertyMetadata{PropertyChangedCallback = CaptionChanged});
private static void CaptionChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
CaptionGuy cg = d as CaptionGuy;
if (cg != null && e.NewValue!=null)
{
cg.CaptionLabel.Content = e.NewValue.ToString();
}
}
#endregion
然后你就可以像这样在WPF应用程序中部署它了……
Then you can deploy it in a WPF application like this...
<Grid>
<chainBinding:CaptionGuy Caption="{Binding VmCaption}"/>
</Grid>
相应的视图模型(或代码隐藏,如果那是你的设计)看起来像这样......
And the corresponding View Model (or code-behind if that's your design) would look like this...
public class ViewModel : INotifyPropertyChanged
{
public ViewModel()
{
Dispatcher dispatcher = Dispatcher.CurrentDispatcher;
DispatcherTimer dt = new DispatcherTimer(new TimeSpan(0,0,0,5), DispatcherPriority.Normal,
delegate
{
VmCaption = DateTime.Now.ToString("G");
}, dispatcher);
dt.Start();
}
private string _vmCaption;
public string VmCaption
{
[DebuggerStepThrough]
get { return _vmCaption; }
[DebuggerStepThrough]
set
{
if (value != _vmCaption)
{
_vmCaption = value;
OnPropertyChanged("VmCaption");
}
}
}
#region INotifyPropertyChanged Implementation
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string name)
{
var handler = System.Threading.Interlocked.CompareExchange(ref PropertyChanged, null, null);
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
#endregion
}
这个例子只是每 5 秒更新一次标题.
This example just updates the caption with the time every 5 seconds.
当然,这个答案在依赖属性上使用回调,但这是一个环境实用性胜过声明式编程的问题.
Of course this answer uses a callback on the dependency property, but this is a matter where circumstantial practicality wins out over declarative programming.
这篇关于WPF 链绑定的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!