none
window.Show( ) WPF window from VSTO addin RRS feed

  • Question

  • I would like to run a WPF Window using the .Show( ) method ( not ShowDialog( ) ) from a VSTO addin.  When the method runs both the Window and the Excel worksheet are working.  But a ContextMenu in the WPF Window does not stay popped up as expected. And I do not expect to get very far in terms of concurrency issues. 

    Is this doable in any way? 

    My user has a large spreadsheet. >10,000 rows.  I want to have a WPF window off to the side that the user can use to find rows in the spreadsheet and then position to the found row.

    thanks,

    Wednesday, November 23, 2016 3:55 PM

Answers

  • Hi Steve,

    Thanks for your detailed information. I made a test with your code and I could reproduce your issue.

    For a workaround, I would suggest you try to show context menu in ListBox_PreviewMouseRightButtonDown.

    Definatin for listbox
            <ListBox Grid.Row="0" 
                       FontFamily="Lucida console" FontSize="14"
                       PreviewMouseRightButtonDown="ListBox_PreviewMouseRightButtonDown"                  
                             ItemsSource="{Binding SearchList}">
                <ListBox.ContextMenu>
                    <ContextMenu>
                        <MenuItem Header="Search Search Search Search Search Search Search Search Search Search Search" Click="MenuItem_Click"/>
                    </ContextMenu>
                </ListBox.ContextMenu>
            </ListBox>
    Method for ListBox_PreviewMouseRightButtonDown
            private void ListBox_PreviewMouseRightButtonDown(object sender, MouseButtonEventArgs e)
            {
                ListBox lb = sender as ListBox;
                ContextMenu cm = lb.ContextMenu;
                cm.PlacementTarget = lb;
                cm.IsOpen = true;           
            }

    Note for this way, I am afraid you need to select the listboxItem first, ListBox_PreviewMouseRightButtonDown would not select the right click item.

    Best Regards,

    Edward


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    • Marked as answer by Steve Richter Monday, November 28, 2016 9:19 PM
    Monday, November 28, 2016 4:48 AM

All replies

  • Hi Steve,

    >> But a ContextMenu in the WPF Window does not stay popped up as expected.

    What do you mean by ContextMenu? Is it a ContextMenu in your WPF control? Did you show WPF control in VSTO add in? How did it behavior and where did it not work?

    Do you mean you create a WPF user Control, show it in VSTO Add in task pane, and the ContextMenu for WPF control did not work? Could you share us a simple demo which could reproduce your issue?

    Best Regards,

    Edward


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Thursday, November 24, 2016 6:26 AM
  • Hi Edward,

    here is a sample addin.  Consists of the ThisAddin.cs file. a UI Ribbon1.cs file. Then a WPF window named SearchWindow.

    the addin creates a WPF window. The window displays the contents of column 3 in the spreadsheet in a ListBox. You double click an item in the listbox and the code finds the clicked content in the spreadsheet.  Or you can right click the item in the ListBox, get a ContextMenu and click the "Search" menu item. That option does the search also.

    the problem is that when the search window is started using .Show the context menu does not stay visible on the screen. Only when ShowDialog is used. 

    The addin has a checkbox on the ribbon that controls whether Show or ShowDialog is used to Show the search window.

    to use the addin you open a blank worksheet. On the addin ribbon click the "create rows" button to place some text in column 3 of the sheet. Then click "search window" to launch the search window.

    thanks,

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Xml.Linq;
    using Excel = Microsoft.Office.Interop.Excel;
    using Office = Microsoft.Office.Core;
    using Microsoft.Office.Tools.Excel;
    using System.Windows.Threading;
    
    namespace ExcelAddIn1
    {
      public partial class ThisAddIn
      {
        public Ribbon1 Ribbon1 { get; set; }
    
        private void ThisAddIn_Startup(object sender, System.EventArgs e)
        {
        }
    
        private void ThisAddIn_Shutdown(object sender, System.EventArgs e)
        {
          Dispatcher.CurrentDispatcher.InvokeShutdown();
        }
    
        #region VSTO generated code
    
        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InternalStartup()
        {
          this.Startup += new System.EventHandler(ThisAddIn_Startup);
          this.Shutdown += new System.EventHandler(ThisAddIn_Shutdown);
        }
    
        #endregion
      }
    }
    
    --------------------------------------------
    
    namespace ExcelAddIn1
    {
      partial class Ribbon1 : Microsoft.Office.Tools.Ribbon.RibbonBase
      {
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;
    
        public Ribbon1()
            : base(Globals.Factory.GetRibbonFactory())
        {
          InitializeComponent();
        }
    
        /// <summary> 
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
          if (disposing && (components != null))
          {
            components.Dispose();
          }
          base.Dispose(disposing);
        }
    
        #region Component Designer generated code
    
        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
          this.tab1 = this.Factory.CreateRibbonTab();
          this.group1 = this.Factory.CreateRibbonGroup();
          this.butCreateRows = this.Factory.CreateRibbonButton();
          this.butSearchWindow = this.Factory.CreateRibbonButton();
          this.checkBox1 = this.Factory.CreateRibbonCheckBox();
          this.tab1.SuspendLayout();
          this.group1.SuspendLayout();
          this.SuspendLayout();
          // 
          // tab1
          // 
          this.tab1.ControlId.ControlIdType = Microsoft.Office.Tools.Ribbon.RibbonControlIdType.Office;
          this.tab1.Groups.Add(this.group1);
          this.tab1.Label = "TabAddIns";
          this.tab1.Name = "tab1";
          // 
          // group1
          // 
          this.group1.Items.Add(this.butCreateRows);
          this.group1.Items.Add(this.checkBox1);
          this.group1.Items.Add(this.butSearchWindow);
          this.group1.Label = "ContextMenuTester";
          this.group1.Name = "group1";
          // 
          // butCreateRows
          // 
          this.butCreateRows.Label = "create rows";
          this.butCreateRows.Name = "butCreateRows";
          this.butCreateRows.Click += new Microsoft.Office.Tools.Ribbon.RibbonControlEventHandler(this.butCreateRows_Click);
          // 
          // butSearchWindow
          // 
          this.butSearchWindow.Label = "Search Window";
          this.butSearchWindow.Name = "butSearchWindow";
          this.butSearchWindow.Click += new Microsoft.Office.Tools.Ribbon.RibbonControlEventHandler(this.butSearchWindow_Click);
          // 
          // checkBox1
          // 
          this.checkBox1.Label = "Search window as dialog";
          this.checkBox1.Name = "checkBox1";
          // 
          // Ribbon1
          // 
          this.Name = "Ribbon1";
          this.RibbonType = "Microsoft.Excel.Workbook";
          this.Tabs.Add(this.tab1);
          this.Load += new Microsoft.Office.Tools.Ribbon.RibbonUIEventHandler(this.Ribbon1_Load);
          this.tab1.ResumeLayout(false);
          this.tab1.PerformLayout();
          this.group1.ResumeLayout(false);
          this.group1.PerformLayout();
          this.ResumeLayout(false);
    
        }
    
        #endregion
    
        internal Microsoft.Office.Tools.Ribbon.RibbonTab tab1;
        internal Microsoft.Office.Tools.Ribbon.RibbonGroup group1;
        internal Microsoft.Office.Tools.Ribbon.RibbonButton butCreateRows;
        internal Microsoft.Office.Tools.Ribbon.RibbonButton butSearchWindow;
        internal Microsoft.Office.Tools.Ribbon.RibbonCheckBox checkBox1;
      }
    
      partial class ThisRibbonCollection
      {
        internal Ribbon1 Ribbon1
        {
          get { return this.GetRibbon<Ribbon1>(); }
        }
      }
    }
    
    ------------------------------------------------
    
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using Microsoft.Office.Tools.Ribbon;
    using Excel = Microsoft.Office.Interop.Excel;
    
    namespace ExcelAddIn1
    {
      public partial class Ribbon1
      {
        private void Ribbon1_Load(object sender, RibbonUIEventArgs e)
        {
          Globals.ThisAddIn.Ribbon1 = this;
        }
    
        private void butCreateRows_Click(object sender, RibbonControlEventArgs e)
        {
          var sheet = Globals.ThisAddIn.Application.ActiveSheet as Excel.Worksheet;
          for( int rownum = 1; rownum < 10; ++rownum)
          {
            var r1 = sheet.Cells[rownum, 3] as Excel.Range;
            r1.Value = "test value " + rownum.ToString();
          }
        }
    
        private void butSearchWindow_Click(object sender, RibbonControlEventArgs e)
        {
          var sheet = Globals.ThisAddIn.Application.ActiveSheet as Excel.Worksheet;
    
          // copy column 3 to array.
          var searchArray = new List<string>();
          for (int rownum = 1; rownum < 10; ++rownum)
          {
            var r1 = sheet.Cells[rownum, 3] as Excel.Range;
            var s1 = (string)r1.Text;
            searchArray.Add(s1);
          }
    
          // popup the search window. pass in search column contents.
          var searchWindow = new SearchWindow(sheet, searchArray);
          if (checkBox1.Checked == true)
            searchWindow.ShowDialog();
          else
            searchWindow.Show();
        }
      }
    }
    
    ----------------------------------------
    
    <Window x:Class="ExcelAddIn1.SearchWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:local="clr-namespace:ExcelAddIn1"
            mc:Ignorable="d"
            Title="SearchWindow" Height="350" Width="525">
        <Grid x:Name="grdMain">
          <Grid.RowDefinitions>
            <RowDefinition Height="*"></RowDefinition>
            <RowDefinition Height="auto"></RowDefinition>
          </Grid.RowDefinitions>
    
              <ListBox Grid.Row="0" 
                       FontFamily="Lucida console" FontSize="14"
                       MouseDoubleClick="ListBox_MouseDoubleClick"
                             ItemsSource="{Binding SearchList}">
          <ListBox.ContextMenu>
            <ContextMenu>
              <MenuItem Header="Search" Click="MenuItem_Click"/>
    
            </ContextMenu>
          </ListBox.ContextMenu>
        </ListBox>
    
      </Grid>
    </Window>
    
    -----------------------------------------------
    
    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using System.Windows.Navigation;
    using System.Windows.Shapes;
    using Excel = Microsoft.Office.Interop.Excel;
    
    namespace ExcelAddIn1
    {
      /// <summary>
      /// Interaction logic for SearchWindow.xaml
      /// </summary>
      public partial class SearchWindow : Window
      {
        public ObservableCollection<string> SearchList
        {
          get { return (ObservableCollection<string>)GetValue(SearchListProperty); }
          set { SetValue(SearchListProperty, value); }
        }
    
        public static readonly DependencyProperty SearchListProperty =
        DependencyProperty.Register("SearchList", typeof(ObservableCollection<string>),
        typeof(SearchWindow), new PropertyMetadata(null));
    
        public Excel.Worksheet ActiveSheet
        { get; set; }
    
        public SearchWindow( Excel.Worksheet activeSheet, List<string> searchList)
        {
          this.ActiveSheet = activeSheet;
          this.SearchList = new ObservableCollection<string>();
          foreach (var s1 in searchList)
            this.SearchList.Add(s1);
    
          InitializeComponent();
          grdMain.DataContext = this;
    
          this.Closed += MainWindow_Closed;
          this.Loaded += MainWindow_Loaded;
        }
    
        private void MainWindow_Loaded(object sender, RoutedEventArgs e)
        {
        }
    
        private void MainWindow_Closed(object sender, EventArgs e)
        {
        }
    
        public static Excel.Range GetColumnRange(
          Excel.Worksheet ws, int ColumnNumber)
        {
          int toRownum = 10;
          var r1 = (Excel.Range)ws.Cells[1, ColumnNumber];
          var r2 = (Excel.Range)ws.Cells[toRownum, ColumnNumber];
          var r3 = (Excel.Range)ws.Range[r1, r2];
          return r3;
        }
    
        private void MenuItem_Click(object sender, RoutedEventArgs e)
        {
          var lb = FindDataGridAncestor(sender as DependencyObject);
          if (lb != null)
          {
            var s1 = lb.SelectedItem as string;
            if (s1 != null)
            {
              var r1 = GetColumnRange(this.ActiveSheet, 3);
              var r2 = r1.Find(s1);
              if ( r2 != null)
              {
                r2.Select();
              }
            }
          }
        }
    
        private static ListBox FindDataGridAncestor(DependencyObject element)
        {
          while (element != null)
          {
            var cm = element as ContextMenu;
            if (cm != null)
            {
              var lb = cm.PlacementTarget as ListBox;
              if (lb != null)
                return lb;
            }
            element = LogicalTreeHelper.GetParent(element);
          }
          return null;
        }
    
        private void ListBox_MouseDoubleClick(object sender, MouseButtonEventArgs e)
        {
          var lb = sender as ListBox;
          if (lb != null)
          {
            var s1 = lb.SelectedItem as string;
            if (s1 != null)
            {
              var r1 = GetColumnRange(this.ActiveSheet, 3);
              var r2 = r1.Find(s1);
              if (r2 != null)
              {
                r2.Select();
              }
            }
          }
        }
      }
    }
    
    

    Friday, November 25, 2016 9:58 PM
  • Hi Steve,

    Thanks for your detailed information. I made a test with your code and I could reproduce your issue.

    For a workaround, I would suggest you try to show context menu in ListBox_PreviewMouseRightButtonDown.

    Definatin for listbox
            <ListBox Grid.Row="0" 
                       FontFamily="Lucida console" FontSize="14"
                       PreviewMouseRightButtonDown="ListBox_PreviewMouseRightButtonDown"                  
                             ItemsSource="{Binding SearchList}">
                <ListBox.ContextMenu>
                    <ContextMenu>
                        <MenuItem Header="Search Search Search Search Search Search Search Search Search Search Search" Click="MenuItem_Click"/>
                    </ContextMenu>
                </ListBox.ContextMenu>
            </ListBox>
    Method for ListBox_PreviewMouseRightButtonDown
            private void ListBox_PreviewMouseRightButtonDown(object sender, MouseButtonEventArgs e)
            {
                ListBox lb = sender as ListBox;
                ContextMenu cm = lb.ContextMenu;
                cm.PlacementTarget = lb;
                cm.IsOpen = true;           
            }

    Note for this way, I am afraid you need to select the listboxItem first, ListBox_PreviewMouseRightButtonDown would not select the right click item.

    Best Regards,

    Edward


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    • Marked as answer by Steve Richter Monday, November 28, 2016 9:19 PM
    Monday, November 28, 2016 4:48 AM