我想像这样进行链式绑定:我在一个具有类似dependencyproperty的窗口中有一个带有dependencyproperty的usercontrol。我想将usercontrol的dependencyproperty绑定到窗口的dependencyproperty。
我创建了一个示例项目来演示我的问题:
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#:
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();
}
}
MainWindow 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>
MainWindow 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();
}
}
当我将标题设置为&#34; XXX&#34; (窗口)我希望它也通知用户控件并更新其标题,但它没有。我想避免附加的依赖属性,尽可能避免代码落后。有什么想法吗?
感谢您的任何努力。
答案 0 :(得分:3)
问题出在你的绑定上。默认情况下,绑定会在控件的DataContext属性中查找属性。每个绑定都有一个源,在您的情况下它是控件的DataContext属性。所以你的绑定正在评估DataContext.Caption。你真正想要的是制作绑定源,即具有Caption属性的窗口。因此,请按照以下说明更改代码。我在我的机器上测试它,它的工作原理。请记住初始化窗口的Caption属性。
新:
<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">
<Grid>
<Grid>
<Label Content="{Binding Path=Caption, RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=UserControl}}"/>
</Grid>
</Grid>
新:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:current="clr-namespace:WpfApplication1"
Title="MainWindow" Height="350" Width="525" >
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<Label Content="{Binding Caption, Mode=OneWay, RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=Window}}"/>
<current:UserControl1 x:Name="uc" Caption="{Binding Path=Caption, Mode=OneWay, RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=Window}}" Grid.Row="1"/>
</Grid>
答案 1 :(得分:0)
您可以按照......
的方式创建用户控件<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>
...并使用您的依赖属性来检测它......
#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应用程序中部署它......
<Grid>
<chainBinding:CaptionGuy Caption="{Binding VmCaption}"/>
</Grid>
相应的视图模型(或代码隐藏,如果这是你的设计)看起来像这样......
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秒的时间更新标题。
当然这个答案在依赖属性上使用了一个回调,但这是一个在声明性编程方面胜过间接实用性的问题。