C# 绑定自定义用户控件的 DependencyProperty 不会在更改时更新
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/16471876/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Binding on DependencyProperty of custom User Control not updating on change
提问by user2367999
I'm having difficulties with databinding on my custom user control (s). I created an example project to highlight my problem. I'm completely new to WPF and essentially MVVM as well, so bear with me...
我在自定义用户控件上进行数据绑定时遇到困难。我创建了一个示例项目来突出我的问题。我是 WPF 的新手,基本上也是 MVVM,所以请耐心等待...
I created a simple view that uses databinding two ways. The databinding on the built-in control works just fine. My custom control doesn't... I put a breakpoint in the PropertyChangedCallbackof my control. It gets hit once on startup, but then never again. Meanwhile, the label I have bound to the same value is happily counting down.
我创建了一个简单的视图,它以两种方式使用数据绑定。内置控件上的数据绑定工作正常。我的自定义控件没有...我在PropertyChangedCallback我的控件中放置了一个断点。它在启动时被击中一次,但以后再也不会被击中。同时,我绑定到相同值的标签正在愉快地倒计时。
What am I missing? My example project follows:
我错过了什么?我的示例项目如下:
The main window:
主窗口:
<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>
Here's my model:
这是我的模型:
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
}
}
The ViewModel:
视图模型:
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;
}
}
}
Here's the XAML for my user control:
这是我的用户控件的 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>
And here's the code behind the user control:
这是用户控件背后的代码:
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();
}
}
}
采纳答案by XAMeLi
Your change callback is breaking the binding.
您的更改回调正在破坏绑定。
As a skeleton: in your window you have UC.X="{Binding A}"and then in that property change (in UC) you have X=B;. This breaks the binding since in both cases you set X.
作为一个骨架:在您的窗口中,您拥有UC.X="{Binding A}",然后在该属性更改(在 UC 中)中,您拥有X=B;. 这打破了绑定,因为在这两种情况下您都设置了X.
To rectify, remove change callback and add this to the label:
要纠正,请删除更改回调并将其添加到标签中:
Content="{Binding MinutesRemaining, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}}"
回答by Nivid Dholakia
I tried your code works fine the only change i made was to remove the code behind propertychangedcallback you have and databind the Label (Readout) to the dependency property.
我试过你的代码工作正常,我所做的唯一改变是删除你拥有的 propertychangedcallback 背后的代码,并将标签(读出)数据绑定到依赖属性。
USERCONTROL(XAML)
用户控制(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>
USERCONTROL (CODE BEHIND)
用户控制(代码隐藏)
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();
}
}

