【问题标题】:IProgressDialog to start immediatelyIProgressDialog 立即启动
【发布时间】:2016-09-19 08:06:09
【问题描述】:

我正常使用IProgressDialog界面,一切正常,但进度对话框仅在几秒钟后才出现,当它确定操作确实很长时。尽管这在任何地方都没有记录,但它似乎是预期的行为,在许多情况下还不错。但是,在这个特定的应用程序中,我需要立即显示它。

我在整个万维网上找到了single reference 来确认这一点并提出解决方法。但是,可能是因为在那九年中出现了很多新的 Windows 版本,所以今天似乎行不通:

IProgressDialog dialog;
dialog.StartProgressDialog(owner, null, flags, IntPtr.Zero);
...
IntPtr DialogHWnd;
((IOleWindow)dialog).GetWindow(out DialogHWnd);
SendMessage(DialogHWnd, WM_TIMER, new IntPtr(1), IntPtr.Zero);

窗口句柄没问题,我检查了一下,没有错误,只是行为没有变化。该对话框仅在几秒钟后出现。

有没有人建议不要在 C# 中重新创建相同的对话框和功能?当然也不是不可能,但是除了用户非常熟悉之外,库存对话框还具有很好的功能,例如动画和取消行为。

【问题讨论】:

    标签: c# winapi


    【解决方案1】:

    StartProgressDialog之前或之后立即调用dialog.Timer(PDTIMER_RESUME, null)。这是一个最小的示例:

    using System;
    using System.Runtime.InteropServices;
    using System.Windows.Forms;
    
    namespace WindowsFormsApplication1 {
    
    [Flags]
    public enum IPD_Flags: uint {
        Normal = 0x00000000,
        Modal = 0x00000001,
        AutoTime = 0x00000002,
        NoTime = 0x00000004,
        NoMinimize = 0x00000008,
        NoProgressBar = 0x00000010 
    }
    
    [Flags]
    public enum IPDTIMER_Flags: uint {
        Reset = 0x00000001,
        Pause = 0x00000002,
        Resume = 0x00000003
    }
    
    [ComImport]
    [Guid("F8383852-FCD3-11d1-A6B9-006097DF5BD4")]
    internal class ProgressDialog {
    }
    
    [ComImport]
    [Guid("EBBC7C04-315E-11d2-B62F-006097DF5BD4")]
    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    internal interface IProgressDialog {
    
        [PreserveSig]
        void StartProgressDialog(IntPtr hwndParent
            , [MarshalAs(UnmanagedType.IUnknown)] object  punkEnableModless
            , uint dwFlags
            , IntPtr pvResevered);
    
        [PreserveSig]
        void StopProgressDialog();
    
        [PreserveSig]
        void SetTitle([MarshalAs(UnmanagedType.LPWStr)] string pwzTitle);
    
        [PreserveSig]
        void SetAnimation(IntPtr hInstAnimation, ushort idAnimation);
    
        [PreserveSig]
        [return: MarshalAs(UnmanagedType.Bool)]
        bool HasUserCancelled();
    
        [PreserveSig]
        void SetProgress(uint dwCompleted, uint dwTotal);
    
        [PreserveSig]
        void SetProgress64(ulong ullCompleted, ulong ullTotal );
    
        [PreserveSig]
        void SetLine(uint dwLineNum
            , [MarshalAs(UnmanagedType.LPWStr)] string pwzString
            , [MarshalAs(UnmanagedType.VariantBool)] bool fCompactPath
            , IntPtr pvResevered);
    
        [PreserveSig]
        void SetCancelMsg([MarshalAs(UnmanagedType.LPWStr)]string pwzCancelMsg, object pvResevered);
    
        [PreserveSig]
        void Timer(uint dwTimerAction, object pvResevered);
    
    }
    
    
    public partial class Form1 : Form {
        public Form1() {
            InitializeComponent();
        }
    
        private void button1_Click(object sender, EventArgs e) {
            ProgressDialog progressDialog = new ProgressDialog();
            IProgressDialog iProgressDialog = (IProgressDialog)progressDialog;
    
            iProgressDialog.Timer((uint) IPDTIMER_Flags.Resume, null);
            iProgressDialog.StartProgressDialog(this.Handle
                , null
                , (uint)(IPD_Flags.Normal | IPD_Flags.NoMinimize)
                , IntPtr.Zero);
        }
    }
    

    }

    【讨论】:

    • 这个想法非常好(我实际上尝试了Timer(),但没有使用恢复标志)。但恐怕还不完美。它适用于您的这个简单示例,但在我还需要处理进度条的实际应用程序中,现在,我要么立即开始 要么 稍后获得正确的进度条。 :-) 我一直在努力,会回来报告。谢谢。
    • 好的,找到了。重要的是,这不是一个简单的进度条。进度对话框在对SetProgress() 的调用之间为背景中的栏设置动画,以使其在指定值之间移动更平滑,而不是跳跃。结果,除了您的想法之外,我还必须像这样将每个SetProgress() 调用括起来:dialog.Timer(PDTIMER_PAUSE, null); dialog.SetProgress(...); dialog.Timer(PDTIMER_RESUME, null);
    • 虽然这行得通,但它有各种奇怪的副作用:标题和第 1 行被替换为“正在处理”,单击取消时内容被清除,可能还有其他问题我没有没注意到。
    猜你喜欢
    • 2021-01-30
    • 1970-01-01
    • 2016-06-05
    • 1970-01-01
    • 2011-08-10
    • 2012-05-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多