2017-03-06 35 views
1

我有一个表达式交互性DataTrigger,它基于约束TimeSpan属性更改TextBlockText属性。当该值大于或等于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定时器更新。当定时器运行时,一切都很好。当计时器停止时(将TimeRemainingForPart设置为Timespan.Zero),视图按预期显示“00:00:00”。但是,应用程序首次加载时,文本块中不显示任何内容。我甚至尝试过改变值/通知从InspectionService构造函数改变的属性,并没有任何反应。

我总是可以通过一个名为“TimespanLessThanZeroConverter”的转换器或者其他一些标准的WPF DataTrigger,但是对于为什么当前应用程序启动时无法工作的想法有任何想法?

编辑:忘了提我曾试图调用OnPropertyChanged的TimeRemainingForPart财产在我的构造函数以防万一没有得到正确通知服务,但这似乎并没有完成任何事情。

编辑2:为文本块和ViewModel和服务的相关部分添加完整的XAML。

XAML:

<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; 
    } 
} 

服务:

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); 
     } 
    } 
} 

编辑3:

那么显然它不能没有转换器这样做TextBlock代码是mo dified如下:

<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> 

而对于完整性/子孙后代着想转换器看起来是这样的:

using System; 
using System.Globalization; 
using System.Windows; 
using System.Windows.Data; 

namespace CurrentInspection.Converters 
{ 
    public class TimespanLessThanZeroConverter : IValueConverter 
    { 
     public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 
     { 
      if (!(value is TimeSpan)) 
      { 
       return false; 
      } 

      return (TimeSpan)value < TimeSpan.Zero; 
     } 

     public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 
     { 
      return DependencyProperty.UnsetValue; 
     } 
    } 
} 

回答

1

你的TextBoxText属性绑定到源属性,这样?:

<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> 

那么它应该只是将TimeRemainingForPart属性设置为视图模式构造函数中的默认值湖

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

+0

设置为默认会发生在服务的构造函数中,实际上(它继承了Prism中的'BindableBase')。但我已经尝试从构造函数中调用OnPropertyChanged,认为它可以工作,但事实并非如此。 (我应该更新我的问题,以表明我尝试了这个。) – GrantA

+0

请包括TextBlock和您的视图模型的完整标记。 – mm8

+0

我按要求添加了附加代码。 – GrantA