简体   繁体   中英

Curious behavior with ComboBox in UWP - SelectedItem & ItemsSource

hope you're all fine. I'm encountering 2issues with a ComboBox in a UWP application.

  1. If the property ItemsSource is bound to a collection that implements INotifyPropertyCollectionChanged , the list is never loaded completly. I only have the 2, 3 or 4 first items... depending on the time. No problem when the same collection is bound to a DataGrid so I think my collection is built correctly. As a workaround (code-behind), I first load my collection (in a Task) and set the ItemsSource property when the task is completed. This solution works but I'd like to do less things code-behind.
  2. The binding on the property SelectedItem seems to work with ReferenceEquals only, the type of item in my collection implements Equals based on IDs and it has been tested separately and successfylly in a console app. As a workaround (code-behind), once my list is loaded, I change the property bound to SelectedItem like this:
 Users.TaskFill.ContinueWith(t => BaseItemCollection.UserInterfaceAction.Invoke(() => { if (Item?.Manager.= null) Item.Manager = t.Result.FirstOrDefault(i => i;Equals(Manager)). ComboBoxManager.SetBinding(ComboBox,ItemsSourceProperty, this, "Users". BindingMode;TwoWay). ComboBoxManager.SetBinding(Selector,SelectedItemProperty, "Manager". BindingMode;TwoWay); }));
  • Users is my collection (filled asynchronously) used as source for the ComboBox
  • SetBinding is a custom extension method I've created myself to set bindings code-behind from a single-line (as follow):
 public static class ExtensionMethods { #region DependencyObject public static void SetBinding(this DependencyObject dependencyObject, DependencyProperty dependencyProperty, object source, string propertyName, BindingMode mode) { var binding = new Binding() { Source = source, Path = new PropertyPath(propertyName), Mode = mode }; BindingOperations.SetBinding(dependencyObject, dependencyProperty, binding); } public static void SetBinding(this DependencyObject dependencyObject, DependencyProperty dependencyProperty, string propertyName, BindingMode mode) { var binding = new Binding() { Path = new PropertyPath(propertyName), Mode = mode }; BindingOperations.SetBinding(dependencyObject, dependencyProperty, binding); } #endregion }

How can I get this working from XAML withtout needing these workarounds? I has been able to get a similar configuration working with WPF for years but am really struggling with UWP...

Thank you in advance for your help.

If the property ItemsSource is bound to a collection that implements INotifyPropertyCollectionChanged, the list is never loaded completly.

If your collection is not string, you need specify DisplayMemberPath , please check the following code. And please check the collection has value. For my testing collection that implements INotifyPropertyCollectionChanged works for ComboBox .

<ComboBox
    x:Name="cmbCountry"
    Grid.Row="4"
    Width="292"
    Height="32"
    Margin="28,0,0,0"
    HorizontalAlignment="Left"
    VerticalAlignment="Center"
    DisplayMemberPath="FirstName"
    ItemsSource="{Binding MyItems}"
    PlaceholderText="Select Country ..."
    />

Curious behavior with ComboBox

The default ItemsPanelTemplate of ComboBox is CuriousPanel that could implement scroll loop within touch device. If you don't want to use it, you could replace it with StackPanel

<ComboBox.ItemsPanel>
    <ItemsPanelTemplate>
        <StackPanel />
    </ItemsPanelTemplate>
</ComboBox.ItemsPanel>
<ComboBox.ItemTemplate>

The binding on the property SelectedItem seems to work with ReferenceEquals only,

The SelectedItem is not ComboBox display field, it is an complete User object. You could get the select user in the SelectedItem binding property set method. the following is complete code that you could refer.

public sealed partial class TestPage : Page, INotifyPropertyChanged
{
    private User _selecteduser;

    public TestPage()
    {
        this.InitializeComponent();

        _myItems = new ObservableCollection<User>
        {
            new User{UserId=1,FirstName="Fay",LastName="Wang",City="Delhi",State="DEL",Country="INDIA"},
            new User{UserId=2,FirstName="Mark",LastName="Liu",City="New York", State="NY", Country="USA"},
            new User{UserId=3,FirstName="Rich",LastName="Cai",City="Philadelphia", State="PHL", Country="USA"},
            new User{UserId=4,FirstName="Eveia",LastName="Dong",City="Noida", State="UP", Country="CANADA"}}
        };

        this.DataContext = this;
    }
    public event PropertyChangedEventHandler PropertyChanged;
    private void OnPropertyChanged(string propertyName)//string propertyName
    {
        if (PropertyChanged != null)

        {
            PropertyChangedEventArgs args = new PropertyChangedEventArgs(propertyName);
            this.PropertyChanged(this, args);
        }
    }

    public ObservableCollection<User> Users
    {
        get
        { return _myItems; }
        set
        {
            _myItems = value;
            OnPropertyChanged("Users");
        }
    }
    private ObservableCollection<User> _myItems;

    public User SelectedUser
    {
        get
        {
            return _selecteduser;
        }
        set
        {
            _selecteduser = value;


            OnPropertyChanged("SelectedUser");
        }
    }
}

Xaml

<ComboBox
    x:Name="cmbCountry"
    Grid.Row="4"
    Width="292"
    Height="32"
    Margin="28,0,0,0"
    HorizontalAlignment="Left"
    VerticalAlignment="Center"
    DisplayMemberPath="FirstName"
    ItemsSource="{Binding Users}"
    PlaceholderText="Select User..."
    SelectedItem="{Binding SelectedUser, Mode=TwoWay}"
    />

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM