I want to fill a ComboBox when the GotFocus event is triggered.
I tried to fill my ComboBox in the GotFocus event, but it doesn't seem to work.
Items are visible in the dropdown menu but when I want to select one of them the collection is cleared
Click on the ComboBox :
Try to select the first item :
Here is my code :
Private Sub agence_GotFocus(sender As Object, e As RoutedEventArgs) Handles agence.GotFocus
strsql = "Select age_cpt, age_abrege + ' ' + age_nom as age_abregenom from gen_agence where age_soc = " & societe.SelectedValue
Dim da As New SqlDataAdapter(strsql, connSQLServer)
Dim ds As New DataSet()
da.Fill(ds, "t")
agence.ItemsSource = ds.Tables("t").DefaultView
agence.DisplayMemberPath = "age_abregenom"
agence.SelectedValuePath = "age_cpt"
End Sub
How can I manage that ?
I don't want to use MVVM.
The problem is that this event fires multiple times.
Below I will show a demo code in Sharpe (I do not have VB.Net loaded in the Studio), but the code is simple, you should repeat it yourself in BASIC without any problems.
private void OnGotFocus(object sender, RoutedEventArgs e)
{
Debug.WriteLine(++eventCount);
ComboBox comboBox = (ComboBox)sender;
// Try the second option by excluding the following line
if (comboBox.ItemsSource == null)
comboBox.ItemsSource = "First,Second,Third".Split(',');
}
The code should check for null so as not to reconnect the collection.
Commenting out this line will reproduce your problem.
After launching for execution and trying to select an item, you will see in the "Output" window that the event has occurred several times.
It looks like changing the list at the moment of its expansion somehow breaks the logic of the internal bindings of the ComboBox.
There are several ways to fix this, but for this we need to know why you chose this initialization of the element - when the focus is on it.
Several ways:
Nulling the source before assigning a new collection.
private void OnGotFocus(object sender, RoutedEventArgs e)
{
Debug.WriteLine(++eventCount);
ComboBox comboBox = (ComboBox)sender;
comboBox.ItemsSource = null;
comboBox.ItemsSource = "First,Second,Third".Split(',');
}
Setting the collection once when loading the ComboBox.
<ComboBox Loaded="OnLoaded"/>
private void OnLoaded(object sender, RoutedEventArgs e)
{
Debug.WriteLine(++eventCount);
ComboBox comboBox = (ComboBox)sender;
comboBox.ItemsSource = "First,Second,Third".Split(',');
}
Other implementation options are possible, but I need to know more details about your task in order to choose how best to do it.
Answer to the additional question:
Nulling the source before assigning a new collection is a good idea. Now I can move my mouse over the values in the dropdown menu. However, when I select a value, the field is cleared.
If it is not a string array, then the selection can be cleared.
When you enter the event, you recreate the tables each time.
And the rows of these tables, although they are the same in content, will not be considered the same instance.
You selected a row from one table, then you rewrote the source, and the new source does not have this row.
The selection is reset.
I already wrote above that in order to choose the optimal solution, I need more details of your problem.
The way you have chosen to initialize the list is very unusual.
Each time you work in the ComboBox, you make queries to the database three to four times.
I have never met such a implementation and I do not understand its meaning.
Explain why do you need this?
I found a way to do what I wanted : Use the DropDownOpened event instead of GotFocus
Private Sub agence_DropDownOpened(sender As Object, e As EventArgs) Handles agence.DropDownOpened
'... Fill the ComboBox
End Sub
Fill a ComboBox in the GotFocus event works in VBA but not in VB.Net.
In VB.Net I can't use GotFocus cause the event is triggered multiple time. It's triggered when :
I open the ComboBox
I pass my mouse over the items
I select an item
Moreover, this can trigger a stackoverflow exception.
I know it's better to fill a ComboBox before open it.
I am in an application migration procedure and I cannot afford to change the entire code structure.
Use the DropDownOpened event was the best option in my case.
Thanks to the people who helped me find a solution.
Related
I have a winform that includes a DataGridView and a Button among a few other controls. I'm adding and removing datagridview's columns and rows manually. A RefreshContent() method iterates through some arrays and update the datagridview through the following
datagridview.Columns[i].Name = somestring;
or
datagridview.Rows.Add(someobject);
RefreshContent() is called in an event handler OnButtonClick, bond to the button I mentioned above.
Problem is that I click the button and nothing happens to the datagridview, until I interact with another control. It's like the datagridview shows data update a step behind...I even tried adding this to the end of my event handler:
private void OnButtonClick(object s, EventArgs e)
{
// .... some code
RefreshContent();
var ds = dataGridView1.DataSource;
dataGridView1.DataSource = null;
dataGridView1.DataSource = ds;
dataGridView1.Refresh();
}
To no avail. I'm not very good at winforms.
The problem was the RefreshContent calls another method that updates an array that is passed into RefreshContent as an argument, without a ref. RefreshContent doesn't see the change. Therefore it does not really refresh the datagridview.
Remember folks, arrays are typically passed in by value, not reference, unless with ref (c#)
I have a gridview and a repositorycheckedit column, I want it to change its value only when it is double-clicked, and prevent it from changing with a single click.
thanks
I think you can achieve this in the following way:
Make the column read-only. This will disable the native behavior of allowing a click to edit the value.
colCheck.OptionsColumn.Readonly = true;
Add an in-place repository item of a check box and assign it to the column. If this column is a boolean, this is normally unnecessary (check is the default control type for a boolean), but this will help for the next step
Fire the double-click event on the repository item and alter the check property as follows:
~
private void repositoryItemCheckEdit1_DoubleClick(object sender, EventArgs e)
{
Foo f = gridView1.GetFocusedRow() as Foo;
f.Check = !f.Check;
gridView1.RefreshData();
}
Let me know if that helps.
Dotnet, C#, VS2013
I have a method that retrieves the selected item in a combobox (CBSpecies). The method is called when a button is clicked. My problem is that no matter what I select, the item found by the method is always the first one (default set when I populate the combobox). I have a console application with exactly the same method and it works fine.
private void GetSelectedSpecies()
{
//EurostatSpeciesName = "Fish and Chips";
//EurostatSpeciesName = CBSpecies.SelectedIndex.ToString();
//return;
// CBSpecies.SelectedIndex = 3;
String MySpecies = CBSpecies.SelectedItem.ToString();
for (int i = 0; i < MaxSpecies; i++)
if (SpeciesArray[i].SpeciesName == MySpecies)
{
EurostatSpecies = SpeciesArray[i].SpeciesCode;
EurostatSpeciesName = SpeciesArray[i].SpeciesName;
break;
}
}
Added the following note: I think the problem is that I populate and initialize the combobox in the Page_Load method, so when the button does a postback, it resets everything since it reloads the page. This would not happen in the console version. I tried putting the whole setup (populating the species array, then populating the combobox from that, then setting the first combobox item as the default) by using: if (!Page.IsPostBack) as a condition, but then the app throws a null exception when the button is clicked.
Try .SelectedNode and see if that works.
Solved using a suggestion from this post:
https://www.telerik.com/forums/selectedvalue-lost-on-postback-in-dynamically-added-user-controls
The method referred in the question was moved into:
protected void Page_Init(object sender, EventArgs e)
{}
Page_Init is not created automatically, so must be manually added. Once the combobox checking method is put there, the selection is persistent.
Your combobox is a so-called dynamic control. I.e. you're building it in the code-behind instead of in markup.
Dynamic controls must be initialized prior to the viewstate in order to plug them into the ASP.NET Page Lifecycle events.
As you've found out, Page_Init is the correct place to initialize such a control. You can find more info on the subject here
I have a DataGridView populated from a database.
I am trying to get the contents of the row that is selected on the RowEnter event. I have set the grid's selection mode to FullRowSelect
I have tried the following:
int orderId = (int)dgUnprocessedCards.Rows[dgUnprocessedCards.SelectedCells[0].RowIndex].Cells[0].Value;
this keep throwing the error
Index was out of range. Must be non-negative and less than the size of the collection.
Any help is appreciated.
I've just tried this in a sample datagridview app and it works just fine so there must be something going on which you haven't told us about.
First thing to do is break your one big statement up into discrete smaller statements so you can see exactly where the failure is.
You can rewrite the code above to something like this for debugging purposes:
var cellindex = dgUnprocessedCards.SelectedCells[0].RowIndex;
var cellcollection = dgUnprocessedCards.Rows[cellindex].Cells[0];
int orderId = (int)dgUnprocessedCards.Value;
Also, you should be able to do the following to achieve what you want:
int orderId = (int)dataGridView1.SelectedRows[0].Cells[0].Value;
That uses the SelectedRows collection which is a little bit more concise and I'd say the more usual way of accessing selected items from the datagridview.
Finally, you probably want to do checking around your cast of the value, since the Value might not necessarily be an int. Something like:
int orderid;
if (!int.TryParse(cellcollection.Value.ToString(), out orderid))
{
// Some logic to deal with the fact that Value was not an int
}
When is the SelectionChanged event raised?
Now - as you mention, your selection changed event fires while loading data into the grid. This doesn't seem to cause a problem in my test version but could be part of your issue.
Why this happens should not be related to the type of data source you are using, but to when you attach the selection changed eventhandler. This is because databinding causes a selection changed event to be raised.
If you add an eventhandler for the DataBindingComplete event and attach your SelectionChanged or RowEnter eventhandlers there, you should not see the handler invoked during databinding.
void dataGridView1_DataBindingComplete(object sender, DataGridViewBindingCompleteEventArgs e)
{
this.dataGridView1.RowEnter += new System.Windows.Forms.DataGridViewCellEventHandler(this.dataGridView1_RowEnter);
this.dataGridView1.SelectionChanged += new System.EventHandler(this.dataGridView1_SelectionChanged);
}
Note that you will need to delete the designer generated event attachment and reference the designer generated methods for this to work.
This also works:
int orderId = (int)dgUnprocessedCards.SelectedCells[0].OwningRow.Cells[0].Value;
You can get specific column value when you click on Datagridview column
private void DataGridview_CellContentClick(object sender,
DataGridViewCellEventArgs e) { int col = e.ColumnIndex; int row =
e.RowIndex; Var value=DataGridview.Rows[row].Cells[col].Value; }
What I tried to do worked fine but the binding was calling the selection changed event. So I done what David Hall suggested (attaching and detaching the event) and I also put it in a try catch block and now it works perfectly.
I want to use a CheckedListBox in an application where each item in the ListBox is the name of a folder on my hard drive and for the purpose of reading and writing text files to and from each of these folders I want to ensure that one and only one item (a folder) can be selected at any one time in the CheckedListBox
How can I achieve this via code in C#?
Thanks for reading :-)
Edit \ Update - 22/10/2010
Thanks to all who took the time to reply - especially Adrift whose updated code as requested is working perfectly.
I do appreciate what some commentators said about my usage of a checkedlistbox in this manner, however I feel it suits my purposes perfectly in that I want there to be no doubt whatsoever as to where the text files will be read from and written to.
All the best.
I agree with the comments that radio buttons would be the usual UI element when only a single item is 'checked', but if you want to stick with a CheckedListBox for your UI, you can try something like this:
private void checkedListBox1_ItemCheck(object sender, ItemCheckEventArgs e)
{
CheckedListBox.CheckedIndexCollection checkedIndices = checkedListBox1.CheckedIndices;
if (checkedIndices.Count > 0 && checkedIndices[0] != e.Index)
{
checkedListBox1.SetItemChecked(checkedIndices[0], false);
}
}
You also might want to set CheckOnClick to true for the CheckedListBox.
Edit
Updated the code per your comment to deselect an item if it is unchecked. The problem is that unchecking the previously checked item causes the event to fire again. I don't know whether there is a standard way to handle this, but in the code below, I detach the handler before calling SetItemCheck, then reattach the handler. It seems like a clean way to handle this, and it works. If I find that there is a recommended way to handle this, I will update my answer.
HTH
private void checkedListBox1_ItemCheck(object sender, ItemCheckEventArgs e)
{
CheckedListBox.CheckedIndexCollection checkedIndices = checkedListBox1.CheckedIndices;
if (checkedIndices.Count > 0)
{
if (checkedIndices[0] != e.Index)
{
// the checked item is not the one being clicked, so we need to uncheck it.
// this will cause the ItemCheck event to fire again, so we detach the handler,
// uncheck it, and reattach the handler
checkedListBox1.ItemCheck -= checkedListBox1_ItemCheck;
checkedListBox1.SetItemChecked(checkedIndices[0], false);
checkedListBox1.ItemCheck += checkedListBox1_ItemCheck;
}
else
{
// the user is unchecking the currently checked item, so deselect it
checkedListBox1.SetSelected(e.Index, false);
}
}
}