By doing either an Items.Add() or Items.AddRange() call, is there a way to automatically set SelectedIndex to 0 if it is set to -1?
My first guess would be to create a new event that listens to a change in the Items property.
If you are not willing to set SelectedIndex = 0 after the Add (which I personally do not think is too tedious...but to each their own), then you could try creating a custom control that will do this for you. However, there is no event for when an item is added, so you would have to create a new method.
public class MyComboBox: ComboBox
{
public void AddItem(object item)
{
base.Items.Add(item);
if (SelectedIndex == -1)
SelectedIndex = 0;
}
}
Ultimately, this seems like a bit of overkill, but it is doable this way.
Related
I have a DataGridView on a form that is databound to a list of objects. I have several column including a checkbox column. The requirement is that only one item in the collection may have the databound boolean property set to true at a given time. The data object is named Interval, the Property in question is Program:
public bool Program
{
get { return _program; }
set
{
if (value)
{
Parent.Intervals.Except(new[] { this }).ForEach(interval => interval.Program = false);
}
_program = value;
OnPropertyChanged();
}
}
My expected behavior would be that clicking the databound checkbox would set the Program property for one instance of Interval to true, and in so doing, would set the Program property on all other instances to false. That is indeed what happens, however the datagridview does not update correctly. It will leave previous checkboxes checked and after tabbing off the cell or mousing over another checkbox, then it will update that particular checkbox.
How can I get the datagrid view to accurately show the state of my objects. I trusted you, DataGridView! You lied to me. I... I can never trust anything you say again.
The solution is to use a BindingList instead. When binding to a regular List or other collection (that is not of a Binding specific bent), only the selected rows values are updated. BindingList, however, has the added benefit that properties from all of the items are updated, not just the selected Row. Keep in mind that if you are using something like AddRange (from List) you may have to modify your code to add items either at initialization time or via a loop, as BindingList does not have an AddRange method (although an extension method could be written).
Try this
private void dgv_CellValueChanged(object sender, DataGridViewCellEventArgs e)
{
if ((bool)dg.Rows[e.RowIndex].Cells[CheckBoxColumnIndex].Value)
{
var rows = (from DataGridViewRow row in Clients.Rows
where row.Index != e.RowIndex
select row).ToArray();
foreach(DataGridViewRow row in rows)
{
row.Cells[CheckBoxColumnIndex].Value = false;
}
}
}
I have a ComboBox bound to an ObservableCollection of tbPublications which populates as it should. I then select a row from a DataGrid which fires another Create form in which I insert a new record into tbPublications, all good.
When I close said create form and return to my ComboBox form I am clearing and re-reading in the one new item to my ObservableCollection, returning the user to the item they've just created. The ComboBox then displays the one item from my newly populated collection, all good.
My problem is that on returning to my ComboBox form, the new publication is not set as selected item in the ComboBox display, the user has to click the ComboBox then select the item.
I can't use SelectedIndex = "0" in my view XAML as I want to show the whole ObservableCollection in my ComboBox on page load.
Is there any way to use a method in the ViewModel maybe to solve this issue, something maybe such as..
private void SetSelectedIndex()
{
if (MyObservableCollection.Count == 1)
{
//Set selected indexer to "0";
}
}
Found a solution to this, not sure if it's the cleanest 'MVVM' solution...
After reading in my ObservableCollection I invoke this method:
if (_ModelPublicationsObservableList.Count == 1)
{
SelectedPublication = _ModelPublication;
SetSelectedIndex();
}
Here's the method which gets the current main window and sets the SelectedIndex:
private void SetSelectedIndex()
{
ArticlesDataGridWindow singleOrDefault = (ComboBoxWindow)Application.Current.Windows.OfType<ComboBoxWindow>().SingleOrDefault(x => x.IsLoaded);
singleOrDefault.comboBox1.SelectedIndex = 0;
}
Did you consider using the SelectedItem property of combobox? You can bind the selected item property of combobox to get or set the selected item.
XAML
<ComboBox ItemsSource="{Binding Path=Publications}" SelectedItem="{Binding Path=SelectedPublication, Mode=TwoWay}" />
ViewModel
public class ItemListViewModel
{
public ObservableCollection<Publication> Publications {get; set;}
private Publication _selectedPublication;
public Publication SelectedPublication
{
get { return _selectedPublication; }
set
{
if (_selectedPublication== value) return;
_selectedPublication= value;
RaisePropertyChanged("SelectedPublication");
}
}
}
If you want to set the selected item from View model,You can set the SelectedPublication property as-
SelectedPublication = Publications[0];
Or you can locate the required item in the Publications collection and assign it to SelectedPublication property.
Add UpdateSourceTrigger=PropertyChanged to your binding.
SelectedItem={Binding Path=SelectedPublication, Mode=TwoWay}, UpdateSourceTrigger=PropertyChanged}
When I databind my GridView to an ObservableCollection, the first item of the collection is automatically selected. The SelectionMode property of the GridView is set to multiple. Is there some way to prevent this auto-selection? Or on what event should I listen so that I can reset the SelectedIndex of the GridView back to -1?
Set the IsSynchronizedWithCurrenItem property to false on the gridview in xaml
There is acutally a pretty simple solution. I set the SelectionMode of the GridView to None in the XAML. Then, when the page is created, I change the SelectionMode to Multiple.
publicPage()
{
this.InitializeComponent();
itemListView.SelectionMode = ListViewSelectionMode.Multiple;
}
However, the problem I am having seems to be caused by my own program. This is a workaround for the issue I am having, the autoselection is not the default behavior.
http://social.msdn.microsoft.com/Forums/en-US/winappswithcsharp/thread/da7e9f3b-9a3e-47ca-8223-b50539293f5f
My situation is the opposite. I have a GridView that was bind to an ObservableCollection, and I wanted the 1st item to be selected but it was not! I figured out why that was the case though. There are 2 ways to generate my ObservableCollection and depending on which method I chose, the 1st item is either selected or not.
for example, I have a variable ItemList in my viewmodel which I bind to my GridView
public ObservableCollection<Item> ItemList { get; private set; }
Method 1 (nothing selected)
public void getData()
{
var myList = // get your list here
for (int i = 0; i < myList.Count; i++)
{
this.ItemList.add(myList[i]);
}
}
Method 2 (1st item automatically selected)
public void getData()
{
var myList = // get your list here
this.ItemList = myList
}
In a ComboBox there are some items which have to be enabled and some which have to be disabled (and visible).
At first the ComboBox ItemsSource is set:
comboBoxMachine.ItemsSource = machineList;
where comboBoxMachine is a ComboBox and machineList is a List<Machine> (Machine is a custom object)
Later a condition for each machine from the list has to be checked and in case it is fulfilled the appropriate item from the ComboBox has to be disabled.
Below is the combination of code/pseudocode of the logic:
private void modifyMachineComboBoxItems()
{
foreach (Machine mch in machineList)
{
if (constructionSiteSchedule.ReservationMachinePeriods.Count(x => x.MachineId == mch.Id) > 0) //if this condition is fulfilled, it should be not possible to select the machine from the comboBoxMachine
{
int currentPosition = machineList.IndexOf(mch);
disable the element from the comboBoxMachine at position currentPosition;
}
}
}
What I haven't figured out so far is how to disable the element from the ComboBox at given position so I would be very thankful if anyone could modify the code above such that the ComboBox items for machines that satisfy the condition are disabled.
You should just have boolean property on your machine that corresponds to whether the item is enabled, in your ComboBox.ItemContainerStyle you can bind IsEnabled to that property, then when you want to disable the item just set the property on the machine to false.
Alternatively you could use the ItemContainerGenerator (which you really should not):
var item = comboBoxMachine.ItemContainerGenerator.ContainerFromIndex(currentPosition) as ComboBoxItem;
item.IsEnabled = false;
(You do not need to get the position first by the way as there also is a ContainerFromItem method, also see the comment below)
Hey. I've got the following code that populates my list box
UsersListBox.DataSource = GrpList;
However, after the box is populated, the first item in the list is selected by default and the "selected index changed" event fires. How do I prevent the item from being selected right after the list box was populated, or how do I prevent the event from firing?
Thanks
To keep the event from firing, here are two options I have used in the past:
Unregister the event handler while setting the DataSource.
UsersListBox.SelectedIndexChanged -= UsersListBox_SelectedIndexChanged;
UsersListBox.DataSource = GrpList;
UsersListBox.SelectedIndex = -1; // This optional line keeps the first item from being selected.
UsersListBox.SelectedIndexChanged += UsersListBox_SelectedIndexChanged;
Create a boolean flag to ignore the event.
private bool ignoreSelectedIndexChanged;
private void UsersListBox_SelectedIndexChanged(object sender, EventArgs e)
{
if (ignoreSelectedIndexChanged) return;
...
}
...
ignoreSelectedIndexChanged = true;
UsersListBox.DataSource = GrpList;
UsersListBox.SelectedIndex = -1; // This optional line keeps the first item from being selected.
ignoreSelectedIndexChanged = false;
Well, it looks like that the first element is automatically selected after ListBox.DataSource is set. Other solutions are good, but they doesn't resolve the problem. This is how I did resolve the problem:
// Get the current selection mode
SelectionMode selectionMode = yourListBox.SelectionMode;
// Set the selection mode to none
yourListBox.SelectionMode = SelectionMode.None;
// Set a new DataSource
yourListBox.DataSource = yourList;
// Set back the original selection mode
yourListBox.SelectionMode = selectionMode;
i using the following, seems to work for me:
List<myClass> selectedItemsList = dataFromSomewhere
//Check if the selectedItemsList and listBox both contain items
if ((selectedItemsList.Count > 0) && (listBox.Items.Count > 0))
{
//If selectedItemsList does not contain the selected item at
//index 0 of the listBox then deselect it
if (!selectedItemsList.Contains(listBox.Items[0] as myClass))
{
//Detach the event so it is not called again when changing the selection
//otherwise you will get a Stack Overflow Exception
listBox.SelectedIndexChanged -= listBox_SelectedIndexChanged;
listBox.SetSelected(0, false);
listBox.SelectedIndexChanged += listBox_SelectedIndexChanged;
}
}
set IsSynchronizedWithCurrentItem="False" and Also SelectedIndex=-1 and every thing should work for you
If you just want to clear the selected value, you can use ClearSelected after you set the DataSource. But if you dont want the event to fire, then you'll have to use one of Joseph's methods.
Perhaps in DataSourceChanged you could check the state of SelectedIndex, if your lucky you could then just force SelectedIndex = -1.