CopyCommand detail: speed
This commit is contained in:
@@ -5,5 +5,6 @@ public interface ICommandTimeStateViewModel
|
|||||||
IObservable<int> TotalProgress { get; }
|
IObservable<int> TotalProgress { get; }
|
||||||
IObservable<int> CurrentProgress { get; }
|
IObservable<int> CurrentProgress { get; }
|
||||||
IObservable<string> DisplayLabel { get; }
|
IObservable<string> DisplayLabel { get; }
|
||||||
|
IObservable<string> DisplayDetailLabel { get; }
|
||||||
IObservable<bool> IsSelected { get; }
|
IObservable<bool> IsSelected { get; }
|
||||||
}
|
}
|
||||||
@@ -9,12 +9,14 @@ public class CommandTimeStateViewModel : ICommandTimeStateViewModel
|
|||||||
public IObservable<int> CurrentProgress { get; }
|
public IObservable<int> CurrentProgress { get; }
|
||||||
|
|
||||||
public IObservable<string> DisplayLabel { get; }
|
public IObservable<string> DisplayLabel { get; }
|
||||||
|
public IObservable<string> DisplayDetailLabel { get; }
|
||||||
|
|
||||||
public IObservable<bool> IsSelected { get; }
|
public IObservable<bool> IsSelected { get; }
|
||||||
|
|
||||||
public CommandTimeStateViewModel(CommandTimeState commandTimeState)
|
public CommandTimeStateViewModel(CommandTimeState commandTimeState)
|
||||||
{
|
{
|
||||||
DisplayLabel = commandTimeState.Command.DisplayLabel;
|
DisplayLabel = commandTimeState.Command.DisplayLabel;
|
||||||
|
DisplayDetailLabel = commandTimeState.Command.DisplayDetailLabel;
|
||||||
TotalProgress = commandTimeState.Command.TotalProgress;
|
TotalProgress = commandTimeState.Command.TotalProgress;
|
||||||
CurrentProgress = commandTimeState.Command.CurrentProgress;
|
CurrentProgress = commandTimeState.Command.CurrentProgress;
|
||||||
//TODO
|
//TODO
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ namespace FileTime.Core.Command;
|
|||||||
public interface ICommand
|
public interface ICommand
|
||||||
{
|
{
|
||||||
IObservable<string> DisplayLabel { get; }
|
IObservable<string> DisplayLabel { get; }
|
||||||
|
IObservable<string> DisplayDetailLabel { get; }
|
||||||
IObservable<int> TotalProgress { get; }
|
IObservable<int> TotalProgress { get; }
|
||||||
IObservable<int> CurrentProgress { get; }
|
IObservable<int> CurrentProgress { get; }
|
||||||
|
|
||||||
|
|||||||
@@ -7,20 +7,24 @@ namespace FileTime.Core.Command;
|
|||||||
public abstract class CommandBase : ICommand
|
public abstract class CommandBase : ICommand
|
||||||
{
|
{
|
||||||
private readonly BehaviorSubject<string> _displayLabel;
|
private readonly BehaviorSubject<string> _displayLabel;
|
||||||
|
private readonly BehaviorSubject<string> _displayDetailLabel;
|
||||||
private readonly BehaviorSubject<int> _totalProgress;
|
private readonly BehaviorSubject<int> _totalProgress;
|
||||||
private readonly BehaviorSubject<int> _currentProgress;
|
private readonly BehaviorSubject<int> _currentProgress;
|
||||||
|
|
||||||
public IObservable<string> DisplayLabel { get; }
|
public IObservable<string> DisplayLabel { get; }
|
||||||
|
public IObservable<string> DisplayDetailLabel { get; }
|
||||||
public IObservable<int> TotalProgress { get; }
|
public IObservable<int> TotalProgress { get; }
|
||||||
public IObservable<int> CurrentProgress { get; }
|
public IObservable<int> CurrentProgress { get; }
|
||||||
|
|
||||||
protected CommandBase(string displayLabel = "", int totalProgress = 0, int currentProgress = 0)
|
protected CommandBase(string displayLabel = "", string displayDetailLabel = "", int totalProgress = 0, int currentProgress = 0)
|
||||||
{
|
{
|
||||||
_displayLabel = new(displayLabel);
|
_displayLabel = new(displayLabel);
|
||||||
|
_displayDetailLabel = new(displayDetailLabel);
|
||||||
_totalProgress = new(totalProgress);
|
_totalProgress = new(totalProgress);
|
||||||
_currentProgress = new(currentProgress);
|
_currentProgress = new(currentProgress);
|
||||||
|
|
||||||
DisplayLabel = _displayLabel.AsObservable();
|
DisplayLabel = _displayLabel.AsObservable();
|
||||||
|
DisplayDetailLabel = _displayDetailLabel.AsObservable();
|
||||||
TotalProgress = _totalProgress.AsObservable();
|
TotalProgress = _totalProgress.AsObservable();
|
||||||
CurrentProgress = _currentProgress.AsObservable();
|
CurrentProgress = _currentProgress.AsObservable();
|
||||||
}
|
}
|
||||||
@@ -28,7 +32,8 @@ public abstract class CommandBase : ICommand
|
|||||||
public abstract Task<CanCommandRun> CanRun(PointInTime currentTime);
|
public abstract Task<CanCommandRun> CanRun(PointInTime currentTime);
|
||||||
public abstract Task<PointInTime> SimulateCommand(PointInTime currentTime);
|
public abstract Task<PointInTime> SimulateCommand(PointInTime currentTime);
|
||||||
|
|
||||||
protected void SetDisplayLabel(string displayLabel) => _displayLabel.OnNext(displayLabel);
|
protected void SetDisplayLabel(string? displayLabel) => _displayLabel.OnNext(displayLabel ?? string.Empty);
|
||||||
|
protected void SetDisplayDetailLabel(string? displayLabel) => _displayDetailLabel.OnNext(displayLabel ?? string.Empty);
|
||||||
|
|
||||||
protected void SetTotalProgress(int totalProgress) => _totalProgress.OnNext(totalProgress);
|
protected void SetTotalProgress(int totalProgress) => _totalProgress.OnNext(totalProgress);
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
using System.Reactive.Linq;
|
using System.Reactive.Linq;
|
||||||
using System.Reactive.Subjects;
|
using System.Reactive.Subjects;
|
||||||
|
using ByteSizeLib;
|
||||||
|
using DeclarativeProperty;
|
||||||
using FileTime.Core.Enums;
|
using FileTime.Core.Enums;
|
||||||
using FileTime.Core.Models;
|
using FileTime.Core.Models;
|
||||||
using FileTime.Core.Timeline;
|
using FileTime.Core.Timeline;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
namespace FileTime.Core.Command.Copy;
|
namespace FileTime.Core.Command.Copy;
|
||||||
|
|
||||||
@@ -10,19 +13,25 @@ public class CopyCommand : CommandBase, ITransportationCommand
|
|||||||
{
|
{
|
||||||
private readonly ITimelessContentProvider _timelessContentProvider;
|
private readonly ITimelessContentProvider _timelessContentProvider;
|
||||||
private readonly ICommandSchedulerNotifier _commandSchedulerNotifier;
|
private readonly ICommandSchedulerNotifier _commandSchedulerNotifier;
|
||||||
|
private readonly ILogger<CopyCommand> _logger;
|
||||||
|
|
||||||
private readonly List<OperationProgress> _operationProgresses = new();
|
private readonly List<OperationProgress> _operationProgresses = new();
|
||||||
private readonly BehaviorSubject<OperationProgress?> _currentOperationProgress = new(null);
|
private readonly BehaviorSubject<OperationProgress?> _currentOperationProgress = new(null);
|
||||||
|
|
||||||
|
private long _recentTotalSum;
|
||||||
|
private readonly DeclarativeProperty<long> _recentTotalProcessed = new();
|
||||||
|
private readonly DeclarativeProperty<DateTime> _recentStartTime = new();
|
||||||
|
|
||||||
public IReadOnlyList<FullName> Sources { get; }
|
public IReadOnlyList<FullName> Sources { get; }
|
||||||
|
|
||||||
public FullName Target { get; }
|
public FullName Target { get; }
|
||||||
|
|
||||||
public TransportMode TransportMode { get; }
|
public TransportMode TransportMode { get; }
|
||||||
|
|
||||||
public CopyCommand(
|
internal CopyCommand(
|
||||||
ITimelessContentProvider timelessContentProvider,
|
ITimelessContentProvider timelessContentProvider,
|
||||||
ICommandSchedulerNotifier commandSchedulerNotifier,
|
ICommandSchedulerNotifier commandSchedulerNotifier,
|
||||||
|
ILogger<CopyCommand> logger,
|
||||||
IReadOnlyCollection<FullName>? sources,
|
IReadOnlyCollection<FullName>? sources,
|
||||||
TransportMode? mode,
|
TransportMode? mode,
|
||||||
FullName? targetFullName)
|
FullName? targetFullName)
|
||||||
@@ -30,6 +39,7 @@ public class CopyCommand : CommandBase, ITransportationCommand
|
|||||||
{
|
{
|
||||||
_timelessContentProvider = timelessContentProvider;
|
_timelessContentProvider = timelessContentProvider;
|
||||||
_commandSchedulerNotifier = commandSchedulerNotifier;
|
_commandSchedulerNotifier = commandSchedulerNotifier;
|
||||||
|
_logger = logger;
|
||||||
_currentOperationProgress
|
_currentOperationProgress
|
||||||
.Select(p =>
|
.Select(p =>
|
||||||
{
|
{
|
||||||
@@ -46,6 +56,21 @@ public class CopyCommand : CommandBase, ITransportationCommand
|
|||||||
Sources = new List<FullName>(sources).AsReadOnly();
|
Sources = new List<FullName>(sources).AsReadOnly();
|
||||||
TransportMode = mode.Value;
|
TransportMode = mode.Value;
|
||||||
Target = targetFullName;
|
Target = targetFullName;
|
||||||
|
|
||||||
|
var recentSpeed = DeclarativePropertyHelpers.CombineLatest(
|
||||||
|
_recentTotalProcessed,
|
||||||
|
_recentStartTime,
|
||||||
|
(total, start) =>
|
||||||
|
{
|
||||||
|
var elapsed = DateTime.Now - start;
|
||||||
|
|
||||||
|
var size = new ByteSize(total / elapsed.TotalSeconds);
|
||||||
|
return Task.FromResult(size + "/s");
|
||||||
|
});
|
||||||
|
|
||||||
|
recentSpeed
|
||||||
|
.Debounce(TimeSpan.FromMilliseconds(500))
|
||||||
|
.Subscribe(SetDisplayDetailLabel);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Task<CanCommandRun> CanRun(PointInTime currentTime)
|
public override Task<CanCommandRun> CanRun(PointInTime currentTime)
|
||||||
@@ -79,13 +104,16 @@ public class CopyCommand : CommandBase, ITransportationCommand
|
|||||||
|
|
||||||
var resolvedTarget = await _timelessContentProvider.GetItemByFullNameAsync(Target, currentTime);
|
var resolvedTarget = await _timelessContentProvider.GetItemByFullNameAsync(Target, currentTime);
|
||||||
|
|
||||||
|
_recentTotalSum = 0;
|
||||||
|
await _recentTotalProcessed.SetValue(0);
|
||||||
|
await _recentStartTime.SetValue(DateTime.Now);
|
||||||
|
|
||||||
await TraverseTree(
|
await TraverseTree(
|
||||||
currentTime,
|
currentTime,
|
||||||
Sources,
|
Sources,
|
||||||
new AbsolutePath(_timelessContentProvider, resolvedTarget),
|
new AbsolutePath(_timelessContentProvider, resolvedTarget),
|
||||||
TransportMode,
|
TransportMode,
|
||||||
copyOperation);
|
copyOperation);
|
||||||
//await TimeRunner.RefreshContainer.InvokeAsync(this, Target);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task CalculateProgressAsync(PointInTime currentTime)
|
private async Task CalculateProgressAsync(PointInTime currentTime)
|
||||||
@@ -165,8 +193,25 @@ public class CopyCommand : CommandBase, ITransportationCommand
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Task UpdateProgress() =>
|
private readonly object _updateProgressLock = new();
|
||||||
|
private Task UpdateProgress()
|
||||||
|
{
|
||||||
|
lock (_updateProgressLock)
|
||||||
|
{
|
||||||
|
var now = DateTime.Now;
|
||||||
|
var delta = now - _recentStartTime.Value;
|
||||||
|
if (delta.TotalSeconds > 5)
|
||||||
|
{
|
||||||
|
_recentTotalSum += _recentTotalProcessed.Value;
|
||||||
|
_recentStartTime.SetValueSafe(now);
|
||||||
|
}
|
||||||
|
|
||||||
|
var totalProcessedBytes = _operationProgresses.Select(o => o.Progress.Value).Sum();
|
||||||
|
_recentTotalProcessed.SetValueSafe(totalProcessedBytes - _recentTotalSum);
|
||||||
|
}
|
||||||
|
|
||||||
//Not used, progress is reactive in this command
|
//Not used, progress is reactive in this command
|
||||||
//Note: Maybe this should be removed altogether, and every command should use reactive progress
|
//Note: Maybe this should be removed altogether, and every command should use reactive progress
|
||||||
Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -12,5 +12,5 @@ public class CopyCommandContext
|
|||||||
|
|
||||||
public OperationProgress? CurrentProgress { get; }
|
public OperationProgress? CurrentProgress { get; }
|
||||||
|
|
||||||
public async Task UpdateProgress() => await _updateProgress.Invoke();
|
public async Task UpdateProgressAsync() => await _updateProgress.Invoke();
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
using FileTime.Core.Models;
|
using FileTime.Core.Models;
|
||||||
using FileTime.Core.Timeline;
|
using FileTime.Core.Timeline;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
namespace FileTime.Core.Command.Copy;
|
namespace FileTime.Core.Command.Copy;
|
||||||
|
|
||||||
@@ -7,19 +9,29 @@ public class CopyCommandFactory : ITransportationCommandFactory<CopyCommand>
|
|||||||
{
|
{
|
||||||
private readonly ITimelessContentProvider _timelessContentProvider;
|
private readonly ITimelessContentProvider _timelessContentProvider;
|
||||||
private readonly ICommandSchedulerNotifier _commandSchedulerNotifier;
|
private readonly ICommandSchedulerNotifier _commandSchedulerNotifier;
|
||||||
|
private readonly IServiceProvider _serviceProvider;
|
||||||
|
|
||||||
public CopyCommandFactory(
|
public CopyCommandFactory(
|
||||||
ITimelessContentProvider timelessContentProvider,
|
ITimelessContentProvider timelessContentProvider,
|
||||||
ICommandSchedulerNotifier commandSchedulerNotifier)
|
ICommandSchedulerNotifier commandSchedulerNotifier,
|
||||||
|
IServiceProvider serviceProvider)
|
||||||
|
|
||||||
{
|
{
|
||||||
_timelessContentProvider = timelessContentProvider;
|
_timelessContentProvider = timelessContentProvider;
|
||||||
_commandSchedulerNotifier = commandSchedulerNotifier;
|
_commandSchedulerNotifier = commandSchedulerNotifier;
|
||||||
|
_serviceProvider = serviceProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
public CopyCommand GenerateCommand(
|
public CopyCommand GenerateCommand(
|
||||||
IReadOnlyCollection<FullName> sources,
|
IReadOnlyCollection<FullName> sources,
|
||||||
TransportMode mode,
|
TransportMode mode,
|
||||||
FullName targetFullName)
|
FullName targetFullName)
|
||||||
=> new(_timelessContentProvider, _commandSchedulerNotifier, sources, mode, targetFullName);
|
=> new(
|
||||||
|
_timelessContentProvider,
|
||||||
|
_commandSchedulerNotifier,
|
||||||
|
_serviceProvider.GetRequiredService<ILogger<CopyCommand>>(),
|
||||||
|
sources,
|
||||||
|
mode,
|
||||||
|
targetFullName
|
||||||
|
);
|
||||||
}
|
}
|
||||||
@@ -18,7 +18,7 @@ public class CopyStrategy : ICopyStrategy
|
|||||||
{
|
{
|
||||||
foreach (var item in _copyStrategyParam.OperationProgresses.FindAll(o => o.Key.StartsWith(containerPath.Path.Path)))
|
foreach (var item in _copyStrategyParam.OperationProgresses.FindAll(o => o.Key.StartsWith(containerPath.Path.Path)))
|
||||||
{
|
{
|
||||||
item.SetProgress(item.TotalCount);
|
await item.SetProgressAsync(item.TotalCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
await _copyStrategyParam.RefreshContainerAsync(containerPath.Path);
|
await _copyStrategyParam.RefreshContainerAsync(containerPath.Path);
|
||||||
@@ -27,7 +27,11 @@ public class CopyStrategy : ICopyStrategy
|
|||||||
public async Task CopyAsync(AbsolutePath from, AbsolutePath to, CopyCommandContext context)
|
public async Task CopyAsync(AbsolutePath from, AbsolutePath to, CopyCommandContext context)
|
||||||
{
|
{
|
||||||
await _copy(from, to, context);
|
await _copy(from, to, context);
|
||||||
context.CurrentProgress?.SetProgress(context.CurrentProgress.TotalCount);
|
if (context.CurrentProgress is not null)
|
||||||
|
{
|
||||||
|
await context.CurrentProgress.SetProgressAsync(context.CurrentProgress.TotalCount);
|
||||||
|
}
|
||||||
|
|
||||||
if (to.Path.GetParent() is { } parent)
|
if (to.Path.GetParent() is { } parent)
|
||||||
await _copyStrategyParam.RefreshContainerAsync(parent);
|
await _copyStrategyParam.RefreshContainerAsync(parent);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,6 +46,12 @@ public class DeleteCommand : CommandBase, IExecutableCommand
|
|||||||
new Dictionary<string, IItemDeleter>(),
|
new Dictionary<string, IItemDeleter>(),
|
||||||
new DeleteStrategy()
|
new DeleteStrategy()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
var parents = ItemsToDelete.Select(i => i.GetParent()).OfType<FullName>().Distinct();
|
||||||
|
foreach (var parent in parents)
|
||||||
|
{
|
||||||
|
await _commandSchedulerNotifier.RefreshContainer(parent);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task TraverseTree(
|
private async Task TraverseTree(
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ public class MoveCommand : CommandBase, IExecutableCommand
|
|||||||
if (itemToMove.Source.GetParent() is { } parent)
|
if (itemToMove.Source.GetParent() is { } parent)
|
||||||
await _commandSchedulerNotifier.RefreshContainer(parent);
|
await _commandSchedulerNotifier.RefreshContainer(parent);
|
||||||
|
|
||||||
currentOperationProgress.SetProgress(1);
|
await currentOperationProgress.SetProgressAsync(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
IItemMover GetOrAddItemMover(IContentProvider provider)
|
IItemMover GetOrAddItemMover(IContentProvider provider)
|
||||||
|
|||||||
@@ -1,24 +1,26 @@
|
|||||||
using System.Reactive.Linq;
|
using DeclarativeProperty;
|
||||||
using System.Reactive.Subjects;
|
|
||||||
|
|
||||||
namespace FileTime.Core.Command;
|
namespace FileTime.Core.Command;
|
||||||
|
|
||||||
public class OperationProgress
|
public class OperationProgress
|
||||||
{
|
{
|
||||||
private readonly BehaviorSubject<long> _currentProgress = new(0);
|
private readonly DeclarativeProperty<long> _currentProgress = new(0);
|
||||||
public string Key { get; }
|
public string Key { get; }
|
||||||
public IObservable<long> Progress { get; }
|
public IDeclarativeProperty<long> Progress { get; }
|
||||||
public long TotalCount { get; }
|
public long TotalCount { get; }
|
||||||
public IObservable<bool> IsDone { get; }
|
public IDeclarativeProperty<bool> IsDone { get; }
|
||||||
|
|
||||||
public OperationProgress(string key, long totalCount)
|
public OperationProgress(string key, long totalCount)
|
||||||
{
|
{
|
||||||
Key = key;
|
Key = key;
|
||||||
TotalCount = totalCount;
|
TotalCount = totalCount;
|
||||||
|
|
||||||
Progress = _currentProgress.AsObservable();
|
Progress = _currentProgress;
|
||||||
IsDone = Progress.Select(p => p >= TotalCount);
|
IsDone = Progress.Map(p => p >= TotalCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetProgress(long progress) => _currentProgress.OnNext(progress);
|
public async Task SetProgressAsync(long progress) => await _currentProgress.SetValue(progress);
|
||||||
|
|
||||||
|
public void SetProgressSafe(long progress) =>
|
||||||
|
_currentProgress.SetValueSafe(progress);
|
||||||
}
|
}
|
||||||
@@ -76,8 +76,12 @@ public class StreamCopyCommandHandler : ICommandHandler
|
|||||||
await writer.WriteBytesAsync(dataRead);
|
await writer.WriteBytesAsync(dataRead);
|
||||||
await writer.FlushAsync();
|
await writer.FlushAsync();
|
||||||
currentProgress += dataRead.LongLength;
|
currentProgress += dataRead.LongLength;
|
||||||
copyCommandContext.CurrentProgress?.SetProgress(currentProgress);
|
if (copyCommandContext.CurrentProgress is not null)
|
||||||
await copyCommandContext.UpdateProgress();
|
{
|
||||||
|
copyCommandContext.CurrentProgress.SetProgressSafe(currentProgress);
|
||||||
|
}
|
||||||
|
|
||||||
|
await copyCommandContext.UpdateProgressAsync();
|
||||||
}
|
}
|
||||||
} while (dataRead.Length > 0);
|
} while (dataRead.Length > 0);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -316,25 +316,43 @@
|
|||||||
<Border
|
<Border
|
||||||
Background="{DynamicResource ContainerBackgroundColor}"
|
Background="{DynamicResource ContainerBackgroundColor}"
|
||||||
CornerRadius="10"
|
CornerRadius="10"
|
||||||
Height="50"
|
Height="70"
|
||||||
Margin="0,0,10,0"
|
Margin="0,0,10,0"
|
||||||
Padding="5">
|
Padding="5"
|
||||||
|
Width="300">
|
||||||
<ScrollViewer>
|
<ScrollViewer>
|
||||||
<ItemsControl ItemsSource="{Binding Commands.Collection}">
|
<ItemsControl ItemsSource="{Binding Commands.Collection}">
|
||||||
<ItemsControl.ItemTemplate>
|
<ItemsControl.ItemTemplate>
|
||||||
<DataTemplate>
|
<DataTemplate>
|
||||||
<Border BorderThickness="1" Classes.SelectedTimelineCommand="{Binding IsSelected}">
|
<Border BorderThickness="1" Classes.SelectedTimelineCommand="{Binding IsSelected}">
|
||||||
<StackPanel>
|
<Grid ColumnDefinitions="*, *" RowDefinitions="Auto, Auto">
|
||||||
<TextBlock Text="{Binding DisplayLabel^}" />
|
<TextBlock Grid.ColumnSpan="2" Text="{Binding DisplayLabel^}" />
|
||||||
|
|
||||||
|
<StackPanel
|
||||||
|
Grid.Column="0"
|
||||||
|
Grid.Row="1"
|
||||||
|
Margin="0,5,5,5">
|
||||||
|
<TextBlock Text="{Binding DisplayDetailLabel^}" TextAlignment="Right" />
|
||||||
|
|
||||||
<ProgressBar
|
<ProgressBar
|
||||||
Margin="0,5,0,0"
|
Margin="0,5,0,0"
|
||||||
Maximum="100"
|
Maximum="100"
|
||||||
|
MinWidth="50"
|
||||||
Value="{Binding CurrentProgress^}" />
|
Value="{Binding CurrentProgress^}" />
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel
|
||||||
|
Grid.Column="1"
|
||||||
|
Grid.Row="1"
|
||||||
|
Margin="5,5,0,5">
|
||||||
|
<TextBlock Text="{Binding TotalProgress^, StringFormat={}{0}%}" TextAlignment="Right" />
|
||||||
|
|
||||||
<ProgressBar
|
<ProgressBar
|
||||||
Margin="0,5,0,0"
|
Margin="0,5,0,0"
|
||||||
Maximum="100"
|
Maximum="100"
|
||||||
|
MinWidth="50"
|
||||||
Value="{Binding TotalProgress^}" />
|
Value="{Binding TotalProgress^}" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
</Grid>
|
||||||
</Border>
|
</Border>
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
</ItemsControl.ItemTemplate>
|
</ItemsControl.ItemTemplate>
|
||||||
|
|||||||
Reference in New Issue
Block a user