I want to build my own web browser, but I'm stuck on operation for adding new tab, does anyone have any idea to make it done?
The final result will should like this.
you can try this:-
if (tabControl1.SelectedTab.Text == "+")
{
AddNewTab();
}
foreach (Control item in tabControl1.SelectedTab.Controls)
{
if (item.GetType() == typeof(WebBrowser))
{
WebBrowser wb = (WebBrowser)item;
toolStripButton1.Enabled = wb.CanGoBack;
toolStripButton2.Enabled = wb.CanGoForward;
}
}
The way I'd go about it would be (using a TabControl or similar) to create a special tab with just the plus icon you want. Then handle the tab changed event, check if you've switched to the special tab, and if so, cancel the tab change, create a new tab and set that to be displayed instead.
Related
I have a list of checkbox controls
public List<CheckBox> _checkBoxes = new List<CheckBox>();
I add a certain amount during runtime using a switch case with the properties such as location and visibility.
This all works fine, but if I want the checkboxes to disappear or become checked at some point the GUI doesn't get updated, the list is updated with the new data but just not visually.
* I ended up doing this*
I created a bunch of checkboxes on the winfrom.Created a method which you can choose which ones are visible. Then created a method to fill a list of type checkbox. Then you can search the panel for control types, once you found the control, it can be manipulated. This isn't elegant and probably isn't the best way, but i am new to custom controls and winforms.
//search panel for checkboxes
foreach (Control c in panel1.Controls)
{
if (c is CustomControls.RoundedCheckBox)
{
CustomControls.RoundedCheckBox checkBox = c as CustomControls.RoundedCheckBox;
//if it is checked add to list
if(checkBox.Checked)
{
_checkBoxes.Add(checkBox);
}
}
}
If you have something like this:
_checkBoxes.Add(new CheckBox());
_checkBoxes[0].Parent = this;
then you should be able to manipulate your checkboxes from the list:
_checkBoxes[0].Checked = false;
But, the problem may occur if you do it in some kind of loop and want to see the results immediately.
In Windows there is something called message loop. Application simply works like that (pseudocode: TL;DR)
while(true)
{
message = GetFirstMessage();
if(message != null)
{
if(message.Id == CloseApplication)
break;
DispatchMessage(message);
RemoveFirstMessage();
}
}
So, application takes message from queue, then process it. A message is everything - button click, mouse move, paint... Everything.
So when a message is dispatched it looks for the control that should receive this message and then it does some work.
So, for example if you have something like that:
foreach(var ch in _checkBoxes)
{
ch.Checked = false;
DoSomeWorkThatTakesTime();
ch.Checked = true;
}
You won't see the change, because you are "trapped" in DispatchMessage. When you set Checked, you really sending a message. But this message cannot be Dispatched right now, because you are inside the foreach loop.
So the only thing you can do here is to tell your application - now, please DO READ message queue. In WinForms it's called "DoEvents", so this will do the work:
foreach(var ch in _checkBoxes)
{
ch.Checked = false;
Application.DoEvents();
DoSomeWorkThatTakesTime();
ch.Checked = true;
Application.DoEvents();
}
Thanks in advance.
Is it possible to activate a tab in another program using an IntPtr? If so, how?
SendKeys is not an option.
Perhaps what I need is a fishing lesson. I have exhausted Google and my lead developer.
I would appreciate an outright solution OR a recommendation to continue my Google efforts.
basic process is:
I drag a shortcut icon to the launcher
This opens the target application (Notepad++) and grabs IntPtr, etc.
I would like to programmatically select various items in Notepad++ such as Edit, menu items under Edit, or a doc tab.
The basic code I am running is:
the 'blob'
item 1: IntPtr of item
item 2: IntPtr of itemsChild
item 3: control text of item 1
item 4: is rectangle parameters of item 1
root contains similar info:
As others pointed out, the standard way of doing this is to use UI Automation. Notepad++ does support UI Automation (to some extent, as it's somehow automatically provided by the UI Automation Windows layers).
Here is a sample C# console app that demonstrates the following sceanrio (you need to reference UIAutomationClient.dll, UIAutomationProvider.dll and UIAutomationTypes.dll):
1) get the first running notepad++ process (you must start at least one)
2) open two files (note there may be already other opened tabs in notepad++)
3) selects all tabs in an infinite loop
class Program
{
static void Main(string[] args)
{
// this presumes notepad++ has been started somehow
Process process = Process.GetProcessesByName("notepad++").FirstOrDefault();
if (process == null)
{
Console.WriteLine("Cannot find any notepad++ process.");
return;
}
AutomateNpp(process.MainWindowHandle);
}
static void AutomateNpp(IntPtr handle)
{
// get main window handle
AutomationElement window = AutomationElement.FromHandle(handle);
// display the title
Console.WriteLine("Title: " + window.Current.Name);
// open two arbitrary files (change this!)
OpenFile(window, #"d:\my path\file1.txt");
OpenFile(window, #"d:\my path\file2.txt");
// selects all tabs in sequence for demo purposes
// note the user can interact with n++ (for example close tabs) while all this is working
while (true)
{
var tabs = GetTabsNames(window);
if (tabs.Count == 0)
{
Console.WriteLine("notepad++ process seems to have gone.");
return;
}
for (int i = 0; i < tabs.Count; i++)
{
Console.WriteLine("Selecting tab:" + tabs[i]);
SelectTab(window, tabs[i]);
Thread.Sleep(1000);
}
}
}
static IList<string> GetTabsNames(AutomationElement window)
{
List<string> list = new List<string>();
// get tab bar
var tab = window.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Tab));
if (tab != null)
{
foreach (var item in tab.FindAll(TreeScope.Children, PropertyCondition.TrueCondition).OfType<AutomationElement>())
{
list.Add(item.Current.Name);
}
}
return list;
}
static void SelectTab(AutomationElement window, string name)
{
// get tab bar
var tab = window.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Tab));
// get tab
var item = tab.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.NameProperty, name));
if (item == null)
{
Console.WriteLine("Tab item '" + name + "' has been closed.");
return;
}
// select it
((SelectionItemPattern)item.GetCurrentPattern(SelectionItemPattern.Pattern)).Select();
}
static void OpenFile(AutomationElement window, string filePath)
{
// get menu bar
var menu = window.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.MenuBar));
// get the "file" menu
var fileMenu = menu.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.NameProperty, "File"));
// open it
SafeExpand(fileMenu);
// get the new File menu that appears (this is quite specific to n++)
var subFileMenu = fileMenu.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Menu));
// get the "open" menu
var openMenu = subFileMenu.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.NameProperty, "Open..."));
// click it
((InvokePattern)openMenu.GetCurrentPattern(InvokePattern.Pattern)).Invoke();
// get the new Open dialog (from root)
var openDialog = WaitForDialog(window);
// get the combobox
var cb = openDialog.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.ComboBox));
// fill the filename
((ValuePattern)cb.GetCurrentPattern(ValuePattern.Pattern)).SetValue(filePath);
// get the open button
var openButton = openDialog.FindFirst(TreeScope.Children, new AndCondition(
new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Button),
new PropertyCondition(AutomationElement.NameProperty, "Open")));
// press it
((InvokePattern)openButton.GetCurrentPattern(InvokePattern.Pattern)).Invoke();
}
static AutomationElement WaitForDialog(AutomationElement element)
{
// note: this should be improved for error checking (timeouts, etc.)
while(true)
{
var openDialog = element.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Window));
if (openDialog != null)
return openDialog;
}
}
static void SafeExpand(AutomationElement element)
{
// for some reason, menus in np++ behave badly
while (true)
{
try
{
((ExpandCollapsePattern)element.GetCurrentPattern(ExpandCollapsePattern.Pattern)).Expand();
return;
}
catch
{
}
}
}
}
If you wonder how this has been made, then you must read about UI Automation. The mother of all tools is called Inspect: https://msdn.microsoft.com/library/windows/desktop/dd318521.aspx
Make sure you get version at least 7.2.0.0. Note there is another one called UISpy but inspect is better.
Note, unfortunately, notepad++ tab text content - because it's based on the custom scintilla editor control - does not properly supports automation (we can't read from it easily, I suppose we'd have to use scintilla Windows messages for this), but it could be added to it (hey, scintilla guys, if you read this ... :).
In addition to the answer from Garath, you might also want to investigate the Windows automation API's i.e. the technology used to implement coded UI tests for GUI applications. As part of regular functional testing, I routinely control an external application from a set of NUnit tests using these API's.
Tools like UIAVerify will give you an indication of what controls are available in the application and you can use the Invoke Pattern (and many others) to interact with the controls at run-time.
If you want a detailed example of how to use the automation API's, the open source TestStack White project is pretty handy.
It is almost not possible if SendKeys is not an option but read more
Now more important part of the question- why:
We have to look how win32 application works: it has a WndProc/WindowProc method which is resposible for processing "events" form the UI.
So every event in the windows application must go through above method. SendKeys method is a special of SendMessage (MSDN), so you can use SendMessage to control other exe than your.
Simple code could look like:
IntPtr hwnd = FindWindow("Notepad++", null);
SendMessageA(hwnd, WM_COMMAND, SOMETHING1, SOMETHING2);
There is already on StackOverflow example how to do that with chrome: C# - Sending messages to Google Chrome from C# application , but this is only a start. You will have to find out what exactly message you want to send.
In exactly situation which you described I will try to send WM_MOUSE and WM_KEYBORD events to Notepad++ events, but it is only an idea :)
I have several tab pages collection. By default when user open the apps, the first tab page is the start tab page, then user will close the tab page. Now I would like to create a situation where when the user go to the menu strip, click for example the "tab page 1 button", then the "tab page 1" will appear in the tab control. Any expertise can help me please...
Use the SelectedTab() method. It has three overloads.
If you have a reference to the tab:
tabControl1.SelectTab(tabPage2);
If you only know the index:
tabControl1.SelectTab(1); // 0-based index, this shows the second tab
If you only know the name:
tabControl1.SelectTab("tabPage2");
You say your users can click an [x] that removes the tab.
I'll assume it's removed by the easiest means, something like:
tabControl1.TabPages.Remove(tabPage1);
You can't focus on a tab that's not part of the tab control, so you'll have to add it back first.
tabControl1.TabPages.Add(tabPage1); // add tab as last tab in tabcontrol
tabControl1.TabPages.Insert(0, tabPage1); // or insert it at a specific index
tabControl1.SelectTab(tabPage1);
To select the tab page of the TabPage control, not only could user click the title to switch pages, but set the selectedTabPageIndex property (or like this) to do it.
Just have a try.
i am also facing this problem. Finally i solve by following code.
Scenario
My tab Control have many tabs and i make a [x] sign for closing that tab.
on click [x] my tab is remove from Tab Control.
Now when i click on button, i open the tab (that was Removed)
Code
private void openProductTab_Click(object sender, EventArgs e)
{
if (tabControlMdi.TabPages.Contains(tabProduct))//tab already present
{
tabControlMdi.SelectTab(tabProduct); // select by name
}
else
{
tabControlMdi.TabPages.Add(tabProduct); // add removed tab
tabControlMdi.SelectTab(tabProduct); // select by name
}
}
private void invoiceGenerationToolStripMenuItem_Click(object sender, EventArgs e)
{
foreach (Form form in Application.OpenForms)
{
if (form.GetType() == typeof(RETransactions.frmInvoicegeneration))
{
form.Activate();
foreach (TabPage item in tabControl1.TabPages)
{
if (item.Text == "Invoice Generation")
{
tabControl1.SelectTab(item);
}
}
return;
}
}
RETransactions.frmInvoicegeneration rTenancy = new RETransactions.frmInvoicegeneration();
rTenancy.Show();
rTenancy.TopLevel = false;
TabPage tabp = new TabPage("Invoice Generation");
tabp.Controls.Add(rTenancy);
tabControl1.TabPages.Add(tabp);
tabControl1.SelectTab(tabp);
tabp.BackColor = Color.Gainsboro;
}
// i hope it will work ... thank you
I have a tab control in my WPF application with multiple tabs. Each tab gives access to several buttons, text boxes, drop downs. Now before moving to the next tab valid entries in each of the controls in the tab is to be checked or jumping to the next tab should not be allowed. How can this be done?
I was able to use IsEnable property to do this. But I want it like, when I click on the next tab it should, without entering the next tab, display a warning that such and such entry in the present tab is not valid.
If you adhere to the Selected event you can do something like this:
// Keep a global variable for the previous index
int prevIndex = 0;
private void tabControl_Selected(object sender, TabControlEventArgs e)
{
TabControl tc = sender as TabControl;
if (tc != null)
{
bool letSwitchHappen = validateTabControls(tc.SelectedIndex);
if (!letSwitchHappen)
{
tc.SelectedIndex = prevIndex;
}
prevIndex = tc.SelectedIndex;
}
}
Where validateTabControls is something like:
private bool validateTabControls(int tabIndex)
{
bool validEntries = false;
// Some code here to set validEntries according to the control at tabIndex
return validEntries;
}
Take a look at this example from Josh Smith.
It shows explicitly how to do this, and Josh is well-known (and respected) in the WPF world.
I made a custom FindControl function to find a control within all childs of one control I pass in parameter.
But I don't manage to have a hand over the button used to create a user ,in a CreateUserWizard Control.
I kept the default style, do anyone knows the name (ID) of this button?
I saw buttons like "ContinueButtonButton", "FinishButton", but they don't seem to be the one I am searching for, because I then have this line:
this.Form.DefaultButton = Tools.FindControl(CreateUserWizard1, "FinishButton").UniqueID;
And the create user event is not fired when I hit enter.
Any idea?
I finally found it, its ID is "StepNextButtonButton"
how about try something like
foreach (Control ctrl in this.form1.Controls)
{
if (ctrl.GetType() == typeof(Button) && (ctrl as Button).Text == "Button2")
{
this.form1.DefaultButton = ctrl.ID;
}
}