Диалог хода выполнения зависает в надстройке Outlook с помощью DoEvents

Фон:

Я использую простой диалог прогресса в надстройке Outlook, чтобы показать прогресс при выполнении длительных операций. Поскольку я не могу запустить код, использующий объекты Outlook, в отдельном потоке, я не могу реализовать более традиционный фоновый рабочий процесс. Моя надстройка работала нормально до Outlook 2013, где в некоторых случаях зависал мой диалог прогресса. Когда я запускаю надстройку в отладчике VS и вызываю зависание, а затем делаю перерыв, кажется, что он застрял в строке DoEvents(), которая пытается принудительно обновить индикатор выполнения.

Мой вопрос:

Может кто-нибудь предложить лучшую систему, чтобы показать прогресс с ограничением выше (долго работающий код должен выполняться в основном потоке Outlook). Есть ли лучший способ сделать диалог прогресса отзывчивым без использования DoEvents()?

Следующий простой код демонстрирует, как я делаю это сейчас. В коде надстройки, который выполняет длинные операции над объектами Outlook:

private void longRunningProcess()
{
    int max = 100;

    DlgStatus dlgstatus = new DlgStatus();
    dlgstatus.ProgressMax = max;
    dlgstatus.Show();

    for (int i = 0; i < max; i++)
    {
        //Execute long running code that MUST best run in the main (Outlook's) thread of execution...
        System.Threading.Thread.Sleep(1000); //for simulation purposes

        if (dlgstatus.Cancelled) break;
        dlgstatus.SetProgress("Processing item: " + i.ToString(), i);
    }
}

Вот код для простого диалогового окна прогресса:

public partial class DlgStatus : Form
{
    private bool _cancelled;

    public DlgStatus()
    {
        InitializeComponent();
    }

    public int ProgressMax
    {
        set 
        {
            progress.Maximum = value;
            Application.DoEvents();
        }
    }

    public bool Cancelled
    {
        get { return _cancelled; }
    }

    public void SetProgress(string status, int val)
    {
        lblStatus.Text = status;
        progress.Value = val;
        Application.DoEvents();  //Seems to hang here
    }

    private void btnCancel_Click(object sender, EventArgs e)
    {
        _cancelled = true;
        Application.DoEvents();
        this.Visible = false;
    }
}

1 ответ

Я смог сделать это, выполнив следующее. Пользовательская форма имеет индикатор выполнения со стилем Marquee.

Я получил общий метод от http://social.msdn.microsoft.com/Forums/en/vsto/thread/59993421-cbb5-4b7b-b6ff-8a28f74a1fe5 но обнаружил, что мне не нужно использовать все пользовательские дескрипторы окон.

private void btn_syncContacts_Click(object sender, RibbonControlEventArgs e)
{
     Thread t = new Thread(SplashScreenProc);
     t.Start();

     //long running code
     this.SyncContacts();

     syncingSplash.Invoke(new Action(this.syncingSplash.Close), null);
}

private SyncingContactsForm syncingSplash = new SyncingContactsForm();

internal void SplashScreenProc(object param)
{
    this.syncingSplash.ShowDialog();
}

Важно отметить, что форма не работает с объектной моделью Outlook. Microsoft не рекомендует использовать объектную модель в отдельных потоках.

Другие вопросы по тегам