绑定到依赖项属性时绑定时不显示值

时间:2013-11-05 09:46:28

标签: xaml binding dependency-properties

我正在学习Dependency Properties

我在Dependency Property中创建了UserControl,在MainWindow内,我创建了一个控件实例并设置了值。这可以按预期工作。

我的问题是当我尝试使用Binding时。

所以,我的MainWindow XAML看起来像(StartTime类型是字符串)

<Window x:Class="TimeLineCanvas.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:timeline="clr-namespace:TimeLineCanvas.UserControls"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <StackPanel>
            <TextBlock Text="{Binding StartTime}" Height="100" /><!--Works binding to local property-->
            <timeline:TimeLine StartTime="28/01/2015" Height="100" /><!--Works when hard coded value-->
            <timeline:TimeLine StartTime="{Binding StartTime, UpdateSourceTrigger=PropertyChanged}" Height="100" /><!-- Does not display anything -->            
             <timeline:TimeLine x:Name="TimeLineInXaml" Height="100" /><!-- Works (value set in code behind) -->            
        </StackPanel>
    </Grid>
</Window>

MainWindow.xaml.cs

using System;
using System.Windows;
using System.ComponentModel;

namespace TimeLineCanvas
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window, INotifyPropertyChanged
    {
        #region Constructors

        public MainWindow()
        {
            InitializeComponent();
            SetStartTime(DateTime.Now);
            TimeLineInXaml.StartTime = _startTime; 
            this.DataContext = this;
        }

        #endregion

        #region Properties

        private string _startTime;
        public string StartTime
        {
            get
            {
                return _startTime;
            }
            set
            {
                _startTime = value;
                OnPropertyChanged("StartTime");
            }
        }

        #endregion

        #region Methods

        internal void SetStartTime(DateTime dt)
        {
            this.StartTime = dt.ToShortDateString();
        }

        #endregion

        #region INotifyPropertyChanged Implementation

        public void OnPropertyChanged(string PropertyName)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(PropertyName));
        }

        public event PropertyChangedEventHandler PropertyChanged;

        #endregion INotify
    }
}

我的用户控件

<UserControl x:Class="TimeLineCanvas.UserControls.TimeLine"
             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>
        <Canvas>
            <TextBlock Text="{Binding StartTime, UpdateSourceTrigger=PropertyChanged}" />
        </Canvas>           
    </Grid>
</UserControl>

以及我的UserControl背后的代码

using System;
using System.Windows;
using System.Windows.Controls;
using System.ComponentModel;

namespace TimeLineCanvas.UserControls
{
    /// <summary>
    /// Interaction logic for TimeLine.xaml
    /// </summary>
    public partial class TimeLine : UserControl, INotifyPropertyChanged
    {
        #region Constructor

        public TimeLine()
        {
            InitializeComponent();
            this.DataContext = this;
        }

        #endregion

        #region Dependancy Properties

        public static readonly DependencyProperty StartTimeProperty = DependencyProperty.Register(
            "StartTime",
            typeof(string),
            typeof(TimeLine));

        #endregion

        #region Properties

        public string StartTime
        {
            get { return (string)GetValue(TimeLine.StartTimeProperty); }
            set
            {
                DateTime result;
                if (!DateTime.TryParse(value, out result))
                    System.Diagnostics.Debug.Assert(false, "Expected a value which can be converted to a DateTime");

                SetValue(TimeLine.StartTimeProperty, value);
            }
        }

        #endregion


        #region INotifyPropertyChanged Implementation

        public void OnPropertyChanged(string PropertyName)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(PropertyName));
        }

        public event PropertyChangedEventHandler PropertyChanged;

        #endregion INotify
    }
}

所以,问题很清楚,这是绑定,但我不知道如何解决这个问题!甚至我的Voodoo编程(按随机顺序尝试任何事情和所有内容)基于其他建议(例如将DataContext="{Binding RelativeSource={RelativeSource Self}}添加到UserControl,将INotifyPropertyChanged添加到MainWindow和UserContorl)都不会影响结果。

我做错了什么,或者我想做一些不适合做的事情?

2 个答案:

答案 0 :(得分:1)

几乎只需简化您对Binding的理解。 请记住,这里有2个装订

MainWindow使用Property StartTime实现INotify TimeLine用户控件具有DP StartTime

所以MainWindow绑定到MainWindow.cs中的StartTime属性NB Button来测试时间的变化

<Grid>
    <StackPanel>          
        <timeline:TimeLine x:Name="myTime" StartTime="{Binding StartTime, Mode=TwoWay}" Height="100" /> 
        <Button Content="Change Time"  Width="200" Height="100" Click="Button_Click"/>                 
    </StackPanel>
</Grid>

MainWindow的后端

public partial class MainWindow : Window, INotifyPropertyChanged
{
    #region Constructors

    public MainWindow()
    {
        InitializeComponent();           
        this.DataContext = this;
            Loaded += (s, args) =>
            {
                this.myTime.StartTime = "Some Time";
            };
    }

    #endregion

    #region Properties

    private string _startTime;
    public string StartTime
    {
        get
        {
            return _startTime;
        }
        set
        {
            _startTime = value;
            OnPropertyChanged("StartTime");
        }
    }

    #endregion       

    #region INotifyPropertyChanged Implementation

    public void OnPropertyChanged(string PropertyName)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(PropertyName));
    }

    public event PropertyChangedEventHandler PropertyChanged;

    #endregion INotify

     private void Button_Click(object sender, RoutedEventArgs e)
     {
        // We are changing usercontrol StartTime DP which updates or property in main             //window
        this.myTime.StartTime = "A new TIME";
     }
}

}

UserControl(在后端绑定到DP)

<Grid>
    <Canvas>
        <TextBlock Text="{Binding StartTime}" />
    </Canvas>           
</Grid>

UserControl后端只有DP

public partial class TimeLine : UserControl
{
    #region Constructor

    public TimeLine()
    {
        InitializeComponent();           
    }

    public string StartTime
    {
        get { return (string)GetValue(StartTimeProperty); }
        set { SetValue(StartTimeProperty, value); }
    }

    // Using a DependencyProperty as the backing store for StartTime.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty StartTimeProperty =
        DependencyProperty.Register("StartTime", typeof(string), typeof(TimeLine), new PropertyMetadata(""));
}

现在,当您单击“更改时间”按钮时,usercontrol将更新MainWindow属性。 希望有所帮助

答案 1 :(得分:0)

您的代码有点混乱,因为您有重复的属性名称,并且在“Voodoo编程”期间显然已经测试了很多。 :)

然而,无论如何,我认为我发现了你的问题。尝试删除TimeLine类中的以下行:

this.DataContext = this;

这不应该在控件中,而只能在MainWindow

<强>解释

在MainWindow构造函数中,将MainWindow的DataContext设置为自身。如果未明确设置,子元素将从其父元素继承其DataContext。因此,DataContext的{​​{1}}也设置为MainWindow,这就是TextBlock在此正常工作的原因。但是,在所有Binding个实例中,您将TimeLine显式设置为自身(在构造函数中),即DataContext对象。这样,TimeLine实例上的Binding不会引用TimeLine的{​​{1}}属性,而是引用MainWindow中具有相同名称的属性} 控制。但是,此属性永远不会设置为任何实际值(仅绑定到自身没有意义)。因此,不显示任何内容。