【问题标题】:C# - Outlook VSTO - Getting AdvancedSearchComplete to triggerC# - Outlook VSTO - 让 AdvancedSearchComplete 触发
【发布时间】:2019-03-15 16:16:41
【问题描述】:

我正在将我创建的旧 Outlook VBA 宏转换为 C# VSTO 加载项。此工具用于将电子邮件批量归档到各种公共文件夹和本地 .pst 文件,并且需要能够根据用户的搜索条件查找电子邮件。我有一段时间让AdvancedSearchComplete 事件在 VBA 中触发,但最终让它工作。当然,我现在在 C# VSTO 插件中也遇到了同样的问题。

要使用该工具,用户将在用户表单上输入他们的条件,然后单击 Find Emails 按钮执行搜索,结果填充数据网格视图。

public partial class Email_Archiver : Form
{

    public Email_Archiver()
    {
        InitializeComponent();

        //Add event handlers
        Globals.ThisAddIn.Application.AdvancedSearchComplete += new Microsoft.Office.Interop.Outlook.ApplicationEvents_11_AdvancedSearchCompleteEventHandler(Application_AdvancedSearchComplete);
    }

    public void Application_AdvancedSearchComplete(Microsoft.Office.Interop.Outlook.Search SearchObject)
    { //Handles AdvancedSearchComplete event

        if (SearchObject.Tag == "Archiver Search")
        {
            OutlookFunctions.SearchComplete = true;
            MessageBox.Show(this, "Search Complete!","Email Search Error",MessageBoxButtons.OK);
        }

    }

    private void Find_Button_Click(object sender, EventArgs e)
    {

        //Set datagridview datasource
        EmailList.DataSource = FindEmails();
        EmailList.Columns["EntryID"].Visible = false;

    }

    public DataTable FindEmails()
    {
        var dt = new DataTable();

        //Format DataTable
        dt.Columns.Add("EntryID", typeof(string));
        dt.Columns.Add("Project No.", typeof(int));
        dt.Columns.Add("Subject", typeof(string));
        dt.Columns.Add("Sender", typeof(string));
        dt.Columns.Add("Recipient", typeof(string));
        dt.Columns.Add("Time Sent", typeof(DateTime));
        dt.Columns.Add("Size", typeof(decimal));

        //Do stuff to get "searchFolders" and "searchCriteria" from form
        //...

        dt = OutlookFunctions.RunAdvancedSearch(searchFolders, searchCriteria);

        return dt;
    }
}


class OutlookFunctions
{

    public static bool SearchComplete;

    public static DataTable RunAdvancedSearch(string[] searchFolders, string[] searchCriteria)
    {

        //Get Outlook namespace
        var oApp = Globals.ThisAddIn.Application;
        var oNS = oApp.GetNamespace("mapi");
        Microsoft.Office.Interop.Outlook.Search advSearch = null;

        //Do other stuff to properly set up the scope and filter
        //...

        //Perform search
        SearchComplete = false;
        try
        {
            advSearch = oApp.AdvancedSearch(scope, filter, false, "Archiver Search");
        }
        catch (System.Exception ex)
        {
            MessageBox.Show("An error has occurred during the search for emails. \n \n"
                    + ex.Message);
            return null;
        }

        Stopwatch timer = new Stopwatch();
        timer.Start();

        while (!SearchComplete && timer.Elapsed.TotalSeconds < 10)
        {
            //Do nothing
        }

        if (!SearchComplete)
        {
            advSearch.Stop();
        }

        if (advSearch != null)
        {
            var resultTable = new DataTable();

            //Send results to resultTable

            return resultTable;
        }

        return null;

    }

}

搜索有效,我得到了正确的结果,但我必须添加计时器才能让事情继续进行,否则代码永远不会完成,因为AdvancedSearchComplete 没有被触发。我仍然会收到我正在寻找的所有电子邮件,并且只在 Outlook 资源管理器中进行基本相同的搜索,我会在几分之一秒内获得相同的结果。

在计时器结束搜索并且 datagridview 充满结果后,AdvancedSearchComplete 触发,我得到“搜索完成!”消息。

我在这里遗漏了什么阻止事件触发以结束搜索(及时)?

【问题讨论】:

  • 我会使用任务窗格代替用户表单。我还会在按钮单击中使用BackgroundWorker。然后您可以使用DoWorkProgressChangedRunWorkerCompleted 事件。
  • 是的,您可以使用 aduguid 提到的后台工作 (docs.microsoft.com/en-us/dotnet/api/…)。发布一些示例代码作为答案。
  • 我喜欢将其作为任务窗格的想法,所以感谢@aduguid 的建议!我也会更多地研究 BackgroundWorker,但我的理解是 AdvancedSearch 本质上已经是它自己的 BackgroundWorker。我的代码或我运行搜索的方式似乎存在错误,导致它无法按预期工作。
  • 在沮丧地玩了一会儿之后,似乎如果在调用 AdvancedSearch 方法后有任何代码要执行,那么 AdvancedSearchComplete 将无法正确触发。我仍在对此进行测试,但我认为这意味着我将不得不重新排列所有内容,以便在 AdvancedSearchComplete 方法中执行其余代码。

标签: c# outlook vsto outlook-addin add-in


【解决方案1】:

使用后台工作可以参考以下代码:

BackgroundWorker bw = new BackgroundWorker();
    private void button1_Click(object sender, EventArgs e)
    {
        bw.DoWork += new DoWorkEventHandler(bw_DoWork);
        bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
        if (bw.IsBusy != true)
        {
            bw.RunWorkerAsync();
        }
    }
    private void bw_DoWork(object sender, DoWorkEventArgs e)
    {
        //
        // Boring.... Do your long work
        //
        System.Threading.Thread.Sleep(20000);
    }
    private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        if (this.InvokeRequired)
        {
            //Hide your form here
            this.Invoke(new MethodInvoker(delegate { this.Close(); }));
        }
    }

【讨论】:

    【解决方案2】:

    看起来,在 AdvancedSearch 方法启动之后的任何代码基本上都会结束搜索,而不会触发 AdvancedSearchComplete 或 AdvancedSearchStopped 事件。

    相反,我现在在 ThisAddIn 类中有以下内容:

    private void ThisAddIn_Startup(object sender, System.EventArgs e)
    {
        //Create task pane object
        archiverTaskPane1 = new ArchiverTaskPane();
        customTaskPane = this.CustomTaskPanes.Add(archiverTaskPane1, "Title");
    
        //Add event handler for opening task pane
        customTaskPane.VisibleChanged += new EventHandler(customTaskPane_VisibleChanged);
    
        //Add event handler for Outlook's AdvancedSearch
        Globals.ThisAddIn.Application.AdvancedSearchComplete += new Outlook.ApplicationEvents_11_AdvancedSearchCompleteEventHandler(Application_AdvancedSearchComplete);
    }
    
    public void Application_AdvancedSearchComplete(Microsoft.Office.Interop.Outlook.Search SearchObject)
    {
        DataTable dt = new DataTable();
        OutlookFunctions oFunctions = new OutlookFunctions();
        dt = oFunctions.BuildResults(SearchObject.Results);
        this.archiverTaskPane1.DataGridFiller(dt);
    }
    

    在 ArchiverTaskPane 类中(以前的 Email_Archiver 表单 - 我真的很喜欢任务窗格的想法)

    private void Find_Button_Click(object sender, EventArgs e)
    {
        FindEmails();
    }
    
    public void FindEmails()
    {
        DataTable dt = new DataTable();
    
        //Add columns to DataTable
    
        //Do stuff to get "searchFolders" and "searchCriteria" from form
        //...
    
        //Create OutlookFunctions instance
        OutlookFunctions oFunctions = new OutlookFunctions();
        oFunctions.RunAdvancedSearch(searchFolders, searchCriteria);
    }
    
    public void DataGridFiller(DataTable results)
    {
        EmailList.DataSource = results;
    }
    

    在 OutlookFunctions 类中:

    public static DataTable RunAdvancedSearch(string[] searchFolders, string[] searchCriteria)
    {
        //Get Outlook namespace
        var oApp = Globals.ThisAddIn.Application;
        var oNS = oApp.GetNamespace("mapi");
        Microsoft.Office.Interop.Outlook.Search advSearch = null;
    
        //Do other stuff to properly set up the scope and filter
        //...
    
        //Perform search
        SearchComplete = false;
        try
        {
            advSearch = oApp.AdvancedSearch(scope, filter, false, "Archiver Search");
        }
        catch (System.Exception ex)
        {
            MessageBox.Show("An error has occurred during the search for emails. \n \n"
                    + ex.Message);
        }
    }
    
    public DataTable BuildResults(Results searchResults)
    {
        DataTable resultTable = new DataTable();
    
        //Do stuff to build DataTable from search results
        //...
    
        return resultTable;
    }
    

    【讨论】:

      猜你喜欢
      • 2019-02-12
      • 1970-01-01
      • 1970-01-01
      • 2017-11-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多