表达式交互数据触发器最终未正确显示绑定值

时间:2017-03-06 21:00:31

标签: c# .net wpf xaml expression-blend

我有一个表达式交互DataTrigger,它根据绑定的Text属性更改TextBlock的{​​{1}}属性。当该值大于或等于TimeSpan时,文本将是属性的值。当该值小于零时,该值将更改为“??:??:??”。

相关代码如下:

Timespan.Zero

<i:Interaction.Triggers> <ei:DataTrigger Binding="{Binding InspectionService.TimeRemainingForPart}" Comparison="GreaterThanOrEqual" Value="{x:Static sys:TimeSpan.Zero}"> <ei:ChangePropertyAction PropertyName="Text" Value="{Binding InspectionService.TimeRemainingForPart}" /> </ei:DataTrigger> <ei:DataTrigger Binding="{Binding InspectionService.TimeRemainingForPart}" Comparison="LessThan" Value="{x:Static sys:TimeSpan.Zero}"> <ei:ChangePropertyAction PropertyName="Text" Value="??:??:??" /> </ei:DataTrigger> </i:Interaction.Triggers> 属性通过TimeRemainingForPart中的计时器更新。当计时器运行时,一切都很好。当计时器停止时(将InspectionService设置为Timespan.Zero),视图将按预期显示“00:00:00”。但是,当应用程序首次加载时,文本块中不会显示任何内容。我甚至尝试更改值/通知属性更改TimeRemainingForPart的构造函数,但没有任何反应。

我总是可以使用名为“TimespanLessThanZeroConverter”的转换器或其他类似的转换到标准的WPF DataTrigger,但是当应用程序启动时,为什么我正在做的当前方式不起作用的任何想法?

编辑:忘记提及我曾尝试在我的构造函数中为TimeRemainingForPart属性调用OnPropertyChanged,以防万一没有得到正确的通知,但似乎没有完成任何事情。

Edit2:为Textblock添加完整的XAML以及ViewModel和Service的相关部分。

XAML:

InspectionService

视图模型:

<TextBlock Grid.Row="1" FontSize="56" FontWeight="Bold" Text="{Binding InspectionService.TimeRemainingForPart}">
    <TextBlock.Style>
        <Style TargetType="TextBlock" BasedOn="{StaticResource StatusIndicatorTextBlockStyle}">
            <Style.Triggers>
                <DataTrigger Binding="{Binding InspectionService.InspectionExecutionState}" Value="{x:Static enum:InspectionExecutionStates.Paused}">
                    <DataTrigger.EnterActions>
                        <BeginStoryboard>
                            <Storyboard Duration="0:0:1" AutoReverse="True" RepeatBehavior="Forever">
                                <ColorAnimation Storyboard.TargetProperty="Foreground.(SolidColorBrush.Color)" To="Transparent" />
                            </Storyboard>
                        </BeginStoryboard>
                    </DataTrigger.EnterActions>

                    <DataTrigger.ExitActions>
                        <BeginStoryboard>
                            <Storyboard Duration="0:0:1">
                                <ColorAnimation Storyboard.TargetProperty="Foreground.(SolidColorBrush.Color)" To="White" />
                            </Storyboard>
                        </BeginStoryboard>
                    </DataTrigger.ExitActions>
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </TextBlock.Style>

    <i:Interaction.Triggers>
        <ei:DataTrigger Binding="{Binding InspectionService.TimeRemainingForPart}" Comparison="GreaterThanOrEqual" Value="{x:Static sys:TimeSpan.Zero}">
            <ei:ChangePropertyAction PropertyName="Text" Value="{Binding InspectionService.TimeRemainingForPart}" />
        </ei:DataTrigger>

        <ei:DataTrigger Binding="{Binding InspectionService.TimeRemainingForPart}" Comparison="LessThan" Value="{x:Static sys:TimeSpan.Zero}">
            <ei:ChangePropertyAction PropertyName="Text" Value="??:??:??" />
        </ei:DataTrigger>
    </i:Interaction.Triggers>
</TextBlock>

服务:

public class MyViewModel : IMyViewModel
{
    public IInspectionService InspectionService { get; private set; }

    public MyViewModel (IInspectionService inspectionService)
    {
        this.InspectionService = inspectionService;
    }
}

编辑3:

显然,没有转换器就无法完成,所以TextBlock代码修改如下:

public class InspectionService : BindableBase, IInspectionService
{
    private readonly IModeService _modeService;
    private readonly IRemainingTimeFileServiceFactory _remainingTimeFileServiceFactory;

    private string _inspectionCell;

    private readonly DispatcherTimer _timeRemainingForPartTimer;

    #region IInspectionService Members

    private InspectionExecutionStates _inspectionExecutionState;
    public InspectionExecutionStates InspectionExecutionState
    {
        get { return this._inspectionExecutionState; }
        private set { this.SetProperty(ref this._inspectionExecutionState, value); }

    private string _inspectionName;
    public string InspectionName
    {
        get { return this._inspectionName; }
        private set { this.SetProperty(ref this._inspectionName, value); }
    }

    private TimeSpan _timeRemainingForPart;
    public TimeSpan TimeRemainingForPart
    {
        get { return this._timeRemainingForPart; }
        private set { this.SetProperty(ref this._timeRemainingForPart, value); }

    private TimeSpan _totalTimeRemaining;
    public TimeSpan TotalTimeRemaining
    {
        get { return this._totalTimeRemaining; }
        private set { this.SetProperty(ref this._totalTimeRemaining, value); }
    }

    #endregion

    public InspectionService(IModeService modeService, IRemainingTimeFileServiceFactory remainingTimeFileServiceFactory)
    {
        this._modeService = modeService;
        this._remainingTimeFileServiceFactory = remainingTimeFileServiceFactory;

        this._timeRemainingForPartTimer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(1) };
        this._timeRemainingForPartTimer.Tick += this.TimeRemainingForPartTimerOnTick;
    }

    private void StartSelectedInspection(InspectionPlanInfo inspectionPlanInfo)
    {
        this.SetInspectionProperties(inspectionPlanInfo);
        this.StartInspection
    }

    #endregion

    #region Private Methods

    private void StartInspection()
    {
        this.TotalTimeRemaining = this._remainingTimeFileServiceFactory.GetIRemainingTimeFileService(this._inspectionCell).GetInspectionTime(this.InspectionName);
        this.TimeRemainingForPart = this._modeService.IsStudyActive ? TimeSpan.MinValue : this.TotalTimeRemaining;
        this._timeRemainingForPartTimer.Start();
    }

    private void StopInspection()
    {
        this.ClearInspectionProperties();
        this._timeRemainingForPartTimer.Stop();
    }

    private void SetInspectionProperties(InspectionPlanInfo inspectionPlanInfo)
    {
        this.InspectionName = inspectionPlanInfo.InspectionName;
        this._inspectionCell = inspectionPlanInfo.Cell;
    }

    private void ClearInspectionProperties()
    {
        this.InspectionName = "";
        this.TimeRemainingForPart = TimeSpan.Zero;
        this.TotalTimeRemaining = TimeSpan.Zero;
    }

    private void TimeRemainingForPartTimerOnTick(object sender, EventArgs eventArgs)
    {
        if (this.TimeRemainingForPart < TimeSpan.Zero)
        {
            this._timeRemainingForPartTimer.Stop();
        }
        else
        {
            this.TimeRemainingForPart -= TimeSpan.FromSeconds(1);
            this.TotalTimeRemaining -= TimeSpan.FromSeconds(1);
        }
    }
}

为了完整性/后人的缘故,转换器看起来像这样:

<TextBlock Grid.Row="1" FontSize="56" FontWeight="Bold">
    <TextBlock.Style>
        <Style TargetType="TextBlock" BasedOn="{StaticResource StatusIndicatorTextBlockStyle}">
            <Setter Property="Text" Value="{Binding InspectionService.TimeRemainingForPart}" />

            <Style.Triggers>
                <DataTrigger Binding="{Binding InspectionService.TimeRemainingForPart, Converter={StaticResource TimespanLessThanZeroConverter}}"
                        Value="True">
                    <Setter Property="Text" Value="??:??:??" />
                </DataTrigger>

                <DataTrigger Binding="{Binding InspectionService.InspectionExecutionState}" Value="{x:Static enum:InspectionExecutionStates.Paused}">
                    <DataTrigger.EnterActions>
                        <BeginStoryboard>
                            <Storyboard Duration="0:0:1" AutoReverse="True" RepeatBehavior="Forever">
                                <ColorAnimation Storyboard.TargetProperty="Foreground.(SolidColorBrush.Color)" To="Transparent" />
                            </Storyboard>
                        </BeginStoryboard>
                    </DataTrigger.EnterActions>

                    <DataTrigger.ExitActions>
                        <BeginStoryboard>
                            <Storyboard Duration="0:0:1">
                                <ColorAnimation Storyboard.TargetProperty="Foreground.(SolidColorBrush.Color)" To="White" />
                            </Storyboard>
                        </BeginStoryboard>
                    </DataTrigger.ExitActions>
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </TextBlock.Style>
</TextBlock>

1 个答案:

答案 0 :(得分:1)

您是否将Text的{​​{1}}属性绑定到源属性?:

TextBox

然后,只需将<TextBlock Text="{Binding InspectionService.TimeRemainingForPart}"> <i:Interaction.Triggers> <ei:DataTrigger Binding="{Binding InspectionService.TimeRemainingForPart}" Comparison="LessThan" Value="{x:Static sys:TimeSpan.Zero}"> <ei:ChangePropertyAction PropertyName="Text" Value="??:??:??" /> </ei:DataTrigger> </i:Interaction.Triggers> </TextBlock> 属性设置为视图模型的构造函数中的默认值即可。

您已经注意到我已删除了第一个交互触发器。您最好将Text属性绑定到source属性并使用转换器而不是使用两个TimeRemainingForPart。或者绑定到视图模型的字符串属性,该属性根据ChangePropertyAction值返回正确的字符串。