我有一个表达式交互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>
答案 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
值返回正确的字符串。