feat:基础功能实现
feat: 重构 TodoList 架构,新增动态 API 与 MAUI 内嵌 Web 服务 feat:优化交互逻辑,优化发布流程
This commit is contained in:
+63
-7
@@ -7,16 +7,19 @@ using TodoList.Services;
|
||||
using TodoList.ViewModels;
|
||||
using TodoList.Views;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
namespace TodoList
|
||||
{
|
||||
public partial class App : System.Windows.Application
|
||||
{
|
||||
private const string MainWindowTitle = "待办事项";
|
||||
private IDataService _dataService;
|
||||
private GlobalShortcutService _shortcutService;
|
||||
private MainWindow _mainWindow;
|
||||
private QuickEntryWindow? _quickEntryWindow;
|
||||
private SettingsService _settingsService;
|
||||
private System.Windows.Forms.NotifyIcon _notifyIcon;
|
||||
private NotifyIcon _notifyIcon;
|
||||
private Mutex _mutex;
|
||||
private EventWaitHandle _eventWaitHandle;
|
||||
private const string UniqueEventName = "Global\\TodoListApp_Event_v1";
|
||||
@@ -59,7 +62,7 @@ namespace TodoList
|
||||
catch
|
||||
{
|
||||
// Fallback to old method if event open fails
|
||||
var hWnd = FindWindow(null, "待办事项");
|
||||
var hWnd = FindWindow(null, MainWindowTitle);
|
||||
if (hWnd != IntPtr.Zero)
|
||||
{
|
||||
ShowWindow(hWnd, 9); // SW_RESTORE
|
||||
@@ -107,6 +110,7 @@ namespace TodoList
|
||||
var mainViewModel = new MainViewModel(_dataService, _settingsService);
|
||||
|
||||
_mainWindow = new MainWindow(mainViewModel);
|
||||
_mainWindow.Title = MainWindowTitle;
|
||||
_mainWindow.Loaded += MainWindow_Loaded;
|
||||
|
||||
// Initialize Tray Icon
|
||||
@@ -131,7 +135,7 @@ namespace TodoList
|
||||
{
|
||||
try
|
||||
{
|
||||
var exePath = System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName;
|
||||
var exePath = System.Diagnostics.Process.GetCurrentProcess().MainModule?.FileName;
|
||||
string cmd = $"\"{exePath}\" --silent";
|
||||
|
||||
// If running as dotnet tool, try to find the shim or stable entry point
|
||||
@@ -167,7 +171,7 @@ namespace TodoList
|
||||
|
||||
private void InitializeTrayIcon()
|
||||
{
|
||||
_notifyIcon = new System.Windows.Forms.NotifyIcon();
|
||||
_notifyIcon = new NotifyIcon();
|
||||
|
||||
// Try load icon from resource or file
|
||||
try
|
||||
@@ -194,15 +198,43 @@ namespace TodoList
|
||||
}
|
||||
|
||||
_notifyIcon.Visible = true;
|
||||
_notifyIcon.Text = "TodoList";
|
||||
_notifyIcon.Text = GetNotifyIconText();
|
||||
_notifyIcon.DoubleClick += (s, e) => ShowMainWindow();
|
||||
|
||||
var contextMenu = new System.Windows.Forms.ContextMenuStrip();
|
||||
var contextMenu = new ContextMenuStrip();
|
||||
contextMenu.Items.Add("打开主界面", null, (s, e) => ShowMainWindow());
|
||||
contextMenu.Items.Add("退出", null, (s, e) => ExitApplication());
|
||||
_notifyIcon.ContextMenuStrip = contextMenu;
|
||||
}
|
||||
|
||||
private static string GetNotifyIconText()
|
||||
{
|
||||
var version = GetDisplayVersion();
|
||||
var text = string.IsNullOrWhiteSpace(version) ? MainWindowTitle : $"{MainWindowTitle} v{version}";
|
||||
|
||||
return text.Length > 63 ? text[..63] : text;
|
||||
}
|
||||
|
||||
private static string? GetDisplayVersion()
|
||||
{
|
||||
var asm = Assembly.GetExecutingAssembly();
|
||||
|
||||
var info = asm.GetCustomAttribute<AssemblyInformationalVersionAttribute>()?.InformationalVersion?.Trim();
|
||||
if (!string.IsNullOrWhiteSpace(info))
|
||||
{
|
||||
var plus = info.IndexOf('+');
|
||||
return plus >= 0 ? info[..plus] : info;
|
||||
}
|
||||
|
||||
var file = asm.GetCustomAttribute<AssemblyFileVersionAttribute>()?.Version?.Trim();
|
||||
if (!string.IsNullOrWhiteSpace(file))
|
||||
{
|
||||
return file;
|
||||
}
|
||||
|
||||
return asm.GetName().Version?.ToString();
|
||||
}
|
||||
|
||||
private void ShowMainWindow()
|
||||
{
|
||||
Log("ShowMainWindow called");
|
||||
@@ -289,7 +321,31 @@ namespace TodoList
|
||||
private void OnHotKeyPressed()
|
||||
{
|
||||
Log("Hotkey pressed.");
|
||||
ShowMainWindow();
|
||||
ShowQuickEntryWindow();
|
||||
}
|
||||
|
||||
private void ShowQuickEntryWindow()
|
||||
{
|
||||
if (_quickEntryWindow == null)
|
||||
{
|
||||
_quickEntryWindow = new QuickEntryWindow(_dataService);
|
||||
_quickEntryWindow.Title = "新建待办";
|
||||
}
|
||||
|
||||
if (_quickEntryWindow.WindowState == WindowState.Minimized)
|
||||
{
|
||||
_quickEntryWindow.WindowState = WindowState.Normal;
|
||||
}
|
||||
|
||||
_quickEntryWindow.Show();
|
||||
_quickEntryWindow.Activate();
|
||||
|
||||
var helper = new WindowInteropHelper(_quickEntryWindow);
|
||||
var handle = helper.Handle;
|
||||
if (handle != IntPtr.Zero)
|
||||
{
|
||||
SetForegroundWindow(handle);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnExit(ExitEventArgs e)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.Json;
|
||||
using System.Threading.Tasks;
|
||||
using TodoList.Models;
|
||||
@@ -19,7 +20,7 @@ namespace TodoList.Services
|
||||
_filePath = Path.Combine(folder, "tasks.json");
|
||||
}
|
||||
|
||||
public async Task<List<TodoItem>> LoadTasksAsync()
|
||||
public async Task<List<TodoItem>> LoadTasksAsync(bool? completed = null)
|
||||
{
|
||||
if (!File.Exists(_filePath))
|
||||
{
|
||||
@@ -30,7 +31,13 @@ namespace TodoList.Services
|
||||
{
|
||||
using var stream = File.OpenRead(_filePath);
|
||||
var items = await JsonSerializer.DeserializeAsync<List<TodoItem>>(stream);
|
||||
return items ?? new List<TodoItem>();
|
||||
var tasks = items ?? new List<TodoItem>();
|
||||
|
||||
if (completed.HasValue)
|
||||
{
|
||||
return tasks.Where(t => t.IsCompleted == completed.Value).ToList();
|
||||
}
|
||||
return tasks;
|
||||
}
|
||||
catch
|
||||
{
|
||||
@@ -38,7 +45,7 @@ namespace TodoList.Services
|
||||
}
|
||||
}
|
||||
|
||||
public async Task SaveTaskAsync(TodoItem task)
|
||||
public async Task<TodoItem> SaveTaskAsync(TodoItem task)
|
||||
{
|
||||
var tasks = await LoadTasksAsync();
|
||||
var existing = tasks.Find(t => t.Id == task.Id);
|
||||
@@ -48,6 +55,34 @@ namespace TodoList.Services
|
||||
}
|
||||
tasks.Add(task);
|
||||
await SaveAllAsync(tasks);
|
||||
return task;
|
||||
}
|
||||
|
||||
public async Task<TodoItem> UpdateTaskAsync(TodoItem task)
|
||||
{
|
||||
var tasks = await LoadTasksAsync();
|
||||
var existing = tasks.Find(t => t.Id == task.Id);
|
||||
if (existing != null)
|
||||
{
|
||||
tasks.Remove(existing);
|
||||
tasks.Add(task);
|
||||
await SaveAllAsync(tasks);
|
||||
}
|
||||
return task;
|
||||
}
|
||||
|
||||
public async Task<TodoItem> ToggleCompleteAsync(string id)
|
||||
{
|
||||
var tasks = await LoadTasksAsync();
|
||||
var task = tasks.Find(t => t.Id == id);
|
||||
if (task != null)
|
||||
{
|
||||
task.IsCompleted = !task.IsCompleted;
|
||||
task.CompletedAt = task.IsCompleted ? DateTime.Now : null;
|
||||
task.SyncStatus = SyncStatus.Pending;
|
||||
await SaveAllAsync(tasks);
|
||||
}
|
||||
return task;
|
||||
}
|
||||
|
||||
public async Task SaveAllAsync(List<TodoItem> tasks)
|
||||
|
||||
@@ -6,9 +6,10 @@ namespace TodoList.Services
|
||||
{
|
||||
public interface IDataService
|
||||
{
|
||||
Task<List<TodoItem>> LoadTasksAsync();
|
||||
Task SaveTaskAsync(TodoItem task);
|
||||
Task SaveAllAsync(List<TodoItem> tasks);
|
||||
Task<List<TodoItem>> LoadTasksAsync(bool? completed = null);
|
||||
Task<TodoItem> SaveTaskAsync(TodoItem task);
|
||||
Task<TodoItem> UpdateTaskAsync(TodoItem task);
|
||||
Task<TodoItem> ToggleCompleteAsync(string id);
|
||||
Task DeleteTaskAsync(string id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,14 +22,39 @@ namespace TodoList.Services
|
||||
_database.CreateTableAsync<TodoItem>().Wait();
|
||||
}
|
||||
|
||||
public async Task<List<TodoItem>> LoadTasksAsync()
|
||||
public async Task<List<TodoItem>> LoadTasksAsync(bool? completed = null)
|
||||
{
|
||||
return await _database.Table<TodoItem>().ToListAsync();
|
||||
var query = _database.Table<TodoItem>();
|
||||
if (completed.HasValue)
|
||||
{
|
||||
query = query.Where(t => t.IsCompleted == completed.Value);
|
||||
}
|
||||
return await query.ToListAsync();
|
||||
}
|
||||
|
||||
public async Task SaveTaskAsync(TodoItem task)
|
||||
public async Task<TodoItem> SaveTaskAsync(TodoItem task)
|
||||
{
|
||||
await _database.InsertOrReplaceAsync(task);
|
||||
return task;
|
||||
}
|
||||
|
||||
public async Task<TodoItem> UpdateTaskAsync(TodoItem task)
|
||||
{
|
||||
await _database.UpdateAsync(task);
|
||||
return task;
|
||||
}
|
||||
|
||||
public async Task<TodoItem> ToggleCompleteAsync(string id)
|
||||
{
|
||||
var task = await _database.FindAsync<TodoItem>(id);
|
||||
if (task != null)
|
||||
{
|
||||
task.IsCompleted = !task.IsCompleted;
|
||||
task.CompletedAt = task.IsCompleted ? DateTime.Now : null;
|
||||
task.SyncStatus = SyncStatus.Pending;
|
||||
await _database.UpdateAsync(task);
|
||||
}
|
||||
return task;
|
||||
}
|
||||
|
||||
public async Task SaveAllAsync(List<TodoItem> tasks)
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
<TargetFramework>net8.0-windows</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<CodePage>65001</CodePage>
|
||||
<UseWPF>true</UseWPF>
|
||||
<UseWindowsForms>true</UseWindowsForms>
|
||||
<ApplicationIcon>icon.ico</ApplicationIcon>
|
||||
@@ -14,6 +15,7 @@
|
||||
<ItemGroup>
|
||||
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.0" />
|
||||
<PackageReference Include="sqlite-net-pcl" Version="1.9.172" />
|
||||
<PackageReference Include="System.Net.Http.Json" Version="10.0.5" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -55,8 +55,6 @@ namespace TodoList.ViewModels
|
||||
[ObservableProperty]
|
||||
private Models.SortOrder sortOrder = Models.SortOrder.Descending;
|
||||
|
||||
public string AppVersion => System.Reflection.Assembly.GetExecutingAssembly().GetName().Version?.ToString() ?? "1.0.0";
|
||||
|
||||
public string FullShortcut
|
||||
{
|
||||
get
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
xmlns:models="clr-namespace:TodoList.Models"
|
||||
xmlns:converters="clr-namespace:TodoList.Converters"
|
||||
mc:Ignorable="d"
|
||||
Title="{Binding AppVersion, StringFormat='待办事项 v{0}'}" Height="600" Width="450"
|
||||
Title="{Binding AppVersion, StringFormat='待办事项 v{0}'}" Height="450" Width="350"
|
||||
Background="#F5F5F7"
|
||||
Icon="/icon.ico"
|
||||
WindowStartupLocation="CenterScreen"
|
||||
@@ -73,7 +73,7 @@
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- Header / Toolbar -->
|
||||
<Border Grid.Row="0" Background="White" Padding="15" Effect="{DynamicResource {x:Static DropShadowEffect.ShadowDepthProperty}}">
|
||||
<Border Grid.Row="0" Background="White" Padding="10" Effect="{DynamicResource {x:Static DropShadowEffect.ShadowDepthProperty}}">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
@@ -83,10 +83,10 @@
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<StackPanel Grid.Column="1" Orientation="Horizontal" Margin="10,0,15,0" VerticalAlignment="Center">
|
||||
<StackPanel Grid.Column="1" Orientation="Horizontal" Margin="5,0,10,0" VerticalAlignment="Center">
|
||||
<ComboBox ItemsSource="{Binding Source={StaticResource SortByEnum}}"
|
||||
SelectedItem="{Binding SortBy}"
|
||||
Width="90" VerticalContentAlignment="Center" Margin="0,0,5,0">
|
||||
Width="70" VerticalContentAlignment="Center" Margin="0,0,3,0">
|
||||
<ComboBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock Text="{Binding Converter={StaticResource EnumDescConverter}}"/>
|
||||
@@ -95,7 +95,7 @@
|
||||
</ComboBox>
|
||||
<ComboBox ItemsSource="{Binding Source={StaticResource SortOrderEnum}}"
|
||||
SelectedItem="{Binding SortOrder}"
|
||||
Width="60" VerticalContentAlignment="Center">
|
||||
Width="50" VerticalContentAlignment="Center">
|
||||
<ComboBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock Text="{Binding Converter={StaticResource EnumDescConverter}}"/>
|
||||
@@ -106,7 +106,7 @@
|
||||
|
||||
<Button Grid.Column="2" Content="设置快捷键"
|
||||
Command="{Binding OpenSettingsCommand}"
|
||||
Background="Transparent" Foreground="#007AFF" Margin="0,0,15,0">
|
||||
Background="Transparent" Foreground="#007AFF" Margin="0,0,10,0" FontSize="11">
|
||||
<Button.Template>
|
||||
<ControlTemplate TargetType="Button">
|
||||
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
||||
@@ -114,14 +114,14 @@
|
||||
</Button.Template>
|
||||
</Button>
|
||||
|
||||
<CheckBox Grid.Column="3" Content="显示已完成"
|
||||
<CheckBox Grid.Column="3" Content="已完成"
|
||||
IsChecked="{Binding ShowCompleted}"
|
||||
VerticalAlignment="Center" Foreground="#555"/>
|
||||
VerticalAlignment="Center" Foreground="#555" FontSize="11"/>
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
<!-- Input Area -->
|
||||
<Border Grid.Row="1" Margin="15" Background="White" CornerRadius="8" Padding="10">
|
||||
<Border Grid.Row="1" Margin="10" Background="White" CornerRadius="6" Padding="8">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
@@ -130,7 +130,7 @@
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<TextBox Text="{Binding NewContent, UpdateSourceTrigger=PropertyChanged}"
|
||||
FontSize="14" Padding="5" Margin="0,0,10,0" BorderThickness="0,0,0,1"
|
||||
FontSize="12" Padding="4" Margin="0,0,8,0" BorderThickness="0,0,0,1"
|
||||
VerticalContentAlignment="Center"
|
||||
Tag="添加新任务...">
|
||||
<TextBox.Style>
|
||||
@@ -149,7 +149,7 @@
|
||||
|
||||
<ComboBox Grid.Column="1" ItemsSource="{Binding Source={StaticResource PriorityEnum}}"
|
||||
SelectedItem="{Binding NewPriority}"
|
||||
Width="80" Margin="0,0,10,0" VerticalContentAlignment="Center">
|
||||
Width="65" Margin="0,0,8,0" VerticalContentAlignment="Center">
|
||||
<ComboBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock Text="{Binding Converter={StaticResource EnumDescConverter}}"/>
|
||||
@@ -158,7 +158,7 @@
|
||||
</ComboBox>
|
||||
|
||||
<Button Grid.Column="2" Content="添加" Command="{Binding AddTaskCommand}" Style="{StaticResource ModernButton}"
|
||||
VerticalAlignment="Center" Height="32" Width="80"/>
|
||||
VerticalAlignment="Center" Height="28" Width="65" FontSize="12"/>
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
@@ -166,13 +166,13 @@
|
||||
<ListBox Grid.Row="2" ItemsSource="{Binding Tasks}"
|
||||
HorizontalContentAlignment="Stretch"
|
||||
Background="Transparent" BorderThickness="0"
|
||||
Margin="15,0,15,15"
|
||||
Margin="10,0,10,10"
|
||||
ScrollViewer.HorizontalScrollBarVisibility="Disabled">
|
||||
<ListBox.ItemContainerStyle>
|
||||
<Style TargetType="ListBoxItem">
|
||||
<Setter Property="Background" Value="White"/>
|
||||
<Setter Property="Margin" Value="0,0,0,10"/>
|
||||
<Setter Property="Padding" Value="10"/>
|
||||
<Setter Property="Margin" Value="0,0,0,6"/>
|
||||
<Setter Property="Padding" Value="8"/>
|
||||
<EventSetter Event="MouseDoubleClick" Handler="ListBoxItem_MouseDoubleClick"/>
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
@@ -211,12 +211,12 @@
|
||||
CommandParameter="{Binding}"
|
||||
VerticalAlignment="Center">
|
||||
<CheckBox.LayoutTransform>
|
||||
<ScaleTransform ScaleX="1.2" ScaleY="1.2"/>
|
||||
<ScaleTransform ScaleX="1.0" ScaleY="1.0"/>
|
||||
</CheckBox.LayoutTransform>
|
||||
</CheckBox>
|
||||
|
||||
<StackPanel Grid.Column="1" Margin="15,0">
|
||||
<TextBlock Text="{Binding Content}" FontSize="16" VerticalAlignment="Center">
|
||||
<StackPanel Grid.Column="1" Margin="10,0">
|
||||
<TextBlock Text="{Binding Content}" FontSize="13" VerticalAlignment="Center">
|
||||
<TextBlock.Style>
|
||||
<Style TargetType="TextBlock">
|
||||
<Style.Triggers>
|
||||
@@ -231,16 +231,16 @@
|
||||
</Style>
|
||||
</TextBlock.Style>
|
||||
</TextBlock>
|
||||
<TextBlock Text="{Binding Priority, Converter={StaticResource EnumDescConverter}}" FontSize="12" Foreground="#888" Margin="0,2,0,0"/>
|
||||
<TextBlock Text="{Binding Priority, Converter={StaticResource EnumDescConverter}}" FontSize="10" Foreground="#888" Margin="0,1,0,0"/>
|
||||
</StackPanel>
|
||||
|
||||
<Button Grid.Column="2" Content="✎"
|
||||
Command="{Binding DataContext.OpenEditDialogCommand, RelativeSource={RelativeSource AncestorType=Window}}"
|
||||
CommandParameter="{Binding}"
|
||||
Width="24" Height="24"
|
||||
Width="20" Height="20"
|
||||
Background="Transparent" Foreground="#007AFF"
|
||||
BorderThickness="0" FontSize="12" FontWeight="Bold"
|
||||
Cursor="Hand" Margin="0,0,5,0">
|
||||
BorderThickness="0" FontSize="10" FontWeight="Bold"
|
||||
Cursor="Hand" Margin="0,0,4,0">
|
||||
<Button.Template>
|
||||
<ControlTemplate TargetType="Button">
|
||||
<Border x:Name="border" Background="{TemplateBinding Background}" CornerRadius="12">
|
||||
@@ -258,9 +258,9 @@
|
||||
<Button Grid.Column="3" Content="✕"
|
||||
Command="{Binding DataContext.DeleteCommand, RelativeSource={RelativeSource AncestorType=Window}}"
|
||||
CommandParameter="{Binding}"
|
||||
Width="24" Height="24"
|
||||
Width="20" Height="20"
|
||||
Background="Transparent" Foreground="#FF3B30"
|
||||
BorderThickness="0" FontSize="12" FontWeight="Bold"
|
||||
BorderThickness="0" FontSize="10" FontWeight="Bold"
|
||||
Cursor="Hand">
|
||||
<Button.Template>
|
||||
<ControlTemplate TargetType="Button">
|
||||
@@ -280,54 +280,10 @@
|
||||
</ListBox.ItemTemplate>
|
||||
</ListBox>
|
||||
|
||||
<!-- Settings Dialog Overlay -->
|
||||
<Grid Grid.RowSpan="3" Background="#80000000" Visibility="{Binding IsSettingsOpen, Converter={StaticResource BoolToVis}}">
|
||||
<Border Background="White" Width="300" Height="200" CornerRadius="10" VerticalAlignment="Center" HorizontalAlignment="Center" Padding="20">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<TextBlock Text="快捷键设置" FontSize="18" FontWeight="Bold" HorizontalAlignment="Center"/>
|
||||
|
||||
<StackPanel Grid.Row="1" VerticalAlignment="Center">
|
||||
<TextBlock Text="当前支持组合键 (如 Alt+X, Ctrl+Alt+A)" Foreground="#666" Margin="0,0,0,5" FontSize="12" HorizontalAlignment="Center"/>
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
|
||||
<TextBox x:Name="ShortcutBox"
|
||||
Text="{Binding FullShortcut, Mode=OneWay}"
|
||||
Width="200" FontSize="16"
|
||||
HorizontalContentAlignment="Center" VerticalContentAlignment="Center"
|
||||
PreviewKeyDown="ShortcutBox_PreviewKeyDown"
|
||||
CaretBrush="Transparent"
|
||||
IsReadOnly="True"
|
||||
Cursor="Hand"
|
||||
Padding="5"/>
|
||||
</StackPanel>
|
||||
<TextBlock Text="点击上方框并按下快捷键" Foreground="#999" FontSize="12" HorizontalAlignment="Center" Margin="0,5,0,0"/>
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Grid.Row="2" Orientation="Horizontal" HorizontalAlignment="Center">
|
||||
<Button Content="取消" Command="{Binding CloseSettingsCommand}" Width="80" Margin="0,0,10,0"
|
||||
Background="#EEE" Foreground="#333" Height="30" BorderThickness="0">
|
||||
<Button.Template>
|
||||
<ControlTemplate TargetType="Button">
|
||||
<Border Background="{TemplateBinding Background}" CornerRadius="5">
|
||||
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
||||
</Border>
|
||||
</ControlTemplate>
|
||||
</Button.Template>
|
||||
</Button>
|
||||
<Button Content="保存" Command="{Binding SaveSettingsCommand}" Width="80" Height="30" Style="{StaticResource ModernButton}"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Border>
|
||||
</Grid>
|
||||
|
||||
<!-- Edit Dialog Overlay -->
|
||||
<Grid Grid.RowSpan="3" Background="#80000000" Visibility="{Binding IsEditDialogOpen, Converter={StaticResource BoolToVis}}">
|
||||
<Border Background="White" Width="350" Height="250" CornerRadius="10" VerticalAlignment="Center" HorizontalAlignment="Center" Padding="20">
|
||||
<Border Background="White" Width="300" Height="220" CornerRadius="8" VerticalAlignment="Center" HorizontalAlignment="Center" Padding="15">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
@@ -335,18 +291,18 @@
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<TextBlock Text="编辑任务" FontSize="18" FontWeight="Bold" HorizontalAlignment="Center" Margin="0,0,0,15"/>
|
||||
<TextBlock Text="编辑任务" FontSize="15" FontWeight="Bold" HorizontalAlignment="Center" Margin="0,0,0,12"/>
|
||||
|
||||
<StackPanel Grid.Row="1" VerticalAlignment="Center">
|
||||
<TextBlock Text="任务内容" Foreground="#666" Margin="0,0,0,5" FontSize="12"/>
|
||||
<TextBlock Text="任务内容" Foreground="#666" Margin="0,0,0,4" FontSize="10"/>
|
||||
<TextBox Text="{Binding EditContent, UpdateSourceTrigger=PropertyChanged}"
|
||||
FontSize="14" Padding="8" Margin="0,0,0,15" BorderThickness="1" BorderBrush="#DDD"
|
||||
FontSize="12" Padding="6" Margin="0,0,0,12" BorderThickness="1" BorderBrush="#DDD"
|
||||
VerticalContentAlignment="Center"/>
|
||||
|
||||
<TextBlock Text="优先级" Foreground="#666" Margin="0,0,0,5" FontSize="12"/>
|
||||
<TextBlock Text="优先级" Foreground="#666" Margin="0,0,0,4" FontSize="10"/>
|
||||
<ComboBox ItemsSource="{Binding Source={StaticResource PriorityEnum}}"
|
||||
SelectedItem="{Binding EditPriority}"
|
||||
Width="300" VerticalContentAlignment="Center" BorderThickness="1" BorderBrush="#DDD">
|
||||
Width="260" VerticalContentAlignment="Center" BorderThickness="1" BorderBrush="#DDD" FontSize="11">
|
||||
<ComboBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock Text="{Binding Converter={StaticResource EnumDescConverter}}"/>
|
||||
@@ -355,26 +311,26 @@
|
||||
</ComboBox>
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Grid.Row="2" Orientation="Horizontal" HorizontalAlignment="Center" Margin="0,15,0,0">
|
||||
<Button Content="取消" Command="{Binding CloseEditDialogCommand}" Width="80" Margin="0,0,10,0"
|
||||
Background="#EEE" Foreground="#333" Height="30" BorderThickness="0">
|
||||
<StackPanel Grid.Row="2" Orientation="Horizontal" HorizontalAlignment="Center" Margin="0,12,0,0">
|
||||
<Button Content="取消" Command="{Binding CloseEditDialogCommand}" Width="70" Margin="0,0,8,0"
|
||||
Background="#EEE" Foreground="#333" Height="26" BorderThickness="0" FontSize="11">
|
||||
<Button.Template>
|
||||
<ControlTemplate TargetType="Button">
|
||||
<Border Background="{TemplateBinding Background}" CornerRadius="5">
|
||||
<Border Background="{TemplateBinding Background}" CornerRadius="4">
|
||||
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
||||
</Border>
|
||||
</ControlTemplate>
|
||||
</Button.Template>
|
||||
</Button>
|
||||
<Button Content="保存" Command="{Binding SaveEditCommand}" Width="80" Height="30" Style="{StaticResource ModernButton}"/>
|
||||
<Button Content="保存" Command="{Binding SaveEditCommand}" Width="70" Height="26" Style="{StaticResource ModernButton}" FontSize="11"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Border>
|
||||
</Grid>
|
||||
|
||||
<!-- Footer -->
|
||||
<Border Grid.Row="3" Background="#F5F5F7" Padding="15,10" HorizontalAlignment="Center">
|
||||
<TextBlock>
|
||||
<Border Grid.Row="3" Background="#F5F5F7" Padding="10,8" HorizontalAlignment="Center">
|
||||
<TextBlock FontSize="10">
|
||||
<Hyperlink NavigateUri="https://github.com/xinshoushangdao/TodoList" RequestNavigate="Hyperlink_RequestNavigate">
|
||||
<Run Text="GitHub Repository"/>
|
||||
</Hyperlink>
|
||||
|
||||
@@ -28,7 +28,7 @@ namespace TodoList.Views
|
||||
// If settings are open, close settings?
|
||||
// But user requirement is "Equals pressing X button", which usually means Close/Hide window.
|
||||
// However, if we want better UX:
|
||||
if (DataContext is MainViewModel vm && vm.IsSettingsOpen)
|
||||
if (DataContext is MainViewModel { IsSettingsOpen: true } vm)
|
||||
{
|
||||
vm.IsSettingsOpen = false;
|
||||
e.Handled = true;
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
xmlns:models="clr-namespace:TodoList.Models"
|
||||
xmlns:converters="clr-namespace:TodoList.Converters"
|
||||
mc:Ignorable="d"
|
||||
Title="新建待办" Height="220" Width="400"
|
||||
Title="新建待办" Height="180" Width="320"
|
||||
WindowStyle="None" ResizeMode="NoResize"
|
||||
WindowStartupLocation="CenterScreen"
|
||||
Topmost="True"
|
||||
@@ -41,7 +41,7 @@
|
||||
</Style>
|
||||
</Window.Resources>
|
||||
|
||||
<Grid Margin="20">
|
||||
<Grid Margin="15">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
@@ -49,11 +49,11 @@
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<TextBlock Text="新建待办" FontSize="18" FontWeight="Bold" Foreground="#333"/>
|
||||
<TextBlock Text="新建待办" FontSize="15" FontWeight="Bold" Foreground="#333"/>
|
||||
|
||||
<TextBox Grid.Row="1" Margin="0,15,0,15"
|
||||
<TextBox Grid.Row="1" Margin="0,12,0,12"
|
||||
Text="{Binding Content, UpdateSourceTrigger=PropertyChanged}"
|
||||
FontSize="14" Padding="8" BorderThickness="0,0,0,1"
|
||||
FontSize="12" Padding="6" BorderThickness="0,0,0,1"
|
||||
x:Name="InputBox">
|
||||
<TextBox.InputBindings>
|
||||
<KeyBinding Key="Enter" Command="{Binding SaveCommand}"/>
|
||||
@@ -62,10 +62,10 @@
|
||||
</TextBox>
|
||||
|
||||
<StackPanel Grid.Row="2" Orientation="Horizontal" VerticalAlignment="Top">
|
||||
<TextBlock Text="优先级:" VerticalAlignment="Center" Margin="0,0,10,0" Foreground="#666"/>
|
||||
<TextBlock Text="优先级:" VerticalAlignment="Center" Margin="0,0,8,0" Foreground="#666" FontSize="11"/>
|
||||
<ComboBox ItemsSource="{Binding Source={StaticResource PriorityEnum}}"
|
||||
SelectedItem="{Binding Priority}"
|
||||
Width="100">
|
||||
Width="80" FontSize="11">
|
||||
<ComboBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock Text="{Binding Converter={StaticResource EnumDescConverter}}"/>
|
||||
@@ -75,10 +75,10 @@
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Grid.Row="3" Orientation="Horizontal" HorizontalAlignment="Right">
|
||||
<Button Content="取消" Command="{Binding CancelCommand}" Margin="0,0,10,0" Width="80" Height="32"
|
||||
Background="#F0F0F0" Foreground="#333"/>
|
||||
<Button Content="保存" Command="{Binding SaveCommand}" Width="80" Height="32" IsDefault="True"
|
||||
Background="#007AFF" Foreground="White"/>
|
||||
<Button Content="取消" Command="{Binding CancelCommand}" Margin="0,0,8,0" Width="65" Height="26"
|
||||
Background="#F0F0F0" Foreground="#333" FontSize="11"/>
|
||||
<Button Content="保存" Command="{Binding SaveCommand}" Width="65" Height="26" IsDefault="True"
|
||||
Background="#007AFF" Foreground="#White" FontSize="11"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Window>
|
||||
|
||||
Reference in New Issue
Block a user