【问题标题】:Binding to dependancy property is not displaying value when bound绑定到依赖属性时绑定时不显示值
【发布时间】:2013-11-16 03:29:09
【问题描述】:

我正在了解Dependency Properties

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

我的问题是当我尝试使用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
    }
}

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

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

【问题讨论】:

  • 对不起,我的问题措辞不当,造成混乱。我已经重新措辞并重新发布了这个问题,请关闭这个问题。与Dependancy Properties 重复

标签: xaml binding dependency-properties


【解决方案1】:

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

MainWindow 使用属性 StartTime 实现 INotify TimeLine 用户控件具有 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 属性。 希望有帮助

【讨论】:

  • 我有点迷茫,这种方法不只是在按钮单击时直接将值设置为 UserControl 吗?这实际上并没有按照预期的方式使用 UserControl。还是我错过了重点?
  • 您希望如何使用用户控件?在您的原始代码中,您有 2 个同名的属性,因此基于我的回答。为什么你甚至需要用户控件?您是否在多个页面上使用用户控件?
  • 是的,它将被使用,我希望它“即插即用”。换句话说,有人在他们的页面上创建了我的控件的实例,可能每页多次,我希望他们只使用 XAML 并且控件执行它需要做的事情!
【解决方案2】:

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

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

this.DataContext = this;

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

说明:

在 MainWindow 构造函数中,您将 MainWindow 的 DataContext 设置为自身。如果未显式设置,子元素会从其父元素继承其DataContext。因此,TextBlockDataContext 也设置为 MainWindow,这就是 Binding 在这里正常工作的原因。但是,在所有TimeLine 实例中,您将DataContext 显式设置为它们自己(在构造函数中),即TimeLine 对象。这样,TimeLine 实例上的Binding 就不是引用MainWindowStartTime 属性,而是引用TimeLine 控件中的同名属性。但是,此属性永远不会设置为任何实际值(仅绑定到没有意义的自身)。因此,什么都没有显示。

【讨论】:

    猜你喜欢
    • 2016-01-22
    • 1970-01-01
    • 2023-03-26
    • 2018-05-21
    • 1970-01-01
    • 1970-01-01
    • 2023-04-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多