Skip to content

Commit fdecd67

Browse files
committed
feat: 添加批量操作功能和关于窗口,更新版本号至 1.4.0
1 parent 3c594be commit fdecd67

File tree

5 files changed

+313
-2
lines changed

5 files changed

+313
-2
lines changed

MainWindow.xaml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,8 @@
161161
<Separator/>
162162
<MenuItem Header="清空内容" Click="Clear_Click"/>
163163
<MenuItem Header="删除此便签 (Ctrl+D)" Click="DeleteNote_Click" Foreground="Red"/>
164+
<Separator/>
165+
<MenuItem Header="关于 StickyNote v1.4.0" Click="About_Click"/>
164166
</ContextMenu>
165167
</Border.ContextMenu>
166168

@@ -289,6 +291,28 @@
289291
HorizontalScrollBarVisibility="Auto"
290292
TextChanged="RtbContent_TextChanged"
291293
PreviewMouseLeftButtonUp="RtbContent_PreviewMouseLeftButtonUp">
294+
<RichTextBox.ContextMenu>
295+
<ContextMenu>
296+
<MenuItem Header="设为待办" Click="BatchSetTodo_Click"/>
297+
<MenuItem Header="取消待办" Click="BatchUnsetTodo_Click"/>
298+
<Separator/>
299+
<MenuItem Header="标记完成" Click="BatchCheckTodo_Click"/>
300+
<MenuItem Header="取消完成" Click="BatchUncheckTodo_Click"/>
301+
<Separator/>
302+
<MenuItem Header="添加编号">
303+
<MenuItem Header="1. 内容" Click="BatchNumbering_Click" Tag="1."/>
304+
<MenuItem Header="1) 内容" Click="BatchNumbering_Click" Tag="1)"/>
305+
<MenuItem Header="① 内容" Click="BatchNumbering_Click" Tag=""/>
306+
<MenuItem Header="A. 内容" Click="BatchNumbering_Click" Tag="A."/>
307+
<Separator/>
308+
<MenuItem Header="取消编号" Click="BatchRemoveNumbering_Click"/>
309+
</MenuItem>
310+
<Separator/>
311+
<MenuItem Header="剪切" Command="Cut"/>
312+
<MenuItem Header="复制" Command="Copy"/>
313+
<MenuItem Header="粘贴" Command="Paste"/>
314+
</ContextMenu>
315+
</RichTextBox.ContextMenu>
292316
<RichTextBox.Resources>
293317
<Style TargetType="Paragraph">
294318
<Setter Property="Margin" Value="0"/>

MainWindow.xaml.cs

Lines changed: 284 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -605,6 +605,282 @@ private void ReplaceTodoSymbol(TextPointer start, string oldSymbol, string newSy
605605
}
606606
}
607607

608+
// --- 批量操作与编号 ---
609+
610+
private List<Paragraph> GetSelectedParagraphs()
611+
{
612+
var list = new List<Paragraph>();
613+
var start = rtbContent.Selection.Start;
614+
var end = rtbContent.Selection.End;
615+
616+
// 确保 start < end
617+
if (start.CompareTo(end) > 0) (start, end) = (end, start);
618+
619+
Block current = rtbContent.Document.Blocks.FirstBlock;
620+
while (current != null)
621+
{
622+
// 检查交叉:Block Start <= Selection End AND Block End >= Selection Start
623+
if (current.ContentStart.CompareTo(end) <= 0 && current.ContentEnd.CompareTo(start) >= 0)
624+
{
625+
if (current is Paragraph p) list.Add(p);
626+
}
627+
628+
if (current.ContentStart.CompareTo(end) > 0) break;
629+
630+
current = current.NextBlock;
631+
}
632+
return list;
633+
}
634+
635+
private void BatchSetTodo_Click(object sender, RoutedEventArgs e)
636+
{
637+
var paras = GetSelectedParagraphs();
638+
if (paras.Count == 0) return;
639+
640+
rtbContent.BeginChange();
641+
try
642+
{
643+
foreach (var p in paras)
644+
{
645+
string text = new TextRange(p.ContentStart, p.ContentEnd).Text;
646+
if (!text.StartsWith("☐ ") && !text.StartsWith("☑ "))
647+
{
648+
// 确保 Paragraph 有 Inline,如果没有(空行),添加一个 Run
649+
if (p.Inlines.Count == 0)
650+
{
651+
p.Inlines.Add(new Run("☐ "));
652+
}
653+
else
654+
{
655+
p.Inlines.InsertBefore(p.Inlines.FirstInline, new Run("☐ "));
656+
}
657+
}
658+
}
659+
}
660+
finally
661+
{
662+
rtbContent.EndChange();
663+
SaveState();
664+
}
665+
}
666+
667+
private void BatchUnsetTodo_Click(object sender, RoutedEventArgs e)
668+
{
669+
var paras = GetSelectedParagraphs();
670+
if (paras.Count == 0) return;
671+
672+
rtbContent.BeginChange();
673+
try
674+
{
675+
foreach (var p in paras)
676+
{
677+
TextPointer start = p.ContentStart.GetInsertionPosition(LogicalDirection.Forward);
678+
string text = start.GetTextInRun(LogicalDirection.Forward);
679+
680+
if (text.StartsWith("☐ ") || text.StartsWith("☑ "))
681+
{
682+
TextPointer delEnd = start.GetPositionAtOffset(2);
683+
new TextRange(start, delEnd).Text = "";
684+
}
685+
else if (text.StartsWith("☐") || text.StartsWith("☑"))
686+
{
687+
TextPointer delEnd = start.GetPositionAtOffset(1);
688+
new TextRange(start, delEnd).Text = "";
689+
}
690+
}
691+
}
692+
finally
693+
{
694+
rtbContent.EndChange();
695+
SaveState();
696+
}
697+
}
698+
699+
private void BatchCheckTodo_Click(object sender, RoutedEventArgs e)
700+
{
701+
var paras = GetSelectedParagraphs();
702+
if (paras.Count == 0) return;
703+
704+
rtbContent.BeginChange();
705+
try
706+
{
707+
foreach (var p in paras)
708+
{
709+
TextPointer start = p.ContentStart.GetInsertionPosition(LogicalDirection.Forward);
710+
string text = start.GetTextInRun(LogicalDirection.Forward);
711+
712+
if (text.StartsWith("☐"))
713+
{
714+
TextPointer symbolEnd = start.GetPositionAtOffset(1);
715+
new TextRange(start, symbolEnd).Text = "☑";
716+
}
717+
}
718+
}
719+
finally
720+
{
721+
rtbContent.EndChange();
722+
SaveState();
723+
}
724+
}
725+
726+
private void BatchUncheckTodo_Click(object sender, RoutedEventArgs e)
727+
{
728+
var paras = GetSelectedParagraphs();
729+
if (paras.Count == 0) return;
730+
731+
rtbContent.BeginChange();
732+
try
733+
{
734+
foreach (var p in paras)
735+
{
736+
TextPointer start = p.ContentStart.GetInsertionPosition(LogicalDirection.Forward);
737+
string text = start.GetTextInRun(LogicalDirection.Forward);
738+
739+
if (text.StartsWith("☑"))
740+
{
741+
TextPointer symbolEnd = start.GetPositionAtOffset(1);
742+
new TextRange(start, symbolEnd).Text = "☐";
743+
}
744+
}
745+
}
746+
finally
747+
{
748+
rtbContent.EndChange();
749+
SaveState();
750+
}
751+
}
752+
753+
private void BatchNumbering_Click(object sender, RoutedEventArgs e)
754+
{
755+
if (sender is MenuItem item && item.Tag is string style)
756+
{
757+
var paras = GetSelectedParagraphs();
758+
if (paras.Count == 0) return;
759+
760+
rtbContent.BeginChange();
761+
try
762+
{
763+
// 先尝试移除现有的编号,避免重复添加
764+
RemoveNumbering(paras);
765+
766+
int index = 1;
767+
foreach (var p in paras)
768+
{
769+
string text = new TextRange(p.ContentStart, p.ContentEnd).Text;
770+
if (string.IsNullOrWhiteSpace(text)) continue;
771+
772+
string prefix = "";
773+
switch (style)
774+
{
775+
case "1.": prefix = $"{index}. "; break;
776+
case "1)": prefix = $"{index}) "; break;
777+
case "①": prefix = $"{GetCircleNumber(index)} "; break;
778+
case "A.": prefix = $"{GetAlphaNumber(index)}. "; break;
779+
}
780+
781+
if (p.Inlines.Count == 0)
782+
p.Inlines.Add(new Run(prefix));
783+
else
784+
p.Inlines.InsertBefore(p.Inlines.FirstInline, new Run(prefix));
785+
786+
index++;
787+
}
788+
}
789+
finally
790+
{
791+
rtbContent.EndChange();
792+
SaveState();
793+
}
794+
}
795+
}
796+
797+
private void BatchRemoveNumbering_Click(object sender, RoutedEventArgs e)
798+
{
799+
var paras = GetSelectedParagraphs();
800+
if (paras.Count == 0) return;
801+
802+
rtbContent.BeginChange();
803+
try
804+
{
805+
RemoveNumbering(paras);
806+
}
807+
finally
808+
{
809+
rtbContent.EndChange();
810+
SaveState();
811+
}
812+
}
813+
814+
private void RemoveNumbering(List<Paragraph> paras)
815+
{
816+
foreach (var p in paras)
817+
{
818+
TextPointer start = p.ContentStart.GetInsertionPosition(LogicalDirection.Forward);
819+
string text = start.GetTextInRun(LogicalDirection.Forward);
820+
821+
// 匹配常见的编号格式
822+
// 1. 1) ① A. (1) 等
823+
// 这里使用简单的逻辑判断,移除开头的特定模式
824+
825+
int removeLen = 0;
826+
827+
// 检查 A. B. ...
828+
if (text.Length >= 3 && char.IsLetter(text[0]) && text[1] == '.' && text[2] == ' ')
829+
removeLen = 3;
830+
// 检查数字开头的 1. 10. 1) 10) ...
831+
else if (char.IsDigit(text[0]))
832+
{
833+
int i = 0;
834+
while (i < text.Length && char.IsDigit(text[i])) i++;
835+
if (i < text.Length && (text[i] == '.' || text[i] == ')') && i + 1 < text.Length && text[i+1] == ' ')
836+
{
837+
removeLen = i + 2;
838+
}
839+
}
840+
// 检查 ① ... ⑳
841+
else if (text.Length >= 2 && text[0] >= '①' && text[0] <= '⑳' && text[1] == ' ')
842+
{
843+
removeLen = 2;
844+
}
845+
// 检查 (1) ...
846+
else if (text.StartsWith("(") && text.Contains(")") && text.IndexOf(")") < 6)
847+
{
848+
int idx = text.IndexOf(")");
849+
if (idx + 1 < text.Length && text[idx+1] == ' ')
850+
{
851+
// 确保括号里是数字
852+
bool isNum = true;
853+
for(int k=1; k<idx; k++) if(!char.IsDigit(text[k])) { isNum = false; break; }
854+
if (isNum) removeLen = idx + 2;
855+
}
856+
}
857+
858+
if (removeLen > 0)
859+
{
860+
TextPointer delEnd = start.GetPositionAtOffset(removeLen);
861+
new TextRange(start, delEnd).Text = "";
862+
}
863+
}
864+
}
865+
866+
private string GetCircleNumber(int i)
867+
{
868+
if (i >= 1 && i <= 20) return ((char)('①' + i - 1)).ToString();
869+
return $"({i})";
870+
}
871+
872+
private string GetAlphaNumber(int i)
873+
{
874+
string res = "";
875+
while (i > 0)
876+
{
877+
i--;
878+
res = (char)('A' + (i % 26)) + res;
879+
i /= 26;
880+
}
881+
return res;
882+
}
883+
608884
// 右键菜单:改颜色
609885
// 标签选择变化事件
610886
private void TabList_SelectionChanged(object sender, SelectionChangedEventArgs e)
@@ -1198,6 +1474,14 @@ private void Search_Click(object sender, RoutedEventArgs e)
11981474
NoteSearch.Show();
11991475
}
12001476

1477+
private void About_Click(object sender, RoutedEventArgs e)
1478+
{
1479+
var version = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version;
1480+
// 格式化为 v1.4.0 (去掉末尾的 .0 如果是 0)
1481+
string verStr = version != null ? $"{version.Major}.{version.Minor}.{version.Build}" : "1.4.0";
1482+
System.Windows.MessageBox.Show($"StickyNote 便签\n版本: v{verStr}\n\n一个简单好用的桌面便签工具。", "关于", MessageBoxButton.OK, MessageBoxImage.Information);
1483+
}
1484+
12011485
}
12021486

12031487
// --- 数据管理类 ---

StickyNote.csproj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@
88
<UseWPF>true</UseWPF>
99
<UseWindowsForms>true</UseWindowsForms>
1010
<ApplicationIcon>app.ico</ApplicationIcon>
11+
<Version>1.4.0</Version>
12+
<FileVersion>1.4.0</FileVersion>
13+
<AssemblyVersion>1.4.0</AssemblyVersion>
1114
</PropertyGroup>
1215

1316
<ItemGroup>

installer/StickyNote_sc.iss

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#define AppName "StickyNote"
2-
#define AppVersion "1.0.0"
2+
#define AppVersion "1.4.0"
33
#define AppPublisher "StickyNote"
44
#define AppURL "https://example.invalid/StickyNote"
55
#define AppExe "StickyNote.exe"

installer/StickyNote_slim.iss

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#define AppName "StickyNote"
2-
#define AppVersion "1.0.0"
2+
#define AppVersion "1.4.0"
33
#define AppPublisher "StickyNote"
44
#define AppURL "https://example.invalid/StickyNote"
55
#define AppExe "StickyNote.exe"

0 commit comments

Comments
 (0)