【问题标题】:Binding on DependencyProperty of custom User Control not updating on change自定义用户控件的 DependencyProperty 绑定未在更改时更新
【发布时间】:2013-05-04 12:36:15
【问题描述】:

我在自定义用户控件上的数据绑定方面遇到困难。我创建了一个示例项目来突出我的问题。我对 WPF 和本质上的 MVVM 都是全新的,所以请耐心等待......

我创建了一个简单的视图,它以两种方式使用数据绑定。内置控件上的数据绑定工作得很好。我的自定义控件没有...我在我的控件的PropertyChangedCallback 中放置了一个断点。它在启动时被击中一次,但以后再也不会。同时,我绑定到相同值的标签正在愉快地倒计时。

我错过了什么?我的示例项目如下:

主窗口:

<Window x:Class="WpfMVVMApp.MainWindow"
        xmlns:local="clr-namespace:WpfMVVMApp"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Grid.DataContext>
            <local:CountdownViewModel />
        </Grid.DataContext>
        <Label Name="custName" Content="{Binding Path=Countdown.ChargeTimeRemaining_Mins}" Height="45" VerticalAlignment="Top"></Label>
        <local:UserControl1 MinutesRemaining="{Binding Path=Countdown.ChargeTimeRemaining_Mins}" Height="45"></local:UserControl1>
    </Grid>
</Window>

这是我的模型:

namespace WpfMVVMApp
{

    public class CountdownModel : INotifyPropertyChanged
    {
        private int chargeTimeRemaining_Mins;
        public int ChargeTimeRemaining_Mins
        {
            get
            {
                return chargeTimeRemaining_Mins;
            }
            set
            {
                chargeTimeRemaining_Mins = value;
                OnPropertyChanged("ChargeTimeRemaining_Mins");
            }
        }

        #region INotifyPropertyChanged Members
        public event PropertyChangedEventHandler PropertyChanged;
        private void OnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
        #endregion 
    }
}

视图模型:

namespace WpfMVVMApp
{
    public class CountdownViewModel
    {
        public CountdownModel Countdown { get; set; }

        DispatcherTimer timer;
        private const int maxMins = 360;

        public CountdownViewModel()
        {
            Countdown = new CountdownModel { ChargeTimeRemaining_Mins = 60 };

            // Setup timers
            timer = new DispatcherTimer();
            timer.Tick += new EventHandler(this.SystemChargeTimerService);
            timer.Interval = new TimeSpan(0, 0, 1);
            timer.Start();
        }

        private void SystemChargeTimerService(object sender, EventArgs e)
        {
            //convert to minutes remaining
            // DEMO CODE - TODO: Remove
            this.Countdown.ChargeTimeRemaining_Mins -= 1;
        }
    }
}

这是我的用户控件的 XAML:

<UserControl x:Class="WpfMVVMApp.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">
    <Grid>
        <Label Name="Readout"></Label>
    </Grid>
</UserControl>

这是用户控件背后的代码:

namespace WpfMVVMApp
{
    public partial class UserControl1 : UserControl
    {
        #region Dependency Properties
        public static readonly DependencyProperty MinutesRemainingProperty =
                    DependencyProperty.Register
                    (
                        "MinutesRemaining", typeof(int), typeof(UserControl1),
                        new UIPropertyMetadata(10, new PropertyChangedCallback(minutesRemainChangedCallBack))
                    );
        #endregion

        public int MinutesRemaining
        {
            get
            {
                return (int)GetValue(MinutesRemainingProperty);
            }
            set
            {
                SetValue(MinutesRemainingProperty, value);
            }
        }

        static void minutesRemainChangedCallBack(DependencyObject property, DependencyPropertyChangedEventArgs args)
        {
            UserControl1 _readout = (UserControl1)property;
            _readout.MinutesRemaining = (int)args.NewValue;

            _readout.Readout.Content = _readout.MinutesRemaining;
        }

        public UserControl1()
        {
            InitializeComponent();
        }
    }
}

【问题讨论】:

    标签: c# wpf data-binding user-controls dependency-properties


    【解决方案1】:

    您的更改回调正在破坏绑定。

    作为一个骨架:在您的窗口中您有UC.X="{Binding A}",然后在该属性更改中(在 UC 中)您有X=B;。这会破坏绑定,因为在这两种情况下您都设置了X

    要纠正,删除更改回调并将其添加到标签:

     Content="{Binding MinutesRemaining, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}}"
    

    【讨论】:

    • 感谢您的回复。绑定确实有效。然而,我创建依赖属性的原因是因为我想做的不仅仅是在我的实际程序中设置一个标签(这只是一个简单的例子)。我现在看到我在更改回调中为 MinutesRemaining 分配了一个值,这破坏了原始绑定。我注释掉了那行,现在它可以按预期工作了。
    【解决方案2】:

    我试过你的代码工作正常,我所做的唯一更改是删除你拥有的 propertychangedcallback 后面的代码,并将标签(读出)数据绑定到依赖属性。

    用户控制(XAML)

    <UserControl x:Class="WpfApplication1.UserControl"
             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>
           <Label Name="Readout" Content="{Binding RelativeSource={RelativeSource 
                                AncestorType=UserControl}, Path=MinutesRemaining}"/>
      </Grid>
    </UserControl>
    

    用户控制(代码隐藏)

    public partial class UserControl1 : UserControl
    {
        #region Dependency Properties
        public static readonly DependencyProperty MinutesRemainingProperty =
                    DependencyProperty.Register
                    (
                        "MinutesRemaining", typeof(int), typeof(UserControl1),
                        new UIPropertyMetadata(10)
                    );
        #endregion
    
        public int MinutesRemaining
        {
            get
            {
                return (int)GetValue(MinutesRemainingProperty);
            }
            set
            {
                SetValue(MinutesRemainingProperty, value);
            }
        }
    
       public UserControl1()
        {
            InitializeComponent();
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-04-02
      • 2011-08-06
      • 1970-01-01
      • 2011-01-18
      • 1970-01-01
      • 2011-02-20
      相关资源
      最近更新 更多