Search a collection of TabItems for a TabItem Name - c#

I want to input the name of a TabItem to a Window containing a TabControl that contains a collection of TabItems, programatically search the collection and open the TabItem with the name that matches that input. dkozl answered a similar question Aug 16 '13 but I don't understand it (I'm new to this).
I've kicked this around for a couple of days and have come up with the following (which doesn't work)
foreach (IEnumerable<TabItem> item in tabControlList)
{
if (item.Name == "AddRskAreas")
{
item.IsSelected = true;
}
else
{
MessageBox.Show("Tab not found");
}
}
I struggle to understand how to implement IEnumerable. Can anyone help me with this please?

You can update multiple values in a list using LINQ:
tabControlList.Where(item => item.Name == "AddRskAreas").ToList().ForEach(item => item.IsSelected = true);

You need to actually compare the "Header" instead of the name.
foreach (IEnumerable<TabItem> item in tabControlList)
{
if (item.Header== "AddRskAreas")
{
item.IsSelected = true;
}
else
{
MessageBox.Show("Tab not found");
}
}

I derived a solution with a little help from Sean Sextons 2,000 Things You Should Know About C# knowledge base. I'll post the key XAML and C# fragments of my solution below in case anyone else can piece them together get value from it.
Interestingly the buttons are now faded out - anyone know why?
//The XAML fragments ....
<!-- These RoutedUICommands (in <Window.Resources>) are bound to the Process Procedure Selection Buttons. Clicking on the button
opens the corresponding process procedure TabItem -->
<RoutedUICommand x:Key="OpenPrcdrTbItm" Text="This Command opens the Process Procedure TabItem"/>
<Window.CommandBindings>
<!-- These CommandBindings (in <Window.CommandBindings>) bind the Process Procedure Selection Button Commands to the Command Handler in the code behind -->
<CommandBinding Command = "{StaticResource OpenPrcdrTbItm}" Executed="RskPrcssPrcdrs_Click"/>
<Button x:Name="ChngeRskAreas" Grid.Column="1" Content="Change Risk Areas"
Command ="{StaticResource OpenPrcdrTbItm}" CommandParameter="ChngeRskAreas"/>
//The C# code behind fragments
//Select the chosen TabItem
public void RskPrcssPrcdrs_Click(object sender, ExecutedRoutedEventArgs e)
{
RskManWndw rskManWndw = new RskManWndw(this); //Instantiate a new rskManWndw window
TabControl tabControlCollection = new TabControl();
TabItem tabItemCollection = new TabItem();
string slctdTabItem = (string)e.Parameter;
bool slctdTabItemFnd = false;
string msgBoxMsg = "";
//Open the rskAraManWndw window
rskManWndw.Show();
foreach (TabItem tabItem in rskManWndw.RskManPrcssTbCtl.Items)
{
if (tabItem.Name == slctdTabItem)
{
tabItem.IsSelected = true; //Select the chosen TabItem.
slctdTabItemFnd = true; //Flag that the TabItem was found.
break;
}
}
if (slctdTabItemFnd == false) //Was the TabItem found?
{
msgBoxMsg = "A TabItem matching the" + slctdTabItem + "Command Parameter was not found. "
+ "Please inform the system administrator.";
MessageBox.Show($" {msgBoxMsg}", "RMS Processing Error Alert");
rskManWndw.Close();
}
else
{
Hide(); //Hide the Risk_Management_System.MainWindow
}
}

Related

MenuItem AutoClose = false on dynamically generated Toolstrip Menu

So, following this question, I have been attempting to deal with a way to stop a drop down menu from closing when I click on an item.
In the linked question, one such answer suggested that I set the AutoClose property to false. I did so, and this did achieve what I asked. However, the way I implemented it means that the Drop Down menu is forced open.
Form Code:
public void ToolStripMenuItem_Click(object sender, EventArgs e)
{
ToolStripMenuItem item = sender as ToolStripMenuItem;
if (item != null)
item.Checked = !item.Checked;
item.DropDown.AutoClose = false;
}
I know why this is - the implementation means that there is no way to allow the AutoClose to be set to true. However, since the menuItems are dynamically generated in a different class, I don't have any events or objects to refer to.
This code copies the menu structure from the Main Form, and copies it across to recreate it in the "Profile View" (to set what users can/cannot see).
Controller Code:
private void PopulateProfileView(User_AccessProfilesView view, Menu_View mainMenu)
{
// Disabled Items are not able to be set, becasue they are either always visible for every user,
// or only visible to specific users (Administrator)
List<string> disabledMenuItems = new List<string>();
List<string> disabledSubMenuItems = new List<string>();
bool error = false;
bool subError = false;
_groupDictionary = new Dictionary<string, List<string>>();
// Populate the disallowed Menu Items from the Main Menu,
// and then add the items specific to the Profile View
disabledMenuItems.Add("File");
disabledMenuItems.Add("Administrator");
disabledMenuItems.Add("Help");
disabledMenuItems.Add("Te&rminations");
disabledMenuItems.AddRange(mainMenu.disallowedMenuItems);
// Populate the disallowed Sub Menu Items from the Main Menu,
// and then add the items specific to the Profile View
disabledSubMenuItems.Add("View All");
disabledSubMenuItems.AddRange(mainMenu.disallowedSubItems);
foreach (ToolStripMenuItem item in mainMenu.mainMenuStrip.Items)
{
ToolStripMenuItem menuItem = new ToolStripMenuItem(item.Text);
if (error == false)
{
// Add to the menu bar
view.menuStrip.Items.Add(menuItem);
menuItem.Click += new EventHandler(view.ToolStripMenuItem_Click);
foreach (ToolStripItem dropItem in item.DropDownItems)
{
if (dropItem is ToolStripMenuItem)
{
ToolStripMenuItem menuDropItem = new ToolStripMenuItem(dropItem.Text);
// Same concerns as above with regards to doing a substring check
// to decide if menu items should be excluded or not.
foreach (string s1 in disabledSubMenuItems)
{
if (!menuDropItem.Text.Contains(s1))
{
subError = false;
}
else
{
subError = true;
break;
}
}
if (!subError)
{
menuItem.DropDownItems.Add(menuDropItem);
menuDropItem.Click += new EventHandler(view.ToolStripMenuItem_Click);
}
}
else if (dropItem is ToolStripSeparator)
{ menuItem.DropDownItems.Add(new ToolStripSeparator()); }
}
How do I implement the AutoClose property correctly so that if I click on a menu item, the menu won't close, but if I click on the menu header, or move the mouse away from the menu, or select another menu (either by click or mouse over), the menu does Close?
Apologies if this is a simple issue - I have been out of the game for roughly a year, and have to jump back into this and I am having a little bit of an issue following everything properly.
To solve the problem you can follow these steps:
You should determine which menu items should keep open even after clicking on them. I'll use "keepopen" as value of Tag property for those items that should be kept open after clicking.
For the menu item which contains those items, you need to get DropDown property and and handle its ItemClicked event and in the ItemClicked event, you should check if the item which is clicked is one of those "keepopen" items, then set DropDown.AutoClose of the container menu item to false. For other items, set it to true. It will prevent closing those "keepopen" item when clicking, while let other items close by click.
You should handle CheckedChanged event of those "keepopen" items and set DropDown.AutoClose to true. While using the Click event handler we prevented the items from closing, here we enable the closing again, so if the user click outside of the menu, it will close.
Then this would be the result, look at mouse clicks:
Example
As an example, create an empty form and handle its Load event and use following code. When you click on SubMenu1, SubMenu2 or SubMenu3, they will just get checked or unchecked without closing the menu. But of you click outside the menu or on SubMenu4, it will close the menu.
const string keepopen = "keepopen";
private void Form1_Load(object sender, EventArgs e)
{
var menuStrip = new MenuStrip() { Dock = DockStyle.Top };
this.Controls.Add(menuStrip);
var menu1 = (ToolStripMenuItem)menuStrip.Items.Add("Menu1");
menu1.DropDownItems.Add(new ToolStripMenuItem("Submenu1")
{ Tag = keepopen, CheckOnClick = true });
menu1.DropDownItems.Add(new ToolStripMenuItem("Submenu2")
{ Tag = keepopen, CheckOnClick = true });
menu1.DropDownItems.Add(new ToolStripMenuItem("Submenu3")
{ Tag = keepopen, CheckOnClick = true });
menu1.DropDownItems.Add("-");
menu1.DropDownItems.Add(new ToolStripMenuItem("Submenu4"));
menu1.DropDown.ItemClicked += (obj, args) =>
{
if (args.ClickedItem.Tag == keepopen)
menu1.DropDown.AutoClose = false;
else
menu1.DropDown.AutoClose = true;
};
menu1.DropDownItems.OfType<ToolStripMenuItem>()
.Where(x => x.Tag == keepopen)
.ToList().ForEach(x =>
{
x.CheckedChanged += (obj, args) =>
{
menu1.DropDown.AutoClose = true;
};
});
}

menuItem.InputGestureText not showing shortcut text

In my application i am creating menu items in code. This is the code for creating menu item
public MenuItem getMenuItem(string toolTip, string menuTitle, Uri menuIconUri, int? tagOnlyForHeaders, string shortCutKeyText ="")
{
MenuItem menuItem = new MenuItem
{
ToolTip = toolTip,
Header = menuTitle
};
if (menuIconUri != null)
{
menuItem.Icon = new Image
{
Source = new BitmapImage(menuIconUri)
};
}
if (tagOnlyForHeaders != null) {
menuItem.Tag = tagOnlyForHeaders;
}
if (shortCutKeyText != "") {
menuItem.InputGestureText = shortCutKeyText;
}
return menuItem;
}
but if I pass value for input Gesture like ctrl+n it is not displaying the shortcut text in the menu item while the application is running. what is wrong in this code. can anyone tell a solution for this.
This is how i add menu items
//Top level Op menu
var opMenuItem = utils.getMenuItem("OP", MenuName, null, 0);
//op registration
var RegistrationMenuItem = utils.getMenuItem("New Registration", "New Registration",
new Uri(baseIconUri + "newRegistration.png"), null,"ctrl+n ");
opMenuItem.Items.Add(opRegistrationMenuItem);
return opMenuItem;
and this is added to the main menu
mainMenu.Items.Add(menuItem); // in this case the "opMenuItem"
The InputGestureText only works when the MenuItem is not a direct child of the Menu(i.e Not directly inside the Items collection). If you want to see the InputGestureText, you need to add MenuItem to the Items collection of another MenuItem. To illustrate what I said, here is an example in XAML.
<Menu>
<MenuItem Header="File" InputGestureText="Ctrl+Z">
<MenuItem InputGestureText="Ctrl+C" Header="Open"></MenuItem>
</MenuItem>
</Menu>
The InputGestureText of the MenuItem (Header = "File) is not visible but that of MenuItem (Header="Open") is visible.
That was a problem with the library(Material design library) i was using to style user interface . I've reported the issue and it is fixed.

ListView SelectedItem not highlighted when set in ViewModel

I have a ListView with a ItemSource data binding and a SelectedItem data binding.
The ListView is populated with a new ItemSource every time I press the Next or Previous button.
The SelectedItem is updated accordingly, the items in the ItemSource have the Selected state, so it can be remembered when the user navigates back and forth.
While debugging, everything seems to work perfectly. The VM updates the controls as expected, and I can also see that the ListView has the correct selected value when I navigate with the next and previous buttons.
The problem is, that regardless of the fact that the ListView has a correct SelectedItem, the ListView does not visualize the SelectedItem as highlighted.
XAML:
<ListView
x:Name="_matchingTvShowsFromOnlineDatabaseListView"
Grid.Row="0"
Grid.Column="0"
Grid.RowSpan="3"
ItemsSource="{Binding AvailableMatchingTvShows}"
SelectedItem="{Binding AcceptedMatchingTvShow, Mode=TwoWay}">
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Behaviour in ViewModel responsible for repopulating the ItemSource and the SelectedItem:
private void UpdateForCurrentVisibleTvShow()
{
var selectedTvShow = FoundTvShows[CurrentTvShow];
// Update the available matches
var availableMatchingTvShows = new ObservableCollection<IWebApiTvShow>();
if (AvailableTvShowMatches[selectedTvShow] != null)
{
foreach (var webApiTvShow in AvailableTvShowMatches[selectedTvShow])
{
availableMatchingTvShows.Add(webApiTvShow);
}
}
AvailableMatchingTvShows = availableMatchingTvShows;
// Update the selected item
AcceptedMatchingTvShow = availableMatchingTvShows.FirstOrDefault(webApiTvShow => webApiTvShow.Accepted);
// Update the progress text
CurrentTvShowInfoText = string.Format(
"TV Show: {0} ({1} of {2} TV Shows)",
FoundTvShows[CurrentTvShow],
CurrentTvShow + 1,
FoundTvShows.Count);
// Update the AcceptedMatchingTvShow selection in the listview
OnPropertyChanged("AcceptedMatchingTvShow");
}
The implementation of AcceptedMatchingTvShow:
public IWebApiTvShow AcceptedMatchingTvShow
{
get
{
IWebApiTvShow acceptedTvShow = null;
if (FoundTvShows.Count > 0)
{
var tvShowName = FoundTvShows[CurrentTvShow];
acceptedTvShow = AvailableTvShowMatches[tvShowName].FirstOrDefault(webApiTvShow => webApiTvShow.Accepted);
}
return acceptedTvShow;
}
set
{
if (value != null)
{
var tvShowName = FoundTvShows[CurrentTvShow];
var currentlyAcceptedTvShow =
AvailableTvShowMatches[tvShowName].FirstOrDefault(webApiTvShow => webApiTvShow.Accepted);
if (currentlyAcceptedTvShow != null)
{
currentlyAcceptedTvShow.Accepted = false;
}
value.Accepted = true;
}
OnPropertyChanged();
}
}
I hope somebody can point me in the right direction. Just to be clear, the ListView has the correct items, and the SelectedItem is set with the correct item.
Well, I found 'a solution' to the problem after a lot of debugging and digging. I would REALLY like to understand if this is how WPF meant the control to behave, or if this is a bug in the ListViews data binding part. If anyone could tell me that, I am very very curious to the correct answer (and maybe I solved this problem in the wrong way, and somebody could explain me how I should've done this).
Anyway, the problem seems to be resolved when I create a copy of the object:
public IWebApiTvShow AcceptedMatchingTvShow
{
get
{
IWebApiTvShow acceptedTvShow = null;
if (FoundTvShows.Count > CurrentTvShow)
{
var tvShowName = FoundTvShows[CurrentTvShow];
acceptedTvShow = AvailableTvShowMatches[tvShowName].FirstOrDefault(webApiTvShow => webApiTvShow.Accepted);
}
if (acceptedTvShow != null)
{
// I MUST create a new instance of the original object for the ListView to update the selected item (why??)
return new WebApiTvShow(acceptedTvShow);
}
return null;
}
set
{
if (value != null)
{
var tvShowName = FoundTvShows[CurrentTvShow];
var availableTvShowMatch = AvailableTvShowMatches[tvShowName];
var currentlyAcceptedTvShow = availableTvShowMatch.FirstOrDefault(webApiTvShow => webApiTvShow.Accepted);
if (currentlyAcceptedTvShow != null)
{
currentlyAcceptedTvShow.Accepted = false;
}
value.Accepted = true;
}
OnPropertyChanged();
}
}
Note the call to the copy constructor :
return new WebApiTvShow(acceptedTvShow);
It works, but seems really ridiculous and smells like a bug in ListView to me. Is it?
I tried to explain the same problem in a simpler example here, if anybody can confirm the bug or can explain me how this should've been implemented I would greatly appreciate the insights.
A bit late to the game, but I had been jumping through hoops to solve this Problem in a similar setup. Setting the SelectedItem in a ListView using a bound Property in the Viewmodel or similar using a bound SelectedIndex just would not work. Until I tried to do it async:
Task.Factory.StartNew(() =>
{
BoundSelectedIndex = index;
});
Seems to work - more advanced contributors may answer why...
i know this is an old post but what worked is overriding the Equals and GetHashCode on your SelectedItem object so the listview can compare the SelectedItem with the bound collection

C# ListView from Another Function

Please forgive me for such a stupid question. I am sure many of you will find this easy, where I have sent almost half the day reading trying to figure this out.
Here is the problem:
I have a FORM (Form1.cs) made. In that form I created a listview, and named it "ListView1".
Within the Form1.cs, I call a function called FileManager(this), where I pass in the THIS object.
In FileManager.cs I was able to listviewArray= originalForm.Controls.Find("listView1", true) and find that 'listview'.
When I do a listviewArray[0]<-- I can't seem to add a list to it.
FileManager.cs
FileManager(object sender)
{
if (sender != null)
{
originalForm = (Form)sender;
}
}
public void getFiles()
{
filePaths = Directory.GetFiles(hsocDir);
if(filePaths != null)
{
listviewArray= originalForm.Controls.Find("listView1", true);
if(listviewArray != null)
{
ListViewItem lvi = new ListViewItem("text");
// My Array is listViewArray
// How to add things to Lvi to it.
}
}
== Form1.cs
public Form1()
{
InitializeComponent(`enter code here`);
mysql = new MySQLCheck(this);
fileManager = new FileManager(this);
fileManager.getFiles();
}
You can't access element 0 of the collection because the collection is empty. To add an item, use:
listViewArray.Items.Add(lvi);
You need to modify the Items collection instead of the ListView itself for this to work, as ListView is not a collection (its a control).
listViewArray.Items.Add(lvi);
Also in your listview,setting this properties will help :
// Set the view to show details.
listViewArray.View = View.Details;
// Select the item and subitems when selection is made.
listViewArray.FullRowSelect = true;
// Display grid lines.
listViewArray.GridLines = true;

How can i give a focus to a listBox in the constructor and when a new item was added?

In the constructor i did:
if (listBox1.Items != null)
{
listBox1.Focus();
}
But when im running the program i cant move with the keyboards up down in listBox since the focus is on a button somewhere else in the Form. I need to click with the mouse on the listBox to get the focus.
Another problem i want that when the user add a new item to the listBox the focus will be automatic on the last added item. For this problem this is the code where im adding a new item to the listBox:
private void KeysValuesUpdate()
{
using (var w = new StreamWriter(keywords_path_file))
{
crawlLocaly1 = new CrawlLocaly();
crawlLocaly1.StartPosition = FormStartPosition.CenterParent;
DialogResult dr = crawlLocaly1.ShowDialog(this);
if (dr == DialogResult.OK)
{
if (LocalyKeyWords.ContainsKey(mainUrl))
{
LocalyKeyWords[mainUrl].Clear();
LocalyKeyWords[mainUrl].Add(crawlLocaly1.getText());
}
else
{
LocalyKeyWords[mainUrl] = new List<string>();
LocalyKeyWords[mainUrl].Add(crawlLocaly1.getText());
}
Write(w);
ClearListBox();
}
if (dr == DialogResult.Cancel)
{
Write(w);
}
}
}
private void ClearListBox()
{
data.Clear();
listBox1.DataSource = null;
string sb;
foreach (KeyValuePair<string, List<string>> kvp in LocalyKeyWords)
{
for (int i = 0; i < kvp.Value.Count(); i++)
{
sb = "Url: " + kvp.Key + " --- " + "Local KeyWord: " + kvp.Value[i] + Environment.NewLine;
data.Add(sb.ToString());
}
}
listBox1.DataSource = data;
}
The question is why i cant set the focus in any of the cases on the listBox items ?
In the first case in the constructor the focus i want it to be on the last item in the list and also each time im adding a new item so the focus will be on the last added item.
Most likely, the item is being selected, you just can't tell because a different control has the focus. There are a couple of different ways that you can solve this, depending on the design of your application.
For the first part of the question, you should set the Focus in the Page/Form Load event, since at the constructor level controls are under initialization process.
Set the focus to the ListView first whenever your form is displayed. The user typically sets focus to controls by clicking on them. However, you can also specify which controls gets the focus programmatically. One way of doing this is by setting the tab index of the control to 0 (the lowest value indicates the control that will have the initial focus). A second possibility is to use the following line of code in your form's Load event, or immediately after you set the Selected property:
listBox1.Select();
The problem with this solution is that the selected item will no longer appear highlighted when the user sets focus to a different control on your form (such as a textbox or a button).
For the second part of the question, selecting last added item in the ListBox, use the following code:
listBox1.SelectedIndex = listBox1.Items.Count - 1;
listBox1.SetFocus();
Looks like your ClearListBox method is actually a UpdateListBox method.
listBox1.DataSource = data;
listBox1.SelectedIndex = <index of newitem>;
// or
listBox1.SelectedItem = "text of new item";
listBox1.SetFocus();
If the new item is the last item, its index is listBox1.Items.Count - 1.

Categories

Resources