C# WPF链结合
我想这样做一个链绑定:在一个具有类似dependencyproperty的窗口中有一个具有dependencyproperty的usercontrol。我想将usercontrol的dependencyproperty绑定到窗口的dependencyproperty 我创建了一个示例项目来演示我的问题: UserControl1 XAML:C# WPF链结合,c#,wpf,xaml,user-controls,C#,Wpf,Xaml,User Controls,我想这样做一个链绑定:在一个具有类似dependencyproperty的窗口中有一个具有dependencyproperty的usercontrol。我想将usercontrol的dependencyproperty绑定到窗口的dependencyproperty 我创建了一个示例项目来演示我的问题: UserControl1 XAML: <UserControl x:Class="WpfApplication1.UserControl1" xmlns="htt
<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>
主窗口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>
问题是,当我将标题设置为“XXX”(窗口的)时,我希望它也通知usercontrol并更新其标题,但它没有。我希望尽可能避免附加依赖属性和代码隐藏。有什么想法吗
感谢您的努力。问题在于您的绑定。默认情况下,绑定在控件的DataContext属性上查找属性。每个绑定都有一个源,在您的例子中,它是控件的DataContext属性。因此,您的绑定将计算为DataContext.Caption。您真正想要的是生成绑定的源,即具有Caption属性的窗口。因此,按如下所示更改代码。我在我的机器上测试了它,它正常工作了。记住初始化窗口的标题属性 新的:
新的:
问题在于您的绑定。默认情况下,绑定在控件的DataContext属性上查找属性。每个绑定都有一个源,在您的例子中,它是控件的DataContext属性。因此,您的绑定将计算为DataContext.Caption。您真正想要的是生成绑定的源,即具有Caption属性的窗口。因此,按如下所示更改代码。我在我的机器上测试了它,它正常工作了。记住初始化窗口的标题属性 新的:
新的:
您可以创建一个用户控件,其内容如下:
<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>
然后您可以在WPF应用程序中部署它,如下所示
#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
<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秒更新一次标题
当然,这个答案使用了对dependency属性的回调,但这是一个环境实用性胜过声明性编程的问题。您可以创建一个用户控件,如下所示
<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>
然后您可以在WPF应用程序中部署它,如下所示
#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
<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秒更新一次标题
当然,这个回答使用依赖属性的回调,但是这是一个间接的实用性胜过声明性编程的问题。
在用户控件的DP声明中,您是否考虑挂起属性更改的回调?这应该会带来您所追求的行为。我有这个想法,但我追求的是一个解决方案,如果有代码隐藏的话,那么代码就更少了。关于数据上下文冲突,请参见下面Kess的回答。但以依赖项属性中的三行代码为代价,您正在创建一个Xaml的matryoshka,而没有实际回报。@GarryVass我想我最终会同意您的建议,如果您将其作为答案编写,我会将其标记为已接受。@GarryVass Sure:。。。我只是想关闭这个问题并给予您信任。在用户控件的DP声明中,您是否考虑挂起属性更改的调用?这应该会带来您所追求的行为。我有这个想法,但我追求的是一个解决方案,如果有代码隐藏的话,那么代码就更少了。关于数据上下文冲突,请参见下面Kess的回答。但以依赖项属性中的三行代码为代价,您正在创建一个Xaml的matryoshka,而没有实际回报。@GarryVass我想我最终会同意您的建议,如果您将其作为答案编写,我会将其标记为已接受。@GarryVass Sure:。。。我只想结束这个问题,给你一个积分。服务的所有部分:)及时编辑会给你一个10分,否则会受到影响!使用Xaml的按钮:)感谢您的回答,我刚刚尝试了它,但不幸的是它似乎没有帮助-设置将标签的内容设置为其(RelativeSource Self)属性标题,该标题不存在(或者我错了吗?)。和Caption=“{Binding Path=Caption,RelativeSource={RelativeSource Mode=Self},Mode=OneWay}”将usercontrol的Caption属性设置为其自己的属性Caption,使其无效(或者我错了吗?)。然而,我可能误解了一些事情……我已经更新了答案。如果用户控件位于主窗口上,则需要从可视树中查找属性。上述解决方案应该有效。谢谢。我已经在Window.xaml中将datacontext设置为Window-在。。。同样,在用户控件中,这取决于您正在做什么。但是,数据上下文通常是为视图模型保留的,因此这可能不是一个好主意。在您的情况下,您只需要从可视树绑定到所需的源。服务的所有部分:)及时编辑为您赢得了10分,否则将受到危害!使用Xaml的按钮:)感谢您的回答,我刚刚尝试了它,但不幸的是它似乎没有帮助-设置将标签的内容设置为其(RelativeSource Self)属性标题,该标题不存在(或者我错了吗?)。和Caption=“{Binding Path=Caption,RelativeSource={RelativeSource Mode=Self},Mode=OneWay}”将usercontrol的Caption属性设置为其自己的属性Caption,使其无效(或者我错了吗?)。然而,我可能误解了一些事情……我已经更新了答案。如果用户控件位于主窗口上,则需要从可视树中查找属性。上述解决方案应该有效。谢谢。我已经在Window.xaml中将datacontext设置为Window-在。。。同样,在用户控件中,这取决于您正在做什么。但是,数据上下文通常是为视图模型保留的,因此这可能不是一个好主意。在你的情况下,你只想结合到酸