c# - 绑定无法通过自定义控件
问题描述
我正在尝试制作一个 WPF 用户控件,该控件可以倒计时到特定日期并将文本变为红色以在剩余指定时间跨度时提醒用户。
当我传入静态参数时,我的代码按计划工作。当我传入绑定参数时,我的代码失败。
这是我的调用代码;
<!-- WORKS (STATIC PARAMETERS) -->
<controls:TextEditDateCountDown
AlertAtMinutesLeft="2100"
DateStampCountDownTo="{Binding Source={x:Static system:DateTime.Now},StringFormat='HH:mm:ss tt'}" />
<!-- DOES NOT WORK (BOUND PARAMETERS) -->
<controls:TextEditDateCountDown
AlertAtMinutesLeft="2100"
DateStampCountDownTo="{Binding Entity.MarketDescription.SuspendTime,Mode=OneTime}"/>
<!-- DOES NOT WORKING (BOUND PARAMETERS TRYING PRIORITY BINDING AS AT http://www.blackwasp.co.uk/WPFPriorityBinding.aspx) -->
<controls:TextEditDateCountDown
AlertAtMinutesLeft="2100">
<controls:TextEditDateCountDown.DateStampCountDownTo>
<PriorityBinding>
<Binding Path="Entity.MarketDescription.SuspendTime" Mode="OneTime" IsAsync="True"/>
<Binding Path="Entity.MarketId" Mode="OneTime" IsAsync="True"/>
</PriorityBinding>
</controls:TextEditDateCountDown.DateStampCountDownTo>
</controls:TextEditDateCountDown>
控制代码如下所示;
<!-- THE XAML -->
<Grid>
<dxe:TextEdit
x:Name="myTextEdit"
IsPrintingMode="True"
Mask="dd\d HH\h mm\m ss\s"
MaskType="DateTimeAdvancingCaret"
MaskUseAsDisplayFormat="True">
<dxe:TextEdit.Style>
<Style TargetType="dxe:TextEdit">
<Style.Triggers>
<DataTrigger Value="True" Binding="{Binding IsAlertOn, RelativeSource={RelativeSource AncestorType=controls:TextEditDateCountDown},Mode=OneTime}">
<Setter Property="Foreground" Value="Red" />
<Setter Property="FontWeight" Value="Bold" />
</DataTrigger>
<DataTrigger Value="False" Binding="{Binding IsAlertOn, RelativeSource={RelativeSource AncestorType=controls:TextEditDateCountDown},Mode=OneTime}"> <Setter Property="Foreground" Value="Black" />
<Setter Property="FontWeight" Value="Regular" />
</DataTrigger>
</Style.Triggers>
</Style>
</dxe:TextEdit.Style>
</dxe:TextEdit>
</Grid>
<!-- THE CODE BEHIND -->
public partial class TextEditDateCountDown : UserControl {
public TextEditDateCountDown() {
InitializeComponent();
timer.Interval = new TimeSpan(0, 0, 1);
timer.Tick += Timer_Tick;
timer.Start();
}
DispatcherTimer timer = new DispatcherTimer();
public static readonly DependencyProperty DateStampCountDownToProperty = DependencyProperty.Register("DateStampCountDownTo", typeof(DateTime), typeof(TextEditDateCountDown), new PropertyMetadata(DateTime.MinValue, CountDownToChanged));
public static readonly DependencyProperty AlertAtMinutesLeftProperty = DependencyProperty.Register("AlertAtMinutesLeft", typeof(string), typeof(TextEditDateCountDown), new PropertyMetadata(string.Empty, Changed));
public static readonly DependencyProperty IsAlertOnProperty = DependencyProperty.Register("IsAlertOn", typeof(bool), typeof(TextEditDateCountDown), new PropertyMetadata(false));
public DateTime? DateStampCountDownTo {
get {
return (DateTime?)GetValue(DateStampCountDownToProperty);
}
set { SetValue(DateStampCountDownToProperty, value); }
}
public virtual string AlertAtMinutesLeft {
get {
return (string)GetValue(AlertAtMinutesLeftProperty);
}
set { SetValue(AlertAtMinutesLeftProperty, value); }
}
public bool IsAlertOn {
get { return (bool)GetValue(IsAlertOnProperty); }
set { SetValue(IsAlertOnProperty, value); }
}
private bool UpdateIsAlertOn(string value) {
if (value != null && value != "") {
int i = int.Parse(AlertAtMinutesLeft);
return DateTime.Now > DateStampCountDownTo.Value.AddMinutes(i);
} else
return false;
}
private DateTime? UpdateDateStampCountDownTo(DateTime? value) {
return DateStampCountDownTo.Value;
}
private static void Changed(DependencyObject d, DependencyPropertyChangedEventArgs e) {
var textEditControl = d as TextEditDateCountDown;
if (textEditControl == null) return;
textEditControl.IsAlertOn = textEditControl.UpdateIsAlertOn(textEditControl.AlertAtMinutesLeft);
}
private static void CountDownToChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) {
var textEditControl = d as TextEditDateCountDown;
if (textEditControl == null) return;
textEditControl.DateStampCountDownTo = textEditControl.UpdateDateStampCountDownTo(textEditControl.DateStampCountDownTo);
}
void Timer_Tick(object sender, EventArgs e) {
if (DateStampCountDownTo != null) {
TimeSpan t = DateStampCountDownTo.Value - TimeProvider.Current.UtcNow;
myTextEdit.MaskType = MaskType.None;
if (t < TimeSpan.Zero) {
myTextEdit.MaskType = MaskType.None;
myTextEdit.EditValue = "Closed";
}
myTextEdit.EditValue = t;
} else {
myTextEdit.EditValue = null;
}
}
}
这是一个复杂的问题(我希望不会因为使用 DevExpress 的 Textedit 控件而变得复杂)。我想知道是否有人给我任何关于我应该去哪里修复它的指示?(或如何解决)。谢谢你的时间。
UPDATE1:我不知道为什么,但是;此事件处理程序从不运行 -> private static void CountDownToChanged(DependencyObj... 此事件处理程序执行 -> private static void Changed(DependencyObj...
问题可能出在 DependencyProperty 声明中吗?
UPDATE2:除了 update1,我还发现 CountDownToChanged 事件处理程序使用静态参数输入运行,但在使用绑定参数时不运行。
UPDATE3:我已更新此处的代码以删除 datacontext = 此代码。并且还更正了控件 xaml 中的相对绑定。
问题仍然存在。
更新4:好的。这是工作。经过数小时的无数次尝试后,老实说,我无法弄清楚我做了什么让它发挥作用。我怀疑 Clemens 链接副本是答案,我犯了某种形式的绑定错误,掩盖了它确实有效的事实。
出于这个原因,可能值得删除这篇文章,因为我不知道真正的解决方案,而且我怀疑没有人会觉得这很有用。
解决方案
你的Entity.MarketDescription.SuspendTime
班级看起来怎么样?
该属性SuspendTime
应实现接口INotifyPropertyChanged
以在每次更新时通知您的控件。
顺便说一句,我注意到Mode=OneTime
您的工作代码中没有。有什么理由吗?
这是实施 INPC 的示例
就像是:
public class MarketDescription : INotifyPropertyChanged
{
// implements your interface here
...
// your property to bind
private DateTime suspendTime;
public DateTime SuspendTime
{
get { return suspendTime; }
set
{
suspendTime = value;
NotifyPropertyChanged("SuspendTime");
}
}
}
推荐阅读
- reactjs - 如何在这个 Reactjs 文件中使用数组之前获取图像的高度和宽度
- python - 在 HTML 页面中加载 Django 中的静态文件
- java - 将 AWT 鼠标侦听器更改为 Swing 鼠标侦听器
- python - 如何更改依赖于输入和执行生成为 C# 中的字符串的代码的多个标签?
- python - python - 如何从ID未更改但状态已从低变为高的数据框中提取记录,反之亦然
- javascript - 发送后处理程序未检索表单数据
- python - 使用 Python 使用 re.match() 或 split() 提取 JSON 字符串中的 URL
- apache-spark - Spark Java union/concat Multiple Dataframe/sql in loop
- flutter - 从不同的 Isolate 调用顶级异步函数
- react-native - 如何通过单击反应本机中的一个平面列表图像来显示特定图像?