Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ComboBox selection breaks when Items is updated (two bugs? check comments) #4048

Closed
Kermalis opened this issue May 31, 2020 · 11 comments · Fixed by #4659
Closed

ComboBox selection breaks when Items is updated (two bugs? check comments) #4048

Kermalis opened this issue May 31, 2020 · 11 comments · Fixed by #4659
Labels

Comments

@Kermalis
Copy link
Contributor

Kermalis commented May 31, 2020

The following xaml:

<ComboBox Items="{Binding MyItems}" SelectedItem="{Binding MySelection}"/>

The following code:

public IEnumerable<object> MyItems { get; }
private object _mySelection;
public object MySelection
{
	get => _mySelection;
	set
	{
		if (_mySelection != value)
		{
			_mySelection = value;
			UpdateMyItems(); // MyItems gets set
			OnPropertyChanged(nameof(MySelection)); // Fire MySelection first with INotifyPropertyChanged
			OnCollectionChanged(nameof(MyItems)); // Fire MyItems second with INotifyCollectionChanged
		}
	}
}

You get the following ComboBox:
image

If you swap the order, it works as intended.

Due to the order my code runs in, I cannot simply swap the order without breaking my programs, so I have been forced to make hacky workarounds in them. It should work both ways since SelectedItem is still the correct value. Even if SelectedItem does not change, but Items does change, it still breaks until a propertychanged event is fired even though the SelectedItem is in the new collection. A fix for this would greatly reduce the amount of redundant extra code being run on my side.

@Kermalis
Copy link
Contributor Author

Kermalis commented May 31, 2020

Just to be clear, I'm using INotifyCollectionChanged, but I think if you use INotifyPropertyChanged to change the MyItems object for another object, it still will not adapt to the SelectedItem. I think this affects all ItemsControl but I have only been using ComboBox in my programs where I've had to deal with this

@jmacato jmacato added the bug label May 31, 2020
@Kermalis Kermalis changed the title If ComboBox.Items is updated after SelectedItem, the combobox will have no selection If ComboBox.Items is updated after SelectedItem, the combobox will have no visible selection May 31, 2020
@Kermalis
Copy link
Contributor Author

Kermalis commented Jul 21, 2020

I know this isn't helpful but this is probably the most annoying bug in Avalonia and it's annoyed me for years now. I'm begging you to fix this before 0.10

Right now I'm making a model that has a ComboBox of string objects. If I update the items of the ComboBox, then the selection is hidden no matter what order I fire events and no matter if the old index is available in range of the new items. I have to manually click the empty ComboBox and select my item in the UI because it's not working in code-behind at all (I have no idea why, this is the first time). It's driving me crazy that something so simple does not work. I really don't know what to do about it other than come here and complain.

<ComboBox Items="{Binding SelectableItems}" SelectedIndex="{Binding Index}" />
private int _index = 0; // Default to first item works
public int Index
{
  get => _index;
  private set
  {
    if (value == -1)
    {
      _index = 0; // No -1 please I beg you, why would I ever want -1
      OnPropertyChanged(nameof(Index));
    }
    else if (value != _index)
    {
      _index = value;
      OnPropertyChanged(nameof(Index));
    }
  }
}
private IEnumerable<string> _selectableItems = new[] { "Default" };
public IEnumerable<string> SelectableItems
{
  get => _selectableItems;
  private set
  {
    _selectableItems = value;
    OnPropertyChanged(nameof(SelectableItems));
  }
}

private void UpdateItems(object[] items)
{
  // Setting selectable items sets the selected index to -1 for no reason
  if (items.Length == 0)
  {
    SelectableItems = new[] { "Default" };
  }
  else
  {
    SelectableItems = items.Select(o => o.ToString());
  }
  Index = 0; // No selection even though I'm telling it to select 0 here and in the setter
  /* Same nonsense if you fire in reverse order
  Index = 0;
  SelectableItems = items;
  */
}

Honestly what can I do?

@Kermalis Kermalis changed the title If ComboBox.Items is updated after SelectedItem, the combobox will have no visible selection ComboBox selection breaks when Items is updated (two bugs? check comments) Jul 21, 2020
@Kermalis
Copy link
Contributor Author

Kermalis commented Jul 21, 2020

The (different) bug in the above comment does not occur if you let the ComboBox successfully set your index to -1 and you change the index from -1 afterwards to what you want. Really, this is unnecessary (and will not work if you are using unsigned types to retrieve your value like I am in my real code), but I have yet another hacky workaround for this now (which is to have a conditional in my getter to return -1 instead of my unsigned value when this bug would occur).

@Gillibald
Copy link
Contributor

I think we might be able to get this to work.

The ItemsControl could use SelectedIndex = IndexOf(SelectedItem) when Items changes. That way one can add items and the selection isn't changing if the currently selected item is present in the Items collection.

@Kermalis
Copy link
Contributor Author

Something to that effect would definitely fix both of these issues, as long as it works that way for both CollectionChanged and PropertyChanged

@Kermalis
Copy link
Contributor Author

Kermalis commented Aug 9, 2020

Something with Items is really wrong. This may be related to what's causing #4461

@grokys
Copy link
Member

grokys commented Aug 10, 2020

@Kermalis taking a look at this now. Got a few questions:

  1. Which version of Avalonia?
  2. What does OnCollectionChanged(nameof(MyItems)); do? Is MyItems a custom collection class that implements INotifyCollectionChanged and OnCollectionChanged is raising the CollectionChanged event on that? If so, with what Action?
  3. ComboBox selection breaks when Items is updated (two bugs? check comments) #4048 (comment) is a different problem, correct? It would be better to open a separate issue for that

I really don't know what to do about it other than come here and complain.

Opening an issue here is definitely the correct thing to do! You're not complaining ;) We can't fix issues if we don't know about them

One this that would really help me would be to create a repository which demonstrates the problem with the last code possible. I'll try to work out the exact problem from the information you've provided here in the meantime.

@grokys
Copy link
Member

grokys commented Aug 10, 2020

Maybe @Gillibald has understood the problem better than me. Is the issue just that:

  • You assign Items and SelectedItem
  • You change Items to a new collection which also contains SelectedItem
  • SelectedItem isn't preserved?

@JaggerJo
Copy link
Contributor

Maybe @Gillibald has understood the problem better than me. Is the issue just that:

  • You assign Items and SelectedItem
  • You change Items to a new collection which also contains SelectedItem
  • SelectedItem isn't preserved?

I think so :)

@Gillibald
Copy link
Contributor

Y that is how I understood it

@Kermalis
Copy link
Contributor Author

Kermalis commented Aug 10, 2020

Yes, that's the issue. SelectedIndex is set to -1 when the collection changes. Also my other comment you linked to is indeed another issue, #4472.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants