diff --git a/PCL.Core/App/Localization/Languages/en-US.xaml b/PCL.Core/App/Localization/Languages/en-US.xaml
index c090e7a13e..2ab64259ad 100644
--- a/PCL.Core/App/Localization/Languages/en-US.xaml
+++ b/PCL.Core/App/Localization/Languages/en-US.xaml
@@ -598,7 +598,7 @@
Download the latest version
Select a target Minecraft instance
- Select an instance…
+ Select instances…
Select a folder…
Download to the current instance
Select a download destination
diff --git a/PCL.Core/App/Localization/Languages/zh-CN.xaml b/PCL.Core/App/Localization/Languages/zh-CN.xaml
index 9bae29f93c..0d6318c996 100644
--- a/PCL.Core/App/Localization/Languages/zh-CN.xaml
+++ b/PCL.Core/App/Localization/Languages/zh-CN.xaml
@@ -598,7 +598,7 @@
快速下载最新版本
选择要下载到的 Minecraft 实例
- 选择一个实例…
+ 选择实例…
选择一个文件夹…
下载到当前选中实例
选择下载方式
diff --git a/Plain Craft Launcher 2/Controls/MyMsg/MyMsgSelect.xaml.cs b/Plain Craft Launcher 2/Controls/MyMsg/MyMsgSelect.xaml.cs
index c489762258..d978020881 100644
--- a/Plain Craft Launcher 2/Controls/MyMsg/MyMsgSelect.xaml.cs
+++ b/Plain Craft Launcher 2/Controls/MyMsg/MyMsgSelect.xaml.cs
@@ -1,4 +1,4 @@
-using System.Collections;
+using System.Collections;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
@@ -82,11 +82,13 @@ private void InitializeSelectionList(object content)
{
PanSelection.Children.Add((UIElement)selection);
selection.Check += (sender, e) => OnChecked((IMyRadio)sender, e);
+ selection.Changed += (_, _) => _UpdateCheckedState();
// 3. Property configuration based on specific type
if (selection is MyListItem listItem)
{
- listItem.Type = MyListItem.CheckType.RadioBox;
+ listItem.Type =
+ myConverter.MultiSelect ? MyListItem.CheckType.CheckBox : MyListItem.CheckType.RadioBox;
listItem.MinHeight = 24.0;
}
else if (selection is MyRadioBox radioBox)
@@ -163,10 +165,26 @@ private void Close()
public void Btn1_Click(object sender, MouseButtonEventArgs e)
{
- if (myConverter.IsExited || selectedIndex == -1)
+ if (myConverter.IsExited)
return;
- myConverter.IsExited = true;
- myConverter.Result = selectedIndex;
+ if (myConverter.MultiSelect)
+ {
+ var indices = new List();
+ for (var i = 0; i < PanSelection.Children.Count; i++)
+ if (PanSelection.Children[i] is MyListItem { Checked: true })
+ indices.Add(i);
+ if (indices.Count == 0)
+ return;
+ myConverter.IsExited = true;
+ myConverter.Result = indices;
+ }
+ else
+ {
+ if (selectedIndex == -1)
+ return;
+ myConverter.IsExited = true;
+ myConverter.Result = selectedIndex;
+ }
Close();
}
@@ -181,10 +199,24 @@ public void Btn2_Click(object sender, MouseButtonEventArgs e)
private void OnChecked(IMyRadio sender, EventArgs e)
{
+ if (myConverter.MultiSelect)
+ return;
Btn1.IsEnabled = true;
selectedIndex = PanSelection.Children.IndexOf((UIElement)sender);
}
+ private void _UpdateCheckedState()
+ {
+ // 多选
+ if (!myConverter.MultiSelect)
+ return;
+ var checkedCount = 0;
+ foreach (var child in PanSelection.Children)
+ if (child is MyListItem { Checked: true })
+ checkedCount += 1;
+ Btn1.IsEnabled = checkedCount > 0;
+ }
+
private void Drag(object sender, MouseButtonEventArgs e)
{
try
diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModComp.cs b/Plain Craft Launcher 2/Modules/Minecraft/ModComp.cs
index 771943c813..be64a00ea3 100644
--- a/Plain Craft Launcher 2/Modules/Minecraft/ModComp.cs
+++ b/Plain Craft Launcher 2/Modules/Minecraft/ModComp.cs
@@ -3540,9 +3540,11 @@ public static void QuickDownload(CompProject project)
break;
case 2: // 询问并下载到选择的实例
{
- var instance = _QuickDownloadPickInstance(project, files);
- if (instance is null) return;
- _QuickDownloadToInstance(project, files, instance);
+ var instances = _QuickDownloadPickInstances(project, files);
+ if (instances is null) return;
+ var startedTargets = new HashSet(StringComparer.OrdinalIgnoreCase);
+ foreach (var instance in instances)
+ _QuickDownloadToInstance(project, files, instance, startedTargets);
break;
}
case 3: // 询问并下载到一个路径
@@ -3562,7 +3564,8 @@ public static void QuickDownload(CompProject project)
}
/// 下载到指定实例的最新兼容版本。
- private static void _QuickDownloadToInstance(CompProject project, List files, McInstance? instance)
+ private static void _QuickDownloadToInstance(CompProject project, List files, McInstance? instance,
+ ISet? startedTargets = null)
{
if (instance is null)
{
@@ -3582,12 +3585,15 @@ private static void _QuickDownloadToInstance(CompProject project, List
var folder = instance.PathIndie + _GetSubFolder(project.Type);
Directory.CreateDirectory(folder);
var target = Path.Combine(folder, CompFileNameGet(project, file));
+ //只下载一次,避免并发写同一文件
+ if (startedTargets is not null && !startedTargets.Add(target))
+ return;
_StartQuickDownload(file, target);
HintService.Hint(Lang.Text("Download.Comp.QuickDownload.Hint.DownloadStarted", project.RawName), HintType.Success);
}
/// 弹实例列表让用户选择,返回选中的实例(兼容者优先、当前选中实例居首);取消或无兼容实例返回 null。
- private static McInstance? _QuickDownloadPickInstance(CompProject project, List files)
+ private static List? _QuickDownloadPickInstances(CompProject project, List files)
{
var needLoad = ModInstanceList.mcInstanceListLoader.State != ModBase.LoadState.Finished;
if (needLoad)
@@ -3612,18 +3618,18 @@ private static void _QuickDownloadToInstance(CompProject project, List
.OrderBy(v => v == current ? 0 : 1)
.ThenBy(v => v.Name)
.ToList();
- int? idx = ModBase.RunInUiWait(() =>
+ var indices = ModBase.RunInUiWait(() =>
{
var options = compatible
- .Select(v => (IMyRadio)new MyRadioBox { Text = v.Name })
+ .Select(v => new MyListItem { Title = v.Name })
.ToList();
- return ModMain.MyMsgBoxSelect(options,
+ return ModMain.MyMsgBoxMultiSelect(options,
Lang.Text("Download.Comp.QuickDownload.ChooseInstance.Title"),
button1: Lang.Text("Common.Action.Continue"),
button2: Lang.Text("Common.Action.Cancel"));
});
- if (idx is null) return null;
- return compatible[idx.Value];
+ if (indices is null) return null;
+ return indices.Select(i => compatible[i]).ToList();
}
/// 下载最新版本到用户选择的文件夹。
diff --git a/Plain Craft Launcher 2/Modules/ModMain.cs b/Plain Craft Launcher 2/Modules/ModMain.cs
index c1ecd882a1..f33362a7bb 100644
--- a/Plain Craft Launcher 2/Modules/ModMain.cs
+++ b/Plain Craft Launcher 2/Modules/ModMain.cs
@@ -1,4 +1,4 @@
-using System.Collections;
+using System.Collections;
using System.Collections.ObjectModel;
using System.IO;
using System.Runtime.InteropServices;
@@ -262,6 +262,11 @@ public class MyMsgBoxConverter
public bool ForceWait;
+ ///
+ /// 选择模式:是否允许勾选多个选项
+ ///
+ public bool MultiSelect;
+
///
/// 有多个按钮时,是否给第一个按钮加高亮。
///
@@ -581,6 +586,44 @@ public static string MyMsgBoxInput(string title, string text = "", string defaul
return (int?)converter.Result;
}
+ ///
+ /// 显示多选选择框并返回勾选的所有项索引(从 0 开始)。若点击第二个按钮,则返回 Nothing。
+ ///
+ /// 需要展示的可勾选列表项。
+ /// 弹窗的标题。
+ /// 显示的第一个按钮,默认为 “确定”。
+ /// 显示的第二个按钮,默认为空。
+ /// 是否为警告弹窗,若为 True,弹窗配色和背景会变为红色。
+ public static List? MyMsgBoxMultiSelect(List selections, string? title = null,
+ string? button1 = null, string? button2 = "", bool isWarn = false)
+ {
+ title ??= GetDefaultDialogTitle();
+ button1 ??= GetDefaultConfirmText();
+ button2 ??= "";
+ // 将弹窗列入队列
+ var converter = new MyMsgBoxConverter
+ {
+ Type = MyMsgBoxType.Select, MultiSelect = true, Button1 = button1, Button2 = button2, Content = selections,
+ IsWarn = isWarn, Title = title
+ };
+ WaitingMyMsgBox.Add(converter);
+ // 虽然我也不知道这是啥但是能用就成了 :)
+ try
+ {
+ if (frmMain is not null)
+ frmMain.DragStop();
+ ComponentDispatcher.PushModal();
+ Dispatcher.PushFrame(converter.WaitFrame);
+ }
+ finally
+ {
+ ComponentDispatcher.PopModal();
+ }
+
+ ModBase.Log($"[Control] 多选弹框返回:{converter.Result ?? "null"}");
+ return (List?)converter.Result;
+ }
+
public static void MyMsgBoxTick()
{