WPF C# Programmatically adding and moving tabs - c#

I'm currently working on something that is probably done in plenty of examples out there. But after some searching I can't find anything.
I'm working with WPF tab control and I'm trying to recreate some basic functionality (which you see in all internet browsers nowadays) to add a new tab by clicking a '+' tab which is the last listed tab.
I already have the '+' tab which adds a new tab. My problem is, I want to move the '+' tab after the new tab (so its the end tab again) and switch view to the new tab that has just been created.
I thought something like:
void tiNewTab_Add(object sender, EventArgs e)
{
int idx = tabControl1.Items.Count;
tabControl1.SelectedIndex = idx - 1;
TabItem ti = new TabItemKPI();
tabControl1.Items.Add(ti);
tabControl1.Items.MoveCurrentToLast();
}
...would work but no luck :(

Try something like this:
tabControl1.Items.Insert(tabControl1.Items.Count-1,ti);
This will do because you always have at least one TabItem (the + one)
Then select the second last one by
tabControl1.SelectedIndex=tabControl1.Items.Count-2;

Not tested, but following should work:
int idx = tabControl1.Items.Count;
tabControl1.SelectedIndex = idx - 1;
TabItem ti = new TabItem();
tabControl1.Items.Insert(tabControl1.Items.IndexOf(tabControl1.Items.Last()), ti);

Related

Difficulty with tabControl/tabitem refresh

I have a WPF window with a maintabWindow and several tabitems.
It normally works fine and the layout is this:
but when I BEFORE add the following window:
the result is this:
So the problem is related with the tabControl/tabItem refresh.
This is fairly obvious but even more because if I move the window or pass with the mouse on the a tabItem they get refreshed one by one.
I searched and found that here is a solution: http://geekswithblogs.net/NewThingsILearned/archive/2008/08/25/refresh--update-wpf-controls.aspx
so I added:
this.MainTab.Refresh();
this.tabItem1.Refresh();
this.tabItem2.Refresh();
this.tabItem3.Refresh();
this.tabItem4.Refresh();
this.tabItem5.Refresh();
but that didn't change a thing.
Thanx for any help
Ok so in the end it has a quite a weird behavious. If I do
for (int i = 0; i < tbcMain.Items.Count; i++)
{
tbcMain.SelectedIndex = i;
tbcMain.UpdateLayout();
}
it works. But I have to set the 1st tabitem so if I add
tbcMain.SelectedIndex = 0;
it doesn't.
So the solution was put a sleep and it works again.
for (int i = 0; i < tbcMain.Items.Count; i++)
{
tbcMain.SelectedIndex = i;
tbcMain.UpdateLayout();
}
System.Threading.Thread.Sleep(250);
tbcMain.SelectedIndex = 0;
But that is not elegant at all. If anyone has a better solution pls let me know it.
Btw adding the tbcMain.SelectedIndex = 0; on the loaded event of the mainWindow is of no use.
You should be able to set your SelectedIndex first, and without having to include it in your loop:
tbcMain.SelectedIndex = 0;
Then, basing it off of your response, you should be able to either just do .UpdateLayout() on each of your TabItems:
MainTab.UpdateLayout();
tabItem1.UpdateLayout();
tabItem2.UpdateLayout();
tabItem3.UpdateLayout();
tabItem4.UpdateLayout();
tabItem5.UpdateLayout();
Or you should be able to do something like this in your loop:
MainTab.UpdateLayout();
for (int i = 0; i < tbcMain.Items.Count; i++)
{
TabItem tbi = (TabItem)this.FindControl("tabItem"+i);
tbi.UpdateLayout();
}
Updating/refreshing should have nothing to do with setting the selected one. Including the selection of the tab within the loop to i was your problem - not a race condition. Set the tbcMain.SelectedIndex = 0 outside of your loop and you should be fine. Sometimes, however, this doesn't work and you need to set it with Dispatcher:
Dispatcher.BeginInvoke((Action)(() => this.tbcMain.SelectedIndex = 0));
There's a write up/comments on a separate thread regarding why it needs to be sent to Dispatcher:
How to programmatically select a TabItem in WPF TabControl
Though, unfortunately for me, I had a similar issue where I was trying to refresh a ListView on a subtab. Neither .UpdateLayout(), nor .InvalidateVisual() (as I saw on this thread) worked. I just had to rebind my grid in the button event I was using on my main page, so that when the tab was clicked, it was refreshed manually. I added an x:Name property on the tab so I could call it using "dot" syntax, and it exposed the ListView. I simply added the DataTable of results back to that ListView's DataContext.

Cannot edit DataGridView cell, after choosing option I have to press Esc and lose the edit

So here is the story - I have 2 DataGridViews - one of them is used as a display, the other one is user for editing or adding new entries. I don't use bindings on the edit one. When I am creating new entry I am just extracting the cells' values and passing them to an object. When I am editing though comes the problem.
The edit consists of 2 parts - one is to select the entry to be edited and display it on the second DGV. This is done with SelectionChanged event and the code is bellow. Then when editing is done it should just publish the new task the same way as creation. The thing is that when I am doing the edit and I come to the moment when I have to select from one of my cells - a ComboBoxCell - and I make a selection everything freezes. I cannot click anything else than this ComboBox until I press Esc - which obviously reverts the choice.
Why is this freeze happening and what causes it only when the data is cloned from the first DGV, but is okay when creating a brand new row? I am using VS2012 by the way and this is a windows forms application
Here is the code for duplication of the selected task - this method is the only thing in the DGV1's SelectionChanged Event handler:
public void createTemplateTaskToBeEditted(Form1 form1, ApplicationControl appControl)
{
form1.dg_templateView.Rows.Clear();
for (int i = 0; i < form1.dg_taskView.SelectedRows.Count; i++)
{
if (form1.dg_taskView.SelectedRows[i].Cells[0].Value == null)
{
form1.dg_taskView.SelectedRows[i].Cells[0].Value = false;
}
int index = form1.dg_templateView.Rows.Add();
form1.dg_templateView.Rows[index].Cells[0].Value =
form1.dg_taskView.SelectedRows[i].Cells[0].Value.ToString();
form1.dg_templateView.Rows[index].Cells[1].Value =
form1.dg_taskView.SelectedRows[i].Cells[2].Value.ToString();
form1.dg_templateView.Rows[index].Cells[2].Value =
form1.dg_taskView.SelectedRows[i].Cells[3].Value.ToString();
form1.dg_templateView.Rows[index].Cells[3].ValueType = typeof(ComboBox);
form1.dg_templateView.Rows[index].Cells[3].Value =
form1.PopulateAssignToComboBox(appControl.GetAllowedMembers(form1));
form1.dg_templateView.Rows[index].Cells[4].Value =
form1.dg_taskView.SelectedRows[i].Cells[5].Value.ToString();
form1.dg_templateView.Rows[index].Cells[5].Value =
form1.dg_taskView.SelectedRows[i].Cells[6].Value.ToString();
form1.dg_templateView.Rows[index].Cells[6].Value =
form1.dg_taskView.SelectedRows[i].Cells[7].Value.ToString();
form1.dg_templateView.Rows[index].Cells[7].Value =
form1.dg_taskView.SelectedRows[i].Cells[8].Value.ToString();
form1.dg_templateView.Rows[index].Cells[8].Value =
form1.dg_taskView.SelectedRows[i].Cells[9].Value.ToString();
form1.dg_templateView.Rows[index].Cells[9].Value =
form1.dg_taskView.SelectedRows[i].Cells[10].Value.ToString();
form1.dg_templateView.Rows[index].Cells[10].Value =
form1.dg_taskView.SelectedRows[i].Cells[11].Value.ToString();
form1.dg_templateView.Rows[index].Cells[11].Value =
form1.dg_taskView.SelectedRows[i].Cells[12].Value.ToString();
}
}

Clicking on List Item on Dropdown

I'm having a problem in interacting with a custom dropdown control. It works fine the 1st 6 times, but after that, since the screen is resized, it could no longer locate and click the option in the dropdown control, returning an exception - can't click on hidden control. I tried putting in a itemField.DrawHighlight(); on the control I'm looking for, and it finds it, however it can't click on it. I also tried a to scroll down, but it seems to be not working.
bool addItemCheck = false;
int scrollCheck = 0;
while (Check == false)
{
var addItem= new HtmlButton(window);
addItem.SearchProperties.Add(HtmlButton.PropertyNames.Id, "add-new-item");
Mouse.Click(addItem);
scrollCheck = scrollCheck + 1;
if (scrollCheck > 6)
{
Mouse.MoveScrollWheel(window, -100);
}
var itemDropDown = new HtmlSpan(window);
itemDropDown .SearchProperties.Add(HtmlSpan.PropertyNames.Class, "item-dropdown");
itemDropDown .SearchProperties.Add(HtmlSpan.PropertyNames.InnerText, "Select an Item");
Mouse.Click(itemDropDown );
addItemCheck = itemDropDown.Exists;
}
bool itemBoxCheck = false;
HtmlCustom itemBox = null;
while (itemBoxCheck == false)
{
itemBox = new HtmlCustom(window);
itemBox.SearchProperties.Add(HtmlCustom.PropertyNames.Id, "item-listbox");
var itemField = new HtmlCustom(itemBox);
itemField .SearchProperties.Add(HtmlCustom.PropertyNames.InnerText, item);
Mouse.Click(itemField);
itemBoxCheck = itemBox.Exists;
}
I would really appreciate any help. Thank you.
Try calling the method InsureClickable() on the control before attempting to click on it.
for example:
itemDropDown.EnsureClickable();
Mouse.Click(itemDropDown);
Edit:
if this doesn't work you'll have to scroll down to the item.
try using:
Mouse.MoveScrollWheel()
if that doesn't work also you'll have to map the scroll control and click on it.

Is there a simple method to get coordinates of a particular item in a checkedlistbox?

I am making a simple class extending CheckedListBox that just adds a small textbox to the right of an item when it is checked. My issue is finding a good way to place the box at the correct location.
I had initially though I could use the Controls.Find() along with the ItemCheckEventArgs index to get the coordinates of the checkbox in question, and move to the right edge of the column from there. However, that did not work, and a brief look through the CheckedListBox class seemed to show that it does not actually contain any CheckBox controls, but merely draws images of them.
I then came up with the following method:
void CreateAmountBox(int index)
{
int itemsPerCol = Height/ItemHeight;
int x = GetColumn(index, itemsPerCol)*ColumnWidth - boxWidth;
int y = (index % itemsPerCol)*ItemHeight - offset;
System.Windows.Forms.TextBox NewAmountTextBox = new System.Windows.Forms.TextBox();
NewAmountTextBox.Location = new System.Drawing.Point(x, y);
NewAmountTextBox.Name = Items[index] + "Amount";
NewAmountTextBox.Size = new System.Drawing.Size(20, boxWidth);
Controls.Add(NewAmountTextBox);
}
where GetColumn(...) returns the column of the given index (from the CheckEventArgs). This works, but it feels like a hack and is not very readable.
Two other ideas I thought of:
1) I could just create all the TextBoxes at the start, and simply hide them until they are needed. Controls like these are all created dynamically throughout the rest of the program however, and I don't want these ones to be the odd exception. It also means that some more functionality needs to be added for cases when an item is added or removed.
2) I could use mouse position, which of course won't work if the input is via keyboard. I don't anticipate it ever being so, but best not to leave that possibility.
With some googling, the only other way I found of possibly doing this was using the ListBoxItem and TranslatePoint method, but I haven't gotten that to work, and I'm unsure as to whether it even can with a CheckedListBox instead of a ListBox.
So, is there a simple way of finding the x and y of the checked item that I don't know of? Or am I limited to simply extracting the x and y declarations above into a method and leaving it there?
You can just use the GetItemRectangle function to accomplish that:
void checkedListBox1_ItemCheck(object sender, ItemCheckEventArgs e) {
Rectangle r = checkedListBox1.GetItemRectangle(e.Index);
TextBox newAmountTextBox = new TextBox();
newAmountTextBox.Location = new Point(r.Left, r.Top);
//...
}

Winform menustrip and hiding tabs

Hello I'm thinking of creating a tabcontrol which the tabpages will be filtered by the clicks in the menustrip.
For ex.
My menustrip is in form 1
and my tabcontrol is in form 2
My tabcontrol consist of 7 tabs and I want only 1 tab will be shown at a time.
for example If I click the name in the menustrip it will open/show a new form and the tabcontrol will only show the names tab.
I wonder if its possible because making diff forms for each list seems to be very long.
thanks for reading this.
Problem is, the TabPage control has no Visible property (well, it has, but it does nothing). So you can't hide and show tabs at will. You'll have to remove the tabs that should not be visible.
You could make a form (named TabbedForm) with code like this:
private readonly int _index;
public TabbedForm(int index)
{
this._index = index;
InitializeComponent();
}
private void form_Load(object sender, EventArgs e)
{
for (int index = this.tabControl1.TabPages.Count - 1; index >= 0; index--)
{
if (index != this._index)
this.tabControl1.TabPages.Remove(this.tabControl1.TabPages[index]);
}
}
With each menu button (Clicked event) in your main form you can open a TabbedForm with a different index.
Yes, this will work pretty fine. But I think, you must use the default tab view control for this and that must not create the problem either in you case too.

Categories

Resources