Skip to content

Commit

Permalink
【WPF】任务列表支持了多选后批量操作
Browse files Browse the repository at this point in the history
  • Loading branch information
autodotua committed May 4, 2024
1 parent 8c105ca commit d3de94d
Show file tree
Hide file tree
Showing 7 changed files with 104 additions and 33 deletions.
1 change: 1 addition & 0 deletions SimpleFFmpegGUI.WPF/App.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
</ResourceDictionary.MergedDictionaries>
<converters:NameDescriptionAttributeValueConverter x:Key="NameDescriptionAttributeValueConverter" />
<converters:HourMinSecTimeSpanConverter x:Key="HourMinSecTimeSpanConverter" />
<converters:CountEqualsOneValueConverter x:Key="CountEqualsOneValueConverter" />
<converters:Index2StringConverter x:Key="Index2StringConverter" />
<system:String x:Key="DateTimeFormat">yyyy-MM-dd HH:mm:ss</system:String>
<system:String x:Key="TimeSpanFormat">hh\:mm\:ss\.fff</system:String>
Expand Down
23 changes: 23 additions & 0 deletions SimpleFFmpegGUI.WPF/Converters/CountEqualsOneValueConverter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using System;
using System.Globalization;
using System.Windows;
using System.Windows.Data;

namespace SimpleFFmpegGUI.WPF.Converters
{
public class CountEqualsOneValueConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (1.Equals(value))
{
return Visibility.Visible;
}
return Visibility.Hidden;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}
4 changes: 4 additions & 0 deletions SimpleFFmpegGUI.WPF/Model/TaskCollectionBase.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
using FzLib;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;

namespace SimpleFFmpegGUI.WPF.Model
{
Expand All @@ -25,5 +27,7 @@ public UITaskInfo SelectedTask
get => selectedTask;
set => this.SetValueAndNotify(ref selectedTask, value, nameof(SelectedTask));
}

public IList<UITaskInfo> SelectedTasks=>Tasks.Where(p=>p.IsSelected).ToList();
}
}
21 changes: 9 additions & 12 deletions SimpleFFmpegGUI.WPF/Model/UITaskInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ public class UITaskInfo : ModelBase, INotifyPropertyChanged

private List<InputArguments> inputs;

private bool isSelected;

/// <summary>
/// 上一个缩略图的时间
Expand All @@ -52,6 +53,7 @@ public class UITaskInfo : ModelBase, INotifyPropertyChanged
private string realOutput;

private bool showSnapshot;

private object snapshotSource;

private DateTime? startTime;
Expand All @@ -78,16 +80,14 @@ public UITaskInfo()
{
timer.Dispose();
}

public event PropertyChangedEventHandler PropertyChanged;

public OutputArguments Arguments
{
get => arguments;
set => this.SetValueAndNotify(ref arguments, value, nameof(Arguments));
}

public bool CancelButtonEnabled => Status is TaskStatus.Queue or TaskStatus.Processing;

public Brush Color => Status switch
{
TaskStatus.Queue => System.Windows.Application.Current.FindResource("SystemControlForegroundBaseHighBrush") as Brush,
Expand Down Expand Up @@ -179,6 +179,11 @@ public string InputText

public bool IsIndeterminate => ProcessStatus == null || ProcessStatus.HasDetail == false || ProcessStatus.Progress.IsIndeterminate;

public bool IsSelected
{
get => isSelected;
set => this.SetValueAndNotify(ref isSelected, value, nameof(IsSelected));
}
public string Message
{
get => message;
Expand Down Expand Up @@ -265,8 +270,6 @@ public string RealOutput
set => this.SetValueAndNotify(ref realOutput, value, nameof(RealOutput));
}

public bool ResetButtonEnabled => Status is TaskStatus.Done or TaskStatus.Cancel or TaskStatus.Error;

public bool ShowSnapshot
{
get => showSnapshot;
Expand All @@ -279,8 +282,6 @@ public object SnapshotSource
set => this.SetValueAndNotify(ref snapshotSource, value, nameof(SnapshotSource));
}

public bool StartButtonEnabled => Status is TaskStatus.Queue;

public DateTime? StartTime
{
get => startTime;
Expand All @@ -291,9 +292,6 @@ public TaskStatus Status
{
get => status;
set => this.SetValueAndNotify(ref status, value, nameof(Status),
nameof(ResetButtonEnabled),
nameof(StartButtonEnabled),
nameof(CancelButtonEnabled),
nameof(StatusText),
nameof(Color),
nameof(Percent));
Expand All @@ -305,8 +303,7 @@ public TaskStatus Status
_ => DescriptionConverter.GetDescription(Status)
};

public string Title => Type == TaskType.Custom ?
AttributeHelper.GetAttributeValue<NameDescriptionAttribute, string>(Type, p => p.Name)
public string Title => Type == TaskType.Custom ? AttributeHelper.GetAttributeValue<NameDescriptionAttribute, string>(Type, p => p.Name)
: AttributeHelper.GetAttributeValue<NameDescriptionAttribute, string>(Type, p => p.Name) + ":" + InputText;

public TaskType Type
Expand Down
19 changes: 13 additions & 6 deletions SimpleFFmpegGUI.WPF/Panels/TaskList.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,18 @@
<ListView
xmlns:c="clr-namespace:FzLib.WPF.Controls;assembly=FzCoreLib.Windows"
xmlns:r="clr-namespace:SimpleFFmpegGUI.WPF"
x:Name="lvwTasks"
c:SmoothScrollViewerHelper.SmoothScroll="{Binding Source={x:Static r:Config.Instance}, Path=SmoothScroll}"
ItemsSource="{Binding Tasks.Tasks}"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
SelectedItem="{Binding Tasks.SelectedTask}">
SelectedItem="{Binding Tasks.SelectedTask}"
SelectionChanged="Tasks_SelectionChanged"
SelectionMode="{Binding SelectionMode}">
<ListView.ItemContainerStyle>
<Style
BasedOn="{StaticResource DefaultListViewItemStyle}"
TargetType="{x:Type ListViewItem}">
<Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
<Setter Property="Padding" Value="8" />
<Setter Property="Margin" Value="0,0,16,0" />
Expand Down Expand Up @@ -296,27 +300,30 @@
<Button
Click="StartButton_Click"
Content="独立执行"
IsEnabled="{Binding Tasks.SelectedTask.StartButtonEnabled}"
IsEnabled="{Binding CanStart}"
Visibility="{Binding ShowAllTasks, Converter={StaticResource Bool2VisibilityConverter}, ConverterParameter=i}" />
<Button
Click="CancelButton_Click"
Content="取消"
IsEnabled="{Binding Tasks.SelectedTask.CancelButtonEnabled}"
IsEnabled="{Binding CanCancel}"
ToolTip="取消执行任务,正在执行的任务会被停止"
Visibility="{Binding ShowAllTasks, Converter={StaticResource Bool2VisibilityConverter}, ConverterParameter=i}" />
<Button
Click="ResetButton_Click"
Content="重置"
IsEnabled="{Binding Tasks.SelectedTask.ResetButtonEnabled}"
ToolTip="将任务设置为排队状态" />
IsEnabled="{Binding CanReset}"
ToolTip="将任务设置为排队状态"
Visibility="{Binding ShowAllTasks, Converter={StaticResource Bool2VisibilityConverter}, ConverterParameter=i}" />
<Button
Click="DeleteButton_Click"
Content="删除"
Visibility="Collapsed" />
<Button
VerticalAlignment="Center"
Background="Transparent"
DataContext="{Binding Tasks.SelectedTask}">
DataContext="{Binding Tasks.SelectedTask}"
Visibility="{Binding ElementName=lvwTasks, Path=SelectedItems.Count, Converter={StaticResource CountEqualsOneValueConverter}}">

<ui:SymbolIcon Symbol="More" />
<ui:FlyoutService.Flyout>
<ui:MenuFlyout>
Expand Down
63 changes: 49 additions & 14 deletions SimpleFFmpegGUI.WPF/Panels/TaskList.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,10 @@ private void ArgumentsButton_Click(object sender, RoutedEventArgs e)

private async void CancelButton_Click(object sender, RoutedEventArgs e)
{
var task = ViewModel.Tasks.SelectedTask;
Debug.Assert(task != null);
if (task.Status == TaskStatus.Processing)
var tasks = App.ServiceProvider.GetService<TasksAndStatuses>().SelectedTasks;

Debug.Assert(tasks.Count > 0);
if (tasks.Any(p => p.Status == TaskStatus.Processing))
{
if (!await CommonDialog.ShowYesNoDialogAsync("取消任务", "任务正在执行,是否取消?"))
{
Expand All @@ -82,8 +83,11 @@ private async void CancelButton_Click(object sender, RoutedEventArgs e)
try
{
IsEnabled = false;
TaskManager.CancelTask(task.Id, ViewModel.Queue);
task.UpdateSelf();
foreach (var task in tasks)
{
TaskManager.CancelTask(task.Id, ViewModel.Queue);
task.UpdateSelf();
}
}
catch (Exception ex)
{
Expand All @@ -93,6 +97,8 @@ private async void CancelButton_Click(object sender, RoutedEventArgs e)
{
IsEnabled = true;
}

ViewModel.NotifyCanExecute();
}

private void CloneButton_Click(object sender, RoutedEventArgs e)
Expand All @@ -103,6 +109,7 @@ private void CloneButton_Click(object sender, RoutedEventArgs e)

private async void DeleteButton_Click(object sender, RoutedEventArgs e)
{
throw new NotImplementedException();
bool delete = true;
if (App.ServiceProvider.GetService<TasksAndStatuses>().SelectedTask.Status == SimpleFFmpegGUI.Model.TaskStatus.Processing)
{
Expand Down Expand Up @@ -206,26 +213,36 @@ private void OpenOutputFileOrFolder(UITaskInfo task, bool folder)

private void ResetButton_Click(object sender, RoutedEventArgs e)
{
var task = ViewModel.Tasks.SelectedTask;
Debug.Assert(task != null);
TaskManager.ResetTask(task.Id, ViewModel.Queue);
task.UpdateSelf();
App.ServiceProvider.GetService<TasksAndStatuses>().NotifyTaskReseted(task);
var tasks = App.ServiceProvider.GetService<TasksAndStatuses>().SelectedTasks;
Debug.Assert(tasks.Count > 0);
foreach (var task in tasks)
{
TaskManager.ResetTask(task.Id, ViewModel.Queue);
task.UpdateSelf();
App.ServiceProvider.GetService<TasksAndStatuses>().NotifyTaskReseted(task);
}

ViewModel.NotifyCanExecute();
}

private void StartButton_Click(object sender, RoutedEventArgs e)
{
try
{
var task = ViewModel.Tasks.SelectedTask;
Debug.Assert(task != null);
ViewModel.Queue.StartStandalone(task.Id);
task.UpdateSelf();
var tasks = App.ServiceProvider.GetService<TasksAndStatuses>().SelectedTasks;
Debug.Assert(tasks.Count > 0);
foreach (var task in tasks)
{
ViewModel.Queue.StartStandalone(task.Id);
task.UpdateSelf();
}
}
catch (Exception ex)
{
this.CreateMessage().QueueError("启动失败", ex);
}

ViewModel.NotifyCanExecute();
}

private void UpdateDetailHeight()
Expand All @@ -239,6 +256,11 @@ private void UserControl_Loaded(object sender, RoutedEventArgs e)
App.ServiceProvider.GetService<MainWindow>().UiCompressModeChanged +=
(s, e) => UpdateDetailHeight();
}

private void Tasks_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
ViewModel.NotifyCanExecute();
}
}

public class TaskListViewModel : INotifyPropertyChanged
Expand All @@ -252,6 +274,17 @@ public TaskListViewModel(QueueManager queue)

public event PropertyChangedEventHandler PropertyChanged;

public bool CanCancel => Tasks.SelectedTasks.All(p => p.Status is TaskStatus.Queue or TaskStatus.Processing);

public bool CanReset => Tasks.SelectedTasks.All(p => p.Status is TaskStatus.Done or TaskStatus.Cancel or TaskStatus.Error);

public bool CanStart => Tasks.SelectedTasks.All(p => p.Status is TaskStatus.Queue);

public void NotifyCanExecute()
{
this.Notify(nameof(CanCancel), nameof(CanReset), nameof(CanStart));
}

public QueueManager Queue { get; }

public bool ShowAllTasks
Expand All @@ -263,5 +296,7 @@ public bool ShowAllTasks
public TaskCollectionBase Tasks => ShowAllTasks ?
App.ServiceProvider.GetService<AllTasks>()
: App.ServiceProvider.GetService<TasksAndStatuses>();

public SelectionMode SelectionMode => ShowAllTasks ? SelectionMode.Single : SelectionMode.Extended;
}
}
6 changes: 5 additions & 1 deletion 日志.md
Original file line number Diff line number Diff line change
Expand Up @@ -685,4 +685,8 @@

## 20240413

【Web】新增处理后删除输入文件的功能
【Web】新增处理后删除输入文件的功能

## 20240504

【WPF】任务列表支持了多选后批量操作

0 comments on commit d3de94d

Please sign in to comment.