WPF TabControl / File open needs to locate child WindowsFormsHost - wpf

I'm trying to write a text editor in WPF and I have a problem trying to locate the correct instance of an editor within a TabControl in response to a File -> Open action.
Tab items are added programatically and contain a WindowsFormsHost instance which in turn allows each tab to display an editor provided by the ScintillaNet WinForms component.
When a tab is selected and a user selects File -> Open, I need to locate the correct WindowsFormsHost instance based on the tab selection so I can load the file into the correct Scintilla instance.
Previously, I'd done this in WinForms simply by doing:
tabControl.TabPages[tabControl.SelectedIndex].Controls.Find("Scintilla")
How does this work in WPF?

To follow up regarding the solution I've gone with for now: I've decided to subclass the TabItem class and hold an additional property that references the WinForms ScintillaNet control:
public class CustomTabItem : TabItem
{
public Scintilla EditorControl
{
get; set;
}
}
And when I add new tabs, I just make sure that EditorControl is set to the new instance of Scintilla that is created too:
var editor = ScintillaFactory.Create();
var tab = new CustomTabItem()
{
Header = "Untitled",
Content = new WindowsFormsHost() { Name = "WinformsHost", Child = editor },
EditorControl = editor
};
tabControl.Items.Add(tab);
tab.Focus();
Now when an event is raised, I can query the selected tab and as cast to CustomTabItem in order to access the reference to the respective editor:
var editor = (tabControl.Items[tabControl.SelectedIndex] as CustomTabItem).EditorControl
editor.Text = "text here";
Hope that helps someone else.

Related

Winforms OpenFileDialog problems

I would like to create a file dialog form that works like the one in MS Word. Specifically, you can select an existing file, create a new one, or delete a file, all within the file dialogue window. OpenFileDialog is a read-only deal. You can't create a new file with that control. SaveFileDialog can't be used to select an existing file. Is there a control that will do all of the above?
To create your custom dialog you should follow these steps:
Create a new form, call it MyFolderDialog
In the new form add the controls you need. For example, in order to let the user browse the file system, you can add a treeView and populate it using the classes System.IO.FileInfo and System.IO.FolderInfo.
Create a property in your form that reflects the user choice, something like public string SelectedFolder
Add a "Confirm" button and a "Cancel" button to your form
In the cancel button click event handler add the code this.DialogResult = DialogResult.Cancel;
In the confirm button click event handler add the code this.DialogResult = DialogResult.Ok;
Call your custom dialog like that
private string PickAFolder()
{
string selectedFolder = string.Empty;
using(var f = new MyFolderDialog())
{
if(f.ShowDialog() == DialogResult.Ok)
{
selectedFolder = f.SelectedFolder;
}
}
return selectedFolder;
}
Note that when the form is shown using ShowDialog method, the form won't dispose when it will be closed, so you can still read his properties after you confirmed. So it a good practice dispose it manually when you don't need it anymore. An elegant way to do it is to use the using keyword.
I hope this helps.

Simple- How To select an Item from a WPF combo box using coded UI

I have worked with coded UI for web applications but for the first time I am trying to leverage Coded UI for WPF. I want to perform a click on an item from a combobox But, I am unable to achieve the same here in WPF. I tried to loop through the items inside the combo box but It did not work. Tried with Search Property - No result. Also, was trying to figure out the AutomationElement stuff but not able to get a solution. It would be great if I can get an idea of the approach that needs to be followed to achieve the requirement.
I have captured the controls and want to play around with them. No record and playback.
You can use the WpfComboBox's SelectedItem property which takes the name of the item you want to select (as mentioned in my comment in yonder answer)
var myComboBox = this.UIMap.UIMainWindowWindow.UIItemComboBox;
var items = myComboBox.Items;
myComboBox.SelectedItem = items[0].Name;
or you can simply set the SelectedIndex if you already know the index of the item you want to set
var myComboBox = this.UIMap.UIMainWindowWindow.UIItemComboBox;
var items = myComboBox.Items;
myComboBox.SelectedIndex = 0;
or you can first click the combobox to get it expanded and then get the UITestControl for the item element and perform a click on it (unfortunately you have to manually click the combobox because it seems that the ExpandWhileSearching configuration it doesn't work on it)
var myComboBox = this.UIMap.UIMainWindowWindow.UIItemComboBox;
var items = myComboBox.Items;
Mouse.Click(myComboBox);
Mouse.Click(items[0]);
or
var myComboBox = this.UIMap.UIMainWindowWindow.UIItemComboBox;
var items = myComboBox.Items;
myComboBox.Expanded = true;
Mouse.Click(items[0]);
You would create the combobox object the same way you would in Html, just using Microsoft.VisualStudio.TestTools.UITesting.WpfControls namespace. For example:
public WpfComboBox tester
{
get
{
WpfComboBox target = new WpfComboBox();
return target;
}
}
Then, you will create a UITestControlCollection object to store the .Items of the combo box.
UITestControlCollection comboBoxItems = tester.Items;
From here, you should be able to edit and set selected items ( tester.SelectedItem = comboBoxItems[0].ToString();) at will.

Centering WPF dialog spawned from VSTO Outlook Add-In

I'm working on an Outlook 2010 add-in that provides a dialog for user input. The code necessary for displaying the button in the ribbon is in its own Outlook 2010 Add-in project. That project has a reference to a WPF User Control Library that is responsible for the bulk of the work.
I use a static method in the WPF User Control Library project that is responsible for configuring Caliburn.Micro correctly and displaying the dialog. All of this works as expected except that I cannot figure out how to correctly position the dialog. I would like it to display centered over the Outlook window. I know I have access to the Microsoft.Office.Interop.Outlook.Application.ActiveWindow(), but I do not see how that helps me since I cannot translate it to a PlacementTarget as expected in the settings for Caliburn.Micro WindowManager's ShowDialog method.
WPF User Control Library
namespace WpfUserControlLibrary {
public static class Connector {
public static void ShowDialog() {
new AppBootstrapper();
var windowManager = IoC.Get<IWindowManager>();
windowManager.ShowDialog( new ShellViewModel() );
}
}
}
Outlook 2010 Add-in
WpfUserControlLibrary.Connector.ShowDialog();
I was able to track down a solution. Thanks to the help of this question, I was able to pass the appropriate parent window location and size parameters to the Connector. I checked the Caliburn.Micro source and noticed that I'm actually creating a ChildWindow--not a Popup. Therefore, I just needed to set the Top and Left values of the settings for the dialog.
WPF User Control Library
namespace WpfUserControlLibrary {
public static class Connector {
public static void ShowDialog(System.Windows.Rect parent) {
new AppBootstrapper();
var windowManager = IoC.Get<IWindowManager>();
// Popup is always 600 x 400
dynamic settings = new System.Dynamic.ExpandoObject();
settings.Left = (parent.Left + parent.Width / 2) - 300;
settings.Top = (parent.Top + parent.Height / 2) - 200;
windowManager.ShowDialog(new ShellViewModel(), settings: settings);
}
}
}
Outlook 2010 Add-in
var win = ThisAddIn.Application.ActiveWindow();
var parent = new System.Windows.Rect(win.Left, win.Top, win.Width, win.Height);
WpfUserControlLibrary.Connector.ShowDialog(parent);

how to Show MDIChild Form on Top of the MDIParent's Controls

I have a MDI-Parent Form with many ChildForms, when I want to add a control on my Parent form, Child form appears under the control, For example I want to add a groupbox and a PictureBox on MDIParent Form, but when I call the Child Form it appears Under these controls.
frmChildForm1.TopMost=true doesn't works either.
I have attached a photo for more description.
What can I do?!
but I want to have an Image as Background
That's possible, you can set the BackgroundImage property of the MDI client control. The only obstacle is that you cannot directly get a reference to that control. You have to find it back by iterating the form's Controls collection. Like this:
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
foreach (Control ctl in this.Controls) {
if (ctl is MdiClient) {
ctl.BackgroundImage = Properties.Resources.Lighthouse;
break;
}
}
}
}
Where Lighthouse was a sample image I added as a resource. Change it to use your own. Another common technique is to subscribe the Paint event for that control and draw whatever you want. A gradient is a common choice.

Replicating WPF TabControl selected TabItem design time behavior for a custom control

I'm developing a custom control which shows an inline popup window and I would like to use a similar technique as the TabControl employes so that only popup windows that are selected within the designer or more commonly by placing the cursor within the popup declaration in XAML that it is visualized right within the desiger without having to run the application or change any runtime values by hand.
I've started by duplicating the implementation of the TabControl which I have successfully mimicking everything but it is all copied from Reflector output and Stylesnooper. I've renamed all of the control parts and then replaced the default templates so that the main control uses an ItemsPresenter instead of a ContentPresenter to show the individual popup controls within a Grid panel overlayed on top of one another. So far this is working great too. The problem is that somewhere along the line I lost the ability to have the designer follow the item that is selected in the XAML editor.
Either an explanation of how the TabControl's design time behavior functionality actually works to describe the selected TabItem behavior that I described above or just some pointers on how one could achieve what I'm tryign to do would be great.
To solve a similar problem, I had to create design time support for my custom tab control. Here is a link for WPF Designer Extensibility.
Basically, I created a PrimarySelectionAdornerProvider to handle click interaction and a FeatureConnector<> / FeatureProvider pair for selection changes (including selection changes made in the xaml editor).
The feature provider / connector:
[FeatureConnector(typeof(AutoTabPageSelectionFeatureConnector))]
class AutoTabPageSelectionFeatureProvider : FeatureProvider
{
public AutoTabPageSelectionFeatureProvider()
: base()
{
// sole purpose is to register the connector
}
}
class AutoTabPageSelectionFeatureConnector : FeatureConnector<AutoTabPageSelectionFeatureProvider>
{
public AutoTabPageSelectionFeatureConnector(FeatureManager manager)
: base(manager)
{
SelectionOperations.Subscribe(this.Context, SelectionChanged);
}
private void SelectionChanged(Selection selection)
{
if (selection.PrimarySelection != null)
{
// navigate tree to find parent (custom tab page and custom tab control)
for (ModelItem item = selection.PrimarySelection; item != null; item = item.Parent)
{
// once found, select appropriate tab
}
}
}
}
Edit (more info):
This Microsoft link has a number of links to walk-throughs that should help. Here are the basic steps to get started:
Create a new project, MyAssembly.VisualStudio.Design.dll.
The library should compile to the same location as MyAssembly.dll (important).
Add references to Microsoft.Windows.Design.Extensibility and Microsoft.Windows.Design.Interaction.
Add a reference to your control library.
Create a class called Metadata
Code:
internal class Metadata : IProvideAttributeTable
{
// Accessed by the designer to register any design-time metadata.
public AttributeTable AttributeTable
{
get
{
AttributeTableBuilder builder = new AttributeTableBuilder();
// Add the adorner provider to the design-time metadata.
builder.AddCustomAttributes(
typeof(MyControl), // rename to your control's name
new FeatureAttribute(typeof(MyPrimaryAdornerProvider)), // rename to whatever you will call your PrimaryAdornerProvider
new FeatureAttribute(typeof(AutoTabPageSelectionFeatureProvider)) // rename to whatever you will call your SelectionFeatureProvider
);
return builder.CreateTable();
}
}
}
Create a class MyPrimaryAdornerProvider from PrimarySelectionAdornerProvider (rename to whatever you want). See link for good walk-through.
Create the AutoTabPageSelectionFeatureProvider and AutoTabPageSelectionFeatureConnector from the example above.

Resources