ComboBox reverting to index 0 at seemingly random - c#

I have an array of ComboBoxes, each with it's own DataSource which is set at the beginning and not messed with any further. Each ComboBox has some index (which is not 0) selected.
Now, I have a grid of Panels drawn on a Form. Each Panel is connected to it's own ComboBox. According to set rules, ComboBox can be drawn on the Form. Here are the rules:
On mouseClick connected-ComboBox is designated as selected-ComboBox. It was already drawn on mouseEnter event.
On mouseEnter selected-ComboBox is replaced with the connected-ComboBox.
On mouseLeave connected-ComboBox is replaced with selected-ComboBox.
Basically, it displays the last selected ComboBox, or the one you are currently hovering over.
When I started the program and started hovering my mouse above the Panels, different ComboBoxes were displayed. However, after some seemingly random time, their index will change to 0, displaying the item at said index.
Now, I only change the selectedIndex of the ComboBox in one place in my code, and that spot should not be executed during the test - and it is not, proven by placing a breakpoint that never triggers.
I can change the selectedIndex as the user using the ComboBox - but I don't do that, so that's out. I just hover over the Panels.
I managed to pause the program after it happened to examine the state of the altered ComboBox. SelectedItem, SelectedIndex and Text properties were all changed. The interesting part? SelectedIndexChanged event never fired.
I don't think this has to do anything with the code, but is some kind of strange behaviour of ComboBox.
What are the reasons for which the ComboBox might default to first index as selected one, not firing the SelectedIndexChanged in the process?
If nothing else, is there a way I could monitor the SelectedIndex property of the ComboBox in a way the code pauses if it changes (as though there was a breakpoint in the setter)?

Related

Changing selection of TabControl programatically works for content, but not for tab/header

I have a ListView that allows me to select items, which are then added to an ObservableCollection. This ObservableCollection is bound to a TabControl, so I get new tabs as I add items. What I would like is for each new tab to become selected and show its content automatically.
From a content perspective, this is working. I am able to see the newly-added item's content as expected, however from the looks of the TabControl itself, all tabs have been "deselected," or moved to the background.
Here's what I'm doing: (Note that I'm setting SelectedItem. I experience similar results when setting SelectedIndex or SelectedValue. Not sure what's best here.)
void MyCollection_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if (e.Action == NotifyCollectionChangedAction.Add)
{
List<MyClass> newStuff = e.NewItems.Cast<MyClass>().ToList<MyClass>();
if (newStuff.Count == 1)
myTabControl.SelectedItem = newStuff[0];
}
}
Using Console.WriteLine and the TabControl's SelectionChanged event, I can verify that the TabControl.SelectedIndex is changing as expected. With each new item however, all tabs appear to move to the background.
I always see the content for the new item, but I must manually click the tab in order for it to visually appear as the foreground tab.
Whenever I click the background tab that is supposed to already be in the foreground, my console often displays a redundant debug message.
For example, if I start with zero items in the collection and then add one, I get one background tab, one console message, and I see the item's content. If I click on the tab, it comes to the foreground and the SelectionChanged method fires(!!!), repeating the same console message while I stare at the same item content:
myTabControl now has SelectedIndex of 0
myTabControl now has SelectedIndex of 0
How can I both programmatically show the content of my new tab, and see that tab as the foreground tab?
The only way I can bring ANY tab to the foreground programmatically is by setting myTabControl.SelectedIndex = -1. Apparently this is not an option while the ObservableCollection contains items, so this forces the TabControl to move the first tab (content, header and all) to the foreground. What am I missing here?
Correction: With this method (setting SelectedItem) I do get my very first tab in the foreground, however creating tab #2 and all subsequent tabs deselects all tabs, while showing the content from the most recent addition.
Some off-by-one bug was occurring here.
The method MyCollection_CollectionChanged was in my View's code-behind (the .xaml.cs file) rather than in the ViewModel. Using the Snoop tool (snoopwpf.codeplex.com) I was able to determine that the index was being set out-of-range somehow. For example, if I added item #4, the item would be placed at index 3, and I would attempt to change to this index. My console log messages would say that the selected index was successfully changed to 3, however the Snoop tool would say the index is 4(!) while all four tabs appeared to be in the background. Truly bizarre. Other collection objects might throw an out-of-range exception, but not this TabControl.
When I discovered this off-by-one bug, I attempted to set the index not to the actual index, but to the index minus one. The result was not a fix, but expected behavior instead. If I tried to set the index to what it should be, it would land on index + 1, but if I tried setting it to index - 1, it would actually change it to index - 1. This meant I could never target the desired tab, but always go one to the left, or one to the right (out-of-range).
Rather than use the View's code-behind to dig the MyClass object out of the NotifyCollectionChangedEventArgs so that it could be used to change tabs (which probably violates the MVVM pattern in the first place), I decided to use the ViewModel to change tabs. This meant passing the TabControl to the ViewModel, so that it could to add to the collection and then immediately change tabs on the next line of code, like so:
MyCollection.Add(newThing);
_tabControl.SelectedItem = newThing;
Works like a charm! Keep this fix in mind if you ever see a TabControl with no tabs selected. The index change may be taking place in the wrong thread, or some such thing.

How to Insert the Cursor at the Beginning of Text in a Textbox Using WPF

I have a listbox which, when an item is selected, is used to populate a set of controls such as textboxes, radio buttons, and the like. What I want to do is cause the cursor to appear in the first textbox after the selected item is parsed into the respective controls. After spending time reading a number of posts here and researching on MSDN, I am still unable to accomplish this simple task.
In the code, I have txtInstName.Focus();. I have confirmed by checking the Keyboard.FocusedElement property that txtInstName does in fact have the focus. So how do I put the cursor at the beginning of the text in txtInstName? I've tried txtIns6tName.Select(0,0); but that does not insert the cursor where I want it.
Any ideas?
You can use the following property
MyTextBox.CaretIndex = someInt32;
this property gets or sets the insertion position index of the caret.

In Winforms, why is validation not being fired after leaving TextBox and entering a DataGridView?

I'm overriding the OnValidating event in a custom Winforms text box. I'm finding that if the text box (which is bound to an object) has focus and then I give a grid focus using the mouse, the OnValidating event doesn't always get fired. When I first give the grid focus, it gets fired fine. But, if put one of the grid's cell in edit (blinking cursor), from there on out it seems to not get fired when I go back between the text box and grid using the mouse. If I change focus using the tab key, the validating always gets fired. If I give focus to a non-grid control using the mouse, the validation is always getting fired.
I tried to recreate this functionality from scratch in a simple form and I can't recreate the problem. The grid I'm using in the setup where I'm getting the problem is a custom DataGridView with custom column types. I'm wondering if the grid is the problem. But, I don't see how it could affect the text box events. Any ideas?
It probably has to do with the CausesValidation property.
A control's validation is suppressed if focus is going to a control that has CausesValidation set to false. It's just a wild guess, but I'm thinking some control inside the grid has CausesValidation = false;
This property is meant for things like "Cancel" buttons, but can cause lots of confusion.

WPF Deleting item from listbox

I have a listbox in WPF that's bound to a ObservableCollection using the ItemSource property. This works fine, the correct items are shown.
The listbox (which contains a list of image names) has an event handler on the SelectionChanged event which updates the source of an Image control with the path to the selected image (effectively giving an image preview).
I have the following code to remove an item from the lisbox, on a button's click event:
if (lstLocal.SelectedIndex > -1)
{
localImages.RemoveAt(lstLocal.SelectedIndex);
}
localImages being the ObservableCollection and lstLocal being the ListBox.
However, when I remove the selected item this causes the SelectionChanged event to fire. My SelectionChanged event handler makes use of the SelectedIndex property on the listbox. I get the exeption Index was out of range. Must be non-negative and less than the size of the collection. , so I'm guessing that removing an item causes SelectedIndex to be set to something like null (or a negative number)?
Is there a way around this problem? I'm guessing there's a better way for me to remove items, or I need some sort of check on my SelectionChanged handler?
Wrap the code in your SelectionChanged handler in a
if (lstLocal.SelectedItem != null)
{
...
}
Ah, a classic annoyance of the ListBox control. When altering the bound collection, it can clear the selection and reset the scroll position to the top. It's truly irritating when you have to select items from a list and edit them piecemeal as part of a workflow.
You may want to maintain a "currently selected item" object reference when changing the list so that you can keep the selection if something changes behind the scenes. Then you can also make sure that if it exists, that it stays in view by scrolling back to that item using the ScrollIntoView method.
A SelectedIndex of -1 means nothing is selected, as you have already remembered. This is an ancient hold-over from pre-.NET, before the SelectedItem property existed. Nowadays SelectedItem will be null at the same time as SelectedIndex is -1.

WPF ListView does not raise SelectionChanged events after the first time the event is raised

I've created a prototype app with a Listview bound to an ObservableCollection programmatically through it's itemsource property. Everything was working well until a day ago when the ListView stopped raising SelectionChanged events after the first time the event is raised. Eg. Select a row in the ListView, SelectionChanged event is raised, UI selects the first row in the ListView no matter what you do, then any attempts to select a row have absolutely no effect on the ListView, either in terms of selecting the row clicked on, or raising events.
So far I've established that if I remove all superflous code from the window, it does not solve the problem. If I transplant the code to a new project, it does not solve the problem.
However, if I re-implement the same code by hand in a new project, the problem does not present, but the code seems identical when compared with Beyond Compare.
I also got the problem to partially disapate by clearing all selections from the listview inside the SelectionChanged event handler, which seems to resolve the issue, but means that rows never appear as selected in the Listview.
I'm at wit's end with this.
If you're using duplicate items with value types(include ref. type string also), this problem could arise as they compare the values. You can wrap your item in a class to show that the items are different. But I don't know why it worked in the new application you've created. May be you could've changed the itemssource.

Categories

Resources