绑定无法通过自定义控件

时间:2018-06-05 02:43:10

标签: c# wpf xaml

我正在尝试制作一个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&#39; Textedit控件不会复杂化)。我想知道是否有人给我任何指示我应该去修复它的地方? (或如何解决它)。谢谢大家的时间。

UPDATE1: 我不知道为什么,但是; 此事件处理程序永远不会运行 - &gt; private static void CountDownToChanged(DependencyObj ... 此事件处理程序执行 - &gt; private static void已更改(DependencyObj ...

问题可能在DependencyProperty声明中吗?

UPDATE2: 继续update1之后,我还发现CountDownToChanged事件处理程序使用静态参数输入运行,但在使用bound参数时则不行。

UPDATE3: 我在这里更新了代码以删除datacontext =此代码。并且还纠正了对照的xaml中的相对结合。

仍然存在问题。

UPDATE4: 好。这是工作。经过几个小时的尝试,我真的无法弄清楚我做了什么让它发挥作用。我怀疑Clemens链接副本是答案,我做了某种形式的绑定错误,这掩盖了它确实有效的事实。

由于这个原因,可能值得删除这篇文章,因为我不知道真正的解决方案,我怀疑没有人会发现这个有用。

1 个答案:

答案 0 :(得分:0)

您的Entity.MarketDescription.SuspendTime课程如何?

属性SuspendTime应实现接口INotifyPropertyChanged,以便每次更新时通知您的控件。

顺便说一下,我注意到您的工作代码中没有Mode=OneTime。有什么理由吗?

Here是实施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");
        }
    }
}