Любопытное поведение с ComboBox в UWP - SelectedItem & ItemsSource - PullRequest
0 голосов
/ 26 мая 2020

надеюсь, у вас все в порядке. Я столкнулся с двумя проблемами с ComboBox в приложении UWP.

  1. Если свойство ItemsSource привязано к коллекции, которая реализует INotifyPropertyCollectionChanged , список будет никогда не загружался полностью. У меня есть только 2, 3 или 4 первых элемента ... в зависимости от времени. Нет проблем, если та же коллекция привязана к DataGrid, поэтому я думаю, что моя коллекция построена правильно. В качестве обходного пути (кода программной части) я сначала загружаю свою коллекцию (в Задаче) и устанавливаю свойство ItemsSource, когда задача завершена. Это решение работает, но я хотел бы делать меньше кода программной части.
  2. Привязка свойства SelectedItem, похоже, работает только с ReferenceEquals, тип элемента в моей коллекции реализует Equals на основе идентификаторов и имеет были протестированы отдельно и успешно в консольном приложении. В качестве обходного пути (код программной части), как только мой список загружен, я изменяю свойство, привязанное к SelectedItem, следующим образом:
        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 - моя коллекция (заполненная асинхронно), используемая в качестве источника для ComboBox
  • SetBinding - это настраиваемый метод расширения, который я создал сам, чтобы установить привязку кода программной части из одной строки (как показано ниже):
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
}

Как я могу заставить это работать из XAML, не прибегая к этим обходным путям? Мне удалось получить аналогичную конфигурацию, работающую с WPF в течение многих лет, но я действительно борюсь с UWP ...

Заранее благодарю вас за вашу помощь.

1 Ответ

1 голос
/ 26 мая 2020

Если свойство ItemsSource привязано к коллекции, которая реализует INotifyPropertyCollectionChanged, список никогда не загружается полностью.

Если ваша коллекция не является строкой, вам нужно указать DisplayMemberPath, проверьте следующий код. И убедитесь, что коллекция имеет ценность. Для моей тестовой коллекции, которая реализует INotifyPropertyCollectionChanged, работает для 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 ..."
    />

Любопытное поведение с ComboBox

По умолчанию ItemsPanelTemplate из ComboBox - CuriousPanel, который может реализовать прокрутку l oop на сенсорном устройстве. Если вы не хотите его использовать, вы можете заменить его на StackPanel

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

Привязка свойства SelectedItem, похоже, работает только с ReferenceEquals,

SelectedItem - это не поле отображения ComboBox, это полный объект User. Вы можете получить выбранного пользователя в методе набора свойств привязки SelectedItem. ниже приведен полный код, на который вы можете ссылаться.

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}"
    />
...