From dd512a0dcbfae9a131c9408a3c4ceac561fda1a2 Mon Sep 17 00:00:00 2001 From: chfei Date: Mon, 12 Oct 2026 18:43:32 +0800 Subject: [PATCH 1/2] =?UTF-8?q?=E6=9B=B4=E6=96=B0=20Dialog=E5=BC=B9?= =?UTF-8?q?=E5=87=BA=E6=A1=86=E6=A8=A1=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 29WxOrderWpf/Common/DialogWindow.xaml.cs | 7 +- 29WxOrderWpf/Common/Dialogs/ButtonResult.cs | 41 ++++ 29WxOrderWpf/Common/Dialogs/Dialog.cs | 82 ++++++++ .../Common/Dialogs/DialogParameters.cs | 24 +++ 29WxOrderWpf/Common/Dialogs/DialogResult.cs | 44 ++++ 29WxOrderWpf/Common/Dialogs/DialogService.cs | 170 +++++++++++++++ 29WxOrderWpf/Common/Dialogs/IDialogAware.cs | 37 ++++ .../Common/Dialogs/IDialogParameters.cs | 63 ++++++ 29WxOrderWpf/Common/Dialogs/IDialogResult.cs | 19 ++ 29WxOrderWpf/Common/Dialogs/IDialogWindow.cs | 71 +++++++ 29WxOrderWpf/Common/Dialogs/IParameters.cs | 71 +++++++ 29WxOrderWpf/Common/Dialogs/ParametersBase.cs | 198 ++++++++++++++++++ .../Common/Dialogs/ParametersExtensions.cs | 163 ++++++++++++++ 13 files changed, 988 insertions(+), 2 deletions(-) create mode 100644 29WxOrderWpf/Common/Dialogs/ButtonResult.cs create mode 100644 29WxOrderWpf/Common/Dialogs/Dialog.cs create mode 100644 29WxOrderWpf/Common/Dialogs/DialogParameters.cs create mode 100644 29WxOrderWpf/Common/Dialogs/DialogResult.cs create mode 100644 29WxOrderWpf/Common/Dialogs/DialogService.cs create mode 100644 29WxOrderWpf/Common/Dialogs/IDialogAware.cs create mode 100644 29WxOrderWpf/Common/Dialogs/IDialogParameters.cs create mode 100644 29WxOrderWpf/Common/Dialogs/IDialogResult.cs create mode 100644 29WxOrderWpf/Common/Dialogs/IDialogWindow.cs create mode 100644 29WxOrderWpf/Common/Dialogs/IParameters.cs create mode 100644 29WxOrderWpf/Common/Dialogs/ParametersBase.cs create mode 100644 29WxOrderWpf/Common/Dialogs/ParametersExtensions.cs diff --git a/29WxOrderWpf/Common/DialogWindow.xaml.cs b/29WxOrderWpf/Common/DialogWindow.xaml.cs index b650996..52c9b84 100644 --- a/29WxOrderWpf/Common/DialogWindow.xaml.cs +++ b/29WxOrderWpf/Common/DialogWindow.xaml.cs @@ -1,4 +1,5 @@ -using System; +using Prism.Services.Dialogs; +using System; using System.Linq; using System.Runtime.InteropServices; using System.Runtime.Remoting.Contexts; @@ -14,7 +15,7 @@ namespace _29WxOrderWpf.Common /// /// DialogWindow.xaml 的交互逻辑 /// - public partial class DialogWindow : Window + public partial class DialogWindow : Window, IDialogWindow { private readonly Style dialogWindowStyle; private bool isConstructorSuccessful = false; @@ -101,6 +102,8 @@ namespace _29WxOrderWpf.Common private const int GWL_STYLE = -16; private const int WS_MINIMIZEBOX = 0x00020000; + public IDialogResult Result { get; set; } + [DllImport("user32.dll")] private static extern int GetWindowLong(IntPtr hWnd, int nIndex); diff --git a/29WxOrderWpf/Common/Dialogs/ButtonResult.cs b/29WxOrderWpf/Common/Dialogs/ButtonResult.cs new file mode 100644 index 0000000..eeaa6ea --- /dev/null +++ b/29WxOrderWpf/Common/Dialogs/ButtonResult.cs @@ -0,0 +1,41 @@ +namespace Prism.Services.Dialogs +{ + /// + /// The result of the dialog. + /// + public enum ButtonResult + { + /// + /// Abort. + /// + Abort = 3, + /// + /// Cancel. + /// + Cancel = 2, + /// + /// Ignore. + /// + Ignore = 5, + /// + /// No. + /// + No = 7, + /// + /// No result returned. + /// + None = 0, + /// + /// OK. + /// + OK = 1, + /// + /// Retry. + /// + Retry = 4, + /// + /// Yes. + /// + Yes = 6 + } +} diff --git a/29WxOrderWpf/Common/Dialogs/Dialog.cs b/29WxOrderWpf/Common/Dialogs/Dialog.cs new file mode 100644 index 0000000..caf978e --- /dev/null +++ b/29WxOrderWpf/Common/Dialogs/Dialog.cs @@ -0,0 +1,82 @@ +#if HAS_UWP +using Windows.UI.Xaml; +#elif HAS_WINUI +using Microsoft.UI.Xaml; +#else +using System.Windows; +#endif + +namespace Prism.Services.Dialogs +{ + /// + /// This class contains attached properties. + /// + public class Dialog + { + /// + /// Identifies the WindowStyle attached property. + /// + /// + /// This attached property is used to specify the style of a . + /// + public static readonly DependencyProperty WindowStyleProperty = + DependencyProperty.RegisterAttached("WindowStyle", typeof(Style), typeof(Dialog), new PropertyMetadata(null)); + + /// + /// Gets the value for the attached property. + /// + /// The target element. + /// The attached to the element. + public static Style GetWindowStyle(DependencyObject obj) + { + return (Style)obj.GetValue(WindowStyleProperty); + } + + /// + /// Sets the attached property. + /// + /// The target element. + /// The Style to attach. + public static void SetWindowStyle(DependencyObject obj, Style value) + { + obj.SetValue(WindowStyleProperty, value); + } + +#if !HAS_UWP && !HAS_WINUI + /// + /// Identifies the WindowStartupLocation attached property. + /// + /// + /// This attached property is used to specify the startup location of a . + /// + public static readonly DependencyProperty WindowStartupLocationProperty = + DependencyProperty.RegisterAttached("WindowStartupLocation", typeof(WindowStartupLocation), typeof(Dialog), new UIPropertyMetadata(OnWindowStartupLocationChanged)); + + /// + /// Gets the value for the attached property. + /// + /// The target element. + /// The attached to the element. + public static WindowStartupLocation GetWindowStartupLocation(DependencyObject obj) + { + return (WindowStartupLocation)obj.GetValue(WindowStartupLocationProperty); + } + + /// + /// Sets the attached property. + /// + /// The target element. + /// The WindowStartupLocation to attach. + public static void SetWindowStartupLocation(DependencyObject obj, WindowStartupLocation value) + { + obj.SetValue(WindowStartupLocationProperty, value); + } + + private static void OnWindowStartupLocationChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) + { + if (sender is Window window) + window.WindowStartupLocation = (WindowStartupLocation)e.NewValue; + } +#endif + } +} diff --git a/29WxOrderWpf/Common/Dialogs/DialogParameters.cs b/29WxOrderWpf/Common/Dialogs/DialogParameters.cs new file mode 100644 index 0000000..b853673 --- /dev/null +++ b/29WxOrderWpf/Common/Dialogs/DialogParameters.cs @@ -0,0 +1,24 @@ +using Prism.Common; + +namespace Prism.Services.Dialogs +{ + /// + /// Represents Dialog parameters. + /// + /// + /// This class can be used to to pass object parameters during the showing and closing of Dialogs. + /// + public class DialogParameters : ParametersBase, IDialogParameters + { + /// + /// Initializes a new instance of the class. + /// + public DialogParameters() : base() { } + + /// + /// Constructs a list of parameters. + /// + /// Query string to be parsed. + public DialogParameters(string query) : base(query) { } + } +} diff --git a/29WxOrderWpf/Common/Dialogs/DialogResult.cs b/29WxOrderWpf/Common/Dialogs/DialogResult.cs new file mode 100644 index 0000000..f0c9a8c --- /dev/null +++ b/29WxOrderWpf/Common/Dialogs/DialogResult.cs @@ -0,0 +1,44 @@ +namespace Prism.Services.Dialogs +{ + /// + /// An that contains from the dialog + /// and the of the dialog. + /// + public class DialogResult : IDialogResult + { + /// + /// The parameters from the dialog. + /// + public IDialogParameters Parameters { get; private set; } = new DialogParameters(); + + /// + /// The result of the dialog. + /// + public ButtonResult Result { get; private set; } = ButtonResult.None; + + /// + /// Initializes a new instance of the class. + /// + public DialogResult() { } + + /// + /// Initializes a new instance of the class. + /// + /// The result of the dialog. + public DialogResult(ButtonResult result) + { + Result = result; + } + + /// + /// Initializes a new instance of the class. + /// + /// The result of the dialog. + /// The parameters from the dialog. + public DialogResult(ButtonResult result, IDialogParameters parameters) + { + Result = result; + Parameters = parameters; + } + } +} diff --git a/29WxOrderWpf/Common/Dialogs/DialogService.cs b/29WxOrderWpf/Common/Dialogs/DialogService.cs new file mode 100644 index 0000000..aa80c0e --- /dev/null +++ b/29WxOrderWpf/Common/Dialogs/DialogService.cs @@ -0,0 +1,170 @@ +using _29WxOrderWpf.Common; +using Prism.Common; +using System; +using System.ComponentModel; +using System.Linq; +using System.Windows; + +namespace Prism.Services.Dialogs +{ + /// + /// 静态弹窗服务:不依赖容器,直接传入 View 实例弹出。 + /// ViewModel 需实现 IDialogAware。 + /// + public static class DialogService + { + // ========== 对外接口 ========== + + /// 非模态弹出 + public static void Show(FrameworkElement view, + IDialogParameters parameters = null, + Action callback = null, + IDialogWindow window = null) + { + ShowInternal(view, parameters, callback, false, window); + } + + /// 模态弹出 + public static void ShowDialog(FrameworkElement view, + IDialogParameters parameters = null, + Action callback = null, + IDialogWindow window = null) + { + ShowInternal(view, parameters, callback, true, window); + } + + // ========== 内部实现 ========== + + private static void ShowInternal(FrameworkElement view, + IDialogParameters parameters, + Action callback, + bool isModal, + IDialogWindow window) + { + if (view == null) throw new ArgumentNullException(nameof(view)); + if (parameters == null) parameters = new DialogParameters(); + + // 1. 创建(或使用传入的)DialogWindow + var dialogWindow = window ?? new DialogWindow(); + + // 2. 绑定事件(关闭、回调等) + ConfigureDialogWindowEvents(dialogWindow, callback); + + // 3. 配置内容(View + ViewModel) + ConfigureDialogWindowContent(view, dialogWindow, parameters); + + // 4. 弹出 + ShowDialogWindow(dialogWindow, isModal); + } + + private static void ShowDialogWindow(IDialogWindow dialogWindow, bool isModal) + { + if (isModal) + dialogWindow.ShowDialog(); + else + dialogWindow.Show(); + } + + /// + /// 把 View 挂到 DialogWindow 上,并触发 OnDialogOpened。 + /// + private static void ConfigureDialogWindowContent(FrameworkElement dialogContent, + IDialogWindow window, + IDialogParameters parameters) + { + // 不再自动绑 ViewModel,DataContext 由 View 自己负责 + if (!(dialogContent.DataContext is IDialogAware viewModel)) + throw new NullReferenceException("A dialog's ViewModel must implement the IDialogAware interface"); + + ConfigureDialogWindowProperties(window, dialogContent, viewModel); + + // 直接触发 OnDialogOpened(替代 MvvmHelpers.ViewAndViewModelAction) + viewModel.OnDialogOpened(parameters); + } + + /// + /// 绑定 DialogWindow 的生命周期事件。 + /// + private static void ConfigureDialogWindowEvents(IDialogWindow dialogWindow, Action callback) + { + Action requestCloseHandler = null; + requestCloseHandler = (o) => + { + dialogWindow.Result = o; + dialogWindow.Close(); + }; + + RoutedEventHandler loadedHandler = null; + loadedHandler = (o, e) => + { + dialogWindow.Loaded -= loadedHandler; + GetDialogViewModel(dialogWindow).RequestClose += requestCloseHandler; + }; + dialogWindow.Loaded += loadedHandler; + + CancelEventHandler closingHandler = null; + closingHandler = (o, e) => + { + if (!GetDialogViewModel(dialogWindow).CanCloseDialog()) + e.Cancel = true; + }; + dialogWindow.Closing += closingHandler; + + EventHandler closedHandler = null; + closedHandler = (o, e) => + { + dialogWindow.Closed -= closedHandler; + dialogWindow.Closing -= closingHandler; + GetDialogViewModel(dialogWindow).RequestClose -= requestCloseHandler; + GetDialogViewModel(dialogWindow).OnDialogClosed(); + + + if (dialogWindow.Result == null) + dialogWindow.Result = new DialogResult(); + + callback?.Invoke(dialogWindow.Result); + + dialogWindow.DataContext = null; + dialogWindow.Content = null; + }; + dialogWindow.Closed += closedHandler; + } + + /// + /// 设置 DialogWindow 的 Style / Content / DataContext / Owner。 + /// + private static void ConfigureDialogWindowProperties(IDialogWindow window, + FrameworkElement dialogContent, + IDialogAware viewModel) + { + var windowStyle = Dialog.GetWindowStyle(dialogContent); + if (windowStyle != null) + window.Style = windowStyle; + + window.Content = dialogContent; + window.DataContext = viewModel; // 宿主窗口和对话框共享同一个 DataContext + + if (window.Owner == null) + window.Owner = Application.Current?.Windows + .OfType() + .FirstOrDefault(x => x.IsActive); + } + + /// + /// 从 window.Content 或 window.DataContext 里拿 IDialogAware。 + /// 替代 Prism 的 dialogWindow.GetDialogViewModel() 扩展方法。 + /// + private static IDialogAware GetDialogViewModel(IDialogWindow window) + { + if (window.Content is FrameworkElement fe) + { + if (fe is IDialogAware aware) return aware; + if (fe.DataContext is IDialogAware vm) return vm; + } + + if (window.DataContext is IDialogAware wvm) return wvm; + + throw new NullReferenceException("A dialog's ViewModel must implement the IDialogAware interface"); + } + } +} diff --git a/29WxOrderWpf/Common/Dialogs/IDialogAware.cs b/29WxOrderWpf/Common/Dialogs/IDialogAware.cs new file mode 100644 index 0000000..7117f57 --- /dev/null +++ b/29WxOrderWpf/Common/Dialogs/IDialogAware.cs @@ -0,0 +1,37 @@ +using System; + +namespace Prism.Services.Dialogs +{ + /// + /// Interface that provides dialog functions and events to ViewModels. + /// + public interface IDialogAware + { + /// + /// Determines if the dialog can be closed. + /// + /// If true the dialog can be closed. If false the dialog will not close. + bool CanCloseDialog(); + + /// + /// Called when the dialog is closed. + /// + void OnDialogClosed(); + + /// + /// Called when the dialog is opened. + /// + /// The parameters passed to the dialog. + void OnDialogOpened(IDialogParameters parameters); + + /// + /// The title of the dialog that will show in the window title bar. + /// + string Title { get; } + + /// + /// Instructs the to close the dialog. + /// + event Action RequestClose; + } +} diff --git a/29WxOrderWpf/Common/Dialogs/IDialogParameters.cs b/29WxOrderWpf/Common/Dialogs/IDialogParameters.cs new file mode 100644 index 0000000..0083505 --- /dev/null +++ b/29WxOrderWpf/Common/Dialogs/IDialogParameters.cs @@ -0,0 +1,63 @@ +using System.Collections.Generic; + +namespace Prism.Services.Dialogs +{ + /// + /// Represents Dialog parameters. + /// + /// + /// A class that implements this interface can be used to pass + /// object parameters during the showing and closing of Dialogs. + /// + public interface IDialogParameters + { + /// + /// Adds the key and value to the collection. + /// + /// The key to reference this parameter value in the collection. + /// The parameter value to store. + void Add(string key, object value); + + /// + /// Checks the collection for the presence of a key. + /// + /// The key to check. + /// true if key exists; false otherwise. + bool ContainsKey(string key); + + /// + /// The number of parameters in the collection. + /// + int Count { get; } + + /// + /// The keys in the collection. + /// + IEnumerable Keys { get; } + + /// + /// Gets the parameter value referenced by a key. + /// + /// The type of object to be returned. + /// The key of the parameter value to be returned. + /// The matching parameter of type . + T GetValue(string key); + + /// + /// Gets all parameter values referenced by a key. + /// + /// The type of object to be returned. + /// The key of the parameter values to be returned. + ///All matching parameter values of type . + IEnumerable GetValues(string key); + + /// + /// Gets the parameter value if the referenced key exists. + /// + /// The type of object to be returned. + /// The key of the parameter value to be returned. + /// The matching parameter of type if the key exists. + /// true if the parameter exists; false otherwise. + bool TryGetValue(string key, out T value); + } +} diff --git a/29WxOrderWpf/Common/Dialogs/IDialogResult.cs b/29WxOrderWpf/Common/Dialogs/IDialogResult.cs new file mode 100644 index 0000000..1fefeb9 --- /dev/null +++ b/29WxOrderWpf/Common/Dialogs/IDialogResult.cs @@ -0,0 +1,19 @@ +namespace Prism.Services.Dialogs +{ + /// + /// Contains from the dialog + /// and the of the dialog. + /// + public interface IDialogResult + { + /// + /// The parameters from the dialog. + /// + IDialogParameters Parameters { get; } + + /// + /// The result of the dialog. + /// + ButtonResult Result { get; } + } +} diff --git a/29WxOrderWpf/Common/Dialogs/IDialogWindow.cs b/29WxOrderWpf/Common/Dialogs/IDialogWindow.cs new file mode 100644 index 0000000..69905d6 --- /dev/null +++ b/29WxOrderWpf/Common/Dialogs/IDialogWindow.cs @@ -0,0 +1,71 @@ +using System; +using System.ComponentModel; +using System.Windows; + +namespace Prism.Services.Dialogs +{ + /// + /// Interface for a dialog hosting window. + /// + public interface IDialogWindow + { + /// + /// Dialog content. + /// + object Content { get; set; } + + /// + /// Close the window. + /// + void Close(); + + /// + /// The window's owner. + /// + Window Owner { get; set; } + + /// + /// Show a non-modal dialog. + /// + void Show(); + + /// + /// Show a modal dialog. + /// + /// + bool? ShowDialog(); + + /// + /// The data context of the window. + /// + /// + /// The data context must implement . + /// + object DataContext { get; set; } + + /// + /// Called when the window is loaded. + /// + event RoutedEventHandler Loaded; + + /// + /// Called when the window is closed. + /// + event EventHandler Closed; + + /// + /// Called when the window is closing. + /// + event CancelEventHandler Closing; + + /// + /// The result of the dialog. + /// + IDialogResult Result { get; set; } + + /// + /// The window style. + /// + Style Style { get; set; } + } +} diff --git a/29WxOrderWpf/Common/Dialogs/IParameters.cs b/29WxOrderWpf/Common/Dialogs/IParameters.cs new file mode 100644 index 0000000..2202587 --- /dev/null +++ b/29WxOrderWpf/Common/Dialogs/IParameters.cs @@ -0,0 +1,71 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Prism.Common +{ + /// + /// Defines a contract for specifying values associated with a unique key. + /// + public interface IParameters : IEnumerable> + { + /// + /// Adds the specified key and value to the parameter collection. + /// + /// The key of the parameter to add. + /// The value of the parameter to add. + void Add(string key, object value); + + /// + /// Determines whether the contains the specified . + /// + /// The key to search the parameters for existence. + /// true if the contains a parameter with the specified key; otherwise, false. + bool ContainsKey(string key); + + /// + /// Gets the number of parameters contained in the . + /// + int Count { get; } + + /// + /// Gets a collection containing the keys in the . + /// + IEnumerable Keys { get; } + + /// + /// Gets the parameter associated with the specified . + /// + /// The type of the parameter to get. + /// The key of the parameter to find. + /// A matching value of if it exists. + T GetValue(string key); + + /// + /// Gets the parameter associated with the specified . + /// + /// The type of the parameter to get. + /// The key of the parameter to find. + /// An of all the values referenced by key. + IEnumerable GetValues(string key); + + /// + /// Gets the parameter associated with the specified . + /// + /// The type of the parameter to get. + /// The key of the parameter to get. + /// + /// When this method returns, contains the parameter associated with the specified key, + /// if the key is found; otherwise, the default value for the type of the value parameter. + /// + /// true if the contains a parameter with the specified key; otherwise, false. + bool TryGetValue(string key, out T value); + + /// + /// Gets the parameter associated with the specified key (legacy). + /// + /// The key of the parameter to get. + /// A matching value if it exists. + object this[string key] { get; } + } +} diff --git a/29WxOrderWpf/Common/Dialogs/ParametersBase.cs b/29WxOrderWpf/Common/Dialogs/ParametersBase.cs new file mode 100644 index 0000000..2bbd7b2 --- /dev/null +++ b/29WxOrderWpf/Common/Dialogs/ParametersBase.cs @@ -0,0 +1,198 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Text; + +namespace Prism.Common +{ + /// + /// This is a generic parameters base class used for Dialog Parameters and Navigation Parameters. + /// + public abstract class ParametersBase : IParameters, IEnumerable> + { + private readonly List> _entries = new List>(); + + /// + /// Default constructor. + /// + protected ParametersBase() + { + } + + /// + /// Constructs a list of parameters. + /// + /// Query string to be parsed. + protected ParametersBase(string query) + { + if (!string.IsNullOrWhiteSpace(query)) + { + int num = query.Length; + for (int i = ((query.Length > 0) && (query[0] == '?')) ? 1 : 0; i < num; i++) + { + int startIndex = i; + int num4 = -1; + while (i < num) + { + char ch = query[i]; + if (ch == '=') + { + if (num4 < 0) + { + num4 = i; + } + } + else if (ch == '&') + { + break; + } + i++; + } + string key = null; + string value; + if (num4 >= 0) + { + key = query.Substring(startIndex, num4 - startIndex); + value = query.Substring(num4 + 1, (i - num4) - 1); + } + else + { + value = query.Substring(startIndex, i - startIndex); + } + + if (key != null) + Add(Uri.UnescapeDataString(key), Uri.UnescapeDataString(value)); + } + } + } + + /// + /// Searches Parameter collection and returns value if Collection contains key. + /// Otherwise returns null. + /// + /// The key for the value to be returned. + /// The value of the parameter referenced by the key; otherwise null. + public object this[string key] + { + get + { + foreach (var entry in _entries) + { + if (string.Compare(entry.Key, key, StringComparison.Ordinal) == 0) + { + return entry.Value; + } + } + + return null; + } + } + + /// + /// The count, or number, of parameters in collection. + /// + public int Count => _entries.Count; + + /// + /// Returns an IEnumerable of the Keys in the collection. + /// + public IEnumerable Keys => + _entries.Select(x => x.Key); + + /// + /// Adds the key and value to the parameters collection. + /// + /// The key to reference this value in the parameters collection. + /// The value of the parameter to store. + public void Add(string key, object value) => + _entries.Add(new KeyValuePair(key, value)); + + /// + /// Checks collection for presence of key. + /// + /// The key to check in the collection. + /// true if key exists; else returns false. + public bool ContainsKey(string key) => + _entries.ContainsKey(key); + + /// + /// Gets an enumerator for the KeyValuePairs in parameter collection. + /// + /// Enumerator. + public IEnumerator> GetEnumerator() => + _entries.GetEnumerator(); + + /// + /// Returns the value of the member referenced by key. + /// + /// The type of object to be returned. + /// The key for the value to be returned. + /// Returns a matching parameter of if one exists in the Collection. + public T GetValue(string key) => + _entries.GetValue(key); + + /// + /// Returns an IEnumerable of all parameters. + /// + /// The type for the values to be returned. + /// The key for the values to be returned. + ///Returns a IEnumerable of all the instances of type . + public IEnumerable GetValues(string key) => + _entries.GetValues(key); + + /// + /// Checks to see if the parameter collection contains the value. + /// + /// The type for the values to be returned. + /// The key for the value to be returned. + /// Value of the returned parameter if it exists. + public bool TryGetValue(string key, out T value) => + _entries.TryGetValue(key, out value); + + IEnumerator IEnumerable.GetEnumerator() => + GetEnumerator(); + + /// + /// Converts parameter collection to a parameter string. + /// + /// A string representation of the parameters. + public override string ToString() + { + var queryBuilder = new StringBuilder(); + + if (_entries.Count > 0) + { + queryBuilder.Append('?'); + var first = true; + + foreach (var kvp in _entries) + { + if (!first) + { + queryBuilder.Append('&'); + } + else + { + first = false; + } + + queryBuilder.Append(Uri.EscapeDataString(kvp.Key)); + queryBuilder.Append('='); + queryBuilder.Append(Uri.EscapeDataString(kvp.Value != null ? kvp.Value.ToString() : "")); + } + } + + return queryBuilder.ToString(); + } + + /// + /// Adds a collection of parameters to the local parameter list. + /// + /// An IEnumerable of KeyValuePairs to add to the current parameter list. + [EditorBrowsable(EditorBrowsableState.Never)] + public void FromParameters(IEnumerable> parameters) => + _entries.AddRange(parameters); + } +} diff --git a/29WxOrderWpf/Common/Dialogs/ParametersExtensions.cs b/29WxOrderWpf/Common/Dialogs/ParametersExtensions.cs new file mode 100644 index 0000000..644da68 --- /dev/null +++ b/29WxOrderWpf/Common/Dialogs/ParametersExtensions.cs @@ -0,0 +1,163 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; + +namespace Prism.Common +{ + /// + /// Extension methods for Navigation or Dialog parameters + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public static class ParametersExtensions + { + /// + /// Searches for + /// + /// The type of the parameter to return + /// A collection of parameters to search + /// The key of the parameter to find + /// A matching value of if it exists + [EditorBrowsable(EditorBrowsableState.Never)] + public static T GetValue(this IEnumerable> parameters, string key) => + (T)GetValue(parameters, key, typeof(T)); + + /// + /// Searches for value referenced by + /// + /// A collection of parameters to search + /// The key of the parameter to find + /// The type of the parameter to return + /// A matching value of if it exists + /// Unable to convert the value of Type + [EditorBrowsable(EditorBrowsableState.Never)] + public static object GetValue(this IEnumerable> parameters, string key, Type type) + { + foreach (var kvp in parameters) + { + if (string.Compare(kvp.Key, key, StringComparison.Ordinal) == 0) + { + if (TryGetValueInternal(kvp, type, out var value)) + return value; + + throw new InvalidCastException($"Unable to convert the value of Type '{kvp.Value.GetType().FullName}' to '{type.FullName}' for the key '{key}' "); + } + } + + return GetDefault(type); + } + + /// + /// Searches for value referenced by + /// + /// The type of the parameter to return + /// A collection of parameters to search + /// The key of the parameter to find + /// The value of parameter to return + /// Success if value is found; otherwise returns false + [EditorBrowsable(EditorBrowsableState.Never)] + public static bool TryGetValue(this IEnumerable> parameters, string key, out T value) + { + var type = typeof(T); + + foreach (var kvp in parameters) + { + if (string.Compare(kvp.Key, key, StringComparison.Ordinal) == 0) + { + var success = TryGetValueInternal(kvp, typeof(T), out object valueAsObject); + value = (T)valueAsObject; + return success; + } + } + + value = default; + return false; + } + + /// + /// Searches for value referenced by + /// + /// The type of the parameter to return + /// A collection of parameters to search + /// The key of the parameter to find + /// An IEnumerable{T} of all the values referenced by key + [EditorBrowsable(EditorBrowsableState.Never)] + public static IEnumerable GetValues(this IEnumerable> parameters, string key) + { + List values = new List(); + var type = typeof(T); + + foreach (var kvp in parameters) + { + if (string.Compare(kvp.Key, key, StringComparison.Ordinal) == 0) + { + TryGetValueInternal(kvp, type, out var value); + values.Add((T)value); + } + } + + return values.AsEnumerable(); + } + + private static bool TryGetValueInternal(KeyValuePair kvp, Type type, out object value) + { + value = GetDefault(type); + var success = false; + if (kvp.Value == null) + { + success = true; + } + else if (kvp.Value.GetType() == type) + { + success = true; + value = kvp.Value; + } + else if (type.IsAssignableFrom(kvp.Value.GetType())) + { + success = true; + value = kvp.Value; + } + else if (type.IsEnum) + { + var valueAsString = kvp.Value.ToString(); + if (Enum.IsDefined(type, valueAsString)) + { + success = true; + value = Enum.Parse(type, valueAsString); + } + else if (int.TryParse(valueAsString, out var numericValue)) + { + success = true; + value = Enum.ToObject(type, numericValue); + } + } + + if (!success && type.GetInterface("System.IConvertible") != null) + { + success = true; + value = Convert.ChangeType(kvp.Value, type); + } + + return success; + } + + /// + /// Checks to see if key exists in parameter collection + /// + /// IEnumerable to search + /// The key to search the for existence + /// true if key exists; false otherwise + [EditorBrowsable(EditorBrowsableState.Never)] + public static bool ContainsKey(this IEnumerable> parameters, string key) => + parameters.Any(x => string.Compare(x.Key, key, StringComparison.Ordinal) == 0); + + private static object GetDefault(Type type) + { + if (type.IsValueType) + { + return Activator.CreateInstance(type); + } + return null; + } + } +} From 064bd1f142a698e7844fe75b7e98f9a06a7a91a1 Mon Sep 17 00:00:00 2001 From: chfei Date: Mon, 12 Oct 2026 18:44:30 +0800 Subject: [PATCH 2/2] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=BC=80=E7=A5=A8=20?= =?UTF-8?q?=E8=BF=87=E7=A8=8B=E4=B8=AD=E5=87=BA=E7=8E=B0=E7=9A=84=E9=94=99?= =?UTF-8?q?=E8=AF=AF=E6=8F=90=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Ctrls/PDDInvoice/PDDInvoiceDialog.xaml.cs | 41 +++++++++++++---- .../ViewModels/PDDInvoiceViewModel.cs | 45 ++++++++++++++----- 2 files changed, 67 insertions(+), 19 deletions(-) diff --git a/29WxOrderWpf/Ctrls/PDDInvoice/PDDInvoiceDialog.xaml.cs b/29WxOrderWpf/Ctrls/PDDInvoice/PDDInvoiceDialog.xaml.cs index 3d4c862..4aa6a26 100644 --- a/29WxOrderWpf/Ctrls/PDDInvoice/PDDInvoiceDialog.xaml.cs +++ b/29WxOrderWpf/Ctrls/PDDInvoice/PDDInvoiceDialog.xaml.cs @@ -1,5 +1,7 @@ using _29WxOrderWpf.Commands; +using _29WxOrderWpf.Common; using _29WxOrderWpf.Ctrls.PDDInvoice.ViewModels; +using Prism.Services.Dialogs; using System; using System.Collections.Generic; using System.Linq; @@ -22,18 +24,25 @@ namespace _29WxOrderWpf.Ctrls.PDDInvoice; /// /// PDDInvoiceDialog.xaml 的交互逻辑 /// -public partial class PDDInvoiceDialog : UserControl +public partial class PDDInvoiceDialog : UserControl, IDialogAware { - public PDDInvoiceDialog() + public PDDInvoiceDialog(InvoiceConfig config) { InitializeComponent(); DataContext = this; - Config = NaiBa.Util.Helper.ConfigHelper.LoadConfig(ConfigPath); + Config = new InvoiceConfig(); + Config.Assign(config); } + public string Title { get; set; } + public event Action RequestClose; private void PDDInvoiceDialog_Loaded(object sender, RoutedEventArgs e) { - + + } + public void OnDialogOpened(IDialogParameters parameters) + { + Title = "设置"; } private void ViewModel_RequestClose() @@ -44,21 +53,35 @@ public partial class PDDInvoiceDialog : UserControl } - private const string ConfigPath = "./invoice.config"; public InvoiceConfig Config { get; } - + public ICommand ConfirmCommand => new DelegateCommand(Confirm); private void Confirm() { - NaiBa.Util.Helper.ConfigHelper.SaveConfig(ConfigPath, Config); - ViewModel_RequestClose(); + RequestClose?.Invoke(new DialogResult(ButtonResult.OK, new DialogParameters + { + { "config",Config} + })); } public ICommand CancelCommand => new DelegateCommand(Cancel); + private void Cancel() { - ViewModel_RequestClose(); + RequestClose?.Invoke(new DialogResult(ButtonResult.Cancel)); } + + public bool CanCloseDialog() + { + return true; + } + + public void OnDialogClosed() + { + + } + + } diff --git a/29WxOrderWpf/Ctrls/PDDInvoice/ViewModels/PDDInvoiceViewModel.cs b/29WxOrderWpf/Ctrls/PDDInvoice/ViewModels/PDDInvoiceViewModel.cs index 42550a5..003e427 100644 --- a/29WxOrderWpf/Ctrls/PDDInvoice/ViewModels/PDDInvoiceViewModel.cs +++ b/29WxOrderWpf/Ctrls/PDDInvoice/ViewModels/PDDInvoiceViewModel.cs @@ -15,6 +15,7 @@ using MAX.Core.Helpers; using NaiBa.Util.Extension; using Newtonsoft.Json; using NPOI.SS.Formula.Functions; +using Prism.Services.Dialogs; using System; using System.Collections.Generic; using System.Collections.ObjectModel; @@ -475,13 +476,17 @@ public partial class PDDInvoiceViewModel : BindableBaseEx private void ShowSettingDialog() { - var view = new PDDInvoiceDialog(); - new DialogWindow + var view = new PDDInvoiceDialog(Config); + DialogService.ShowDialog(view, null, result => { - Title = "设置", - Content = view, - }.ShowDialog(); - Config = view.Config; + if (result.Result == ButtonResult.OK) + { + Config.Assign(view.Config); + NaiBa.Util.Helper.ConfigHelper.SaveConfig(ConfigPath, Config); + } + + }); + } public event EventHandler BatchInvoiceChanged; @@ -506,7 +511,7 @@ public partial class PDDInvoiceViewModel : BindableBaseEx BottomMsg = "已取消批量开票"; return; } - + if (AmountTotal >= Config.MaxAmount) { return; @@ -537,6 +542,11 @@ public partial class PDDInvoiceViewModel : BindableBaseEx order.IsSelected = false; success++; AmountTotal += order.order_amount / 100m; + if (Config.IsSaveData) + { + var temp = OrderInvoiceInfoList?.FirstOrDefault(a => a.order_sn == order.order_sn); + if (temp != null) temp.IsInvoiced = true; + } } else { @@ -547,6 +557,12 @@ public partial class PDDInvoiceViewModel : BindableBaseEx BottomRMsg = $"批量开票状态:成功 {success} 个,失败 {fail} 个。总金额:{AmountTotal.ToString("N2")}"; StatisticsInvoiceAmount(); await Task.Delay(1000); + + if (Config.IsSaveData) + { + SaveOrderInvoiceInfo(); + } + } } catch (Exception ex) @@ -716,9 +732,10 @@ public partial class PDDInvoiceViewModel : BindableBaseEx } } StatisticsInvoiceAmount(); - - - SaveOrderInvoiceInfo(); + if (Config.IsSaveData) + { + SaveOrderInvoiceInfo(); + } } #endregion @@ -897,4 +914,12 @@ public class InvoiceConfig public string TaxNo { get; set; } public decimal MaxAmount { get; set; } public bool IsSaveData { get; set; } + + public void Assign(InvoiceConfig config) + { + Title = config.Title; + TaxNo = config.TaxNo; + MaxAmount = config.MaxAmount; + IsSaveData = config.IsSaveData; + } } \ No newline at end of file