1

我正在学习Dependency Properties.

Dependency Property在 aUserControl和我的 中创建了一个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>

主窗口.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
    }
}

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

我做错了什么,或者我试图做一些不该做的事情?

4

2 回答 2

1

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

MainWindow 用属性 StartTime TimeLine 实现 INotify 用户控件有 DP StartTime

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

<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>

主窗口后端

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(""));
}

现在,当您单击更改时间按钮时,用户控件会更新 MainWindow 属性。希望有帮助

于 2013-11-05T12:24:52.003 回答
0

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

但是,我想我还是找到了你的问题。尝试在您的TimeLine课程中删除以下行:

this.DataContext = this;

This should not be in the control, but only in the MainWindow.

Explanation:

In the MainWindow constructor you set the MainWindow's DataContext to itself. Child elements inherit their DataContext from their parent element if it is not explicitly set. Therefore, the DataContext of the TextBlock is also set to the MainWindow which is why the Binding works properly here. However, in all TimeLine instances, you set the DataContext explicitly to themselves (in the constructor), i.e. the TimeLine object. This way, the Binding on the TimeLine instance does not refer to the MainWindow's StartTime property, but to the property with the same name in the TimeLine control. However, this property is never set to any real value (only bound to itself which does not make sense). Therefore, nothing is displayed.

于 2013-11-05T13:15:29.003 回答