WPF 链绑定 [英] WPF Chain Binding

查看:16
本文介绍了WPF 链绑定的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想像这样进行链式绑定:我在一个窗口内有一个具有依赖属性的用户控件,该窗口具有类似的依赖属性.我想将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 链绑定的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆