2017-03-06 62 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