通用应用程序 - 加载组合框'ItemsSource async会产生奇怪的行为

时间:2015-01-28 18:32:02

标签: c# xaml windows-phone-8.1 winrt-xaml win-universal-app

在使用通用应用程序(目前只在WP8.1版本上)时,我偶然发现了以下奇怪的事情。

我有一个ComboBox,它所在的UserControl(位于WindowsPhone项目中)绑定到共享项目中的VM。 ItemsSource和SelectedItem都绑定到VM中各自的属性。

运行应用程序时,当您选择除第一个项目之外的任何项目时,它运行正常。但是,当我选择第一个项目时,ComboBox中显示的字符串显示VM的.ToString() - 方法而不是......

(顺便说一下,它只是一个简单的List<string>,所选项目是string。它不会比这简单得多:p)

我已经创建了一个示例应用程序,其中只包含此Combobox和VM。我能够重现这一点,我异步填写绑定到ItemsSource的属性的那一刻。从同步方法执行时,它可以工作。但是从异步方法填充它会产生上述问题。

一些屏幕截图:

第一个显示应用程序何时加载。集合更改时,将选择列表的第一个元素。它显示在这里:

After is app loaded

当您单击ComboBox时,您可以像往常一样查看其项目: enter image description here

假设你点击第一个以外的任何元素,你仍然会得到正常的行为: enter image description here

到目前为止,这很正常。现在单击第一个项目。你得到这个: enter image description here

...

我尝试了各种各样的事情,比如把它作为一个对象列表而不仅仅是字符串。将转换器添加到绑定对象,仅用于调试目的,仅显示实际的字符串值。我不知道绑定的SelectedItem如何以及为什么突然显示ComboBox的DataContext ...

您可以在此处下载示例应用: http://1drv.ms/1DhklCQ (不包含二进制文件,只包含代码)

有人有任何想法吗?


编辑:重现此问题所需的代码:

创建一个空白的通用商店应用(8.1)。 在WindowsPhone项目中,MainPage.xaml文件: 我添加了一个简单的组合框,并捕获Loaded事件。

<ComboBox ItemsSource="{Binding Items}" SelectedItem="{Binding SelectedItem}" />

在它的代码背后。我已将DataContext分配给VM。在Loaded事件中,我异步调用VM.LoadData()

private VM _vm = new VM();
public MainPage()
{
    this.InitializeComponent();
    this.DataContext = _vm;
}

private async void Page_Loaded(object sender, RoutedEventArgs e)
{
    await _vm.LoadDataAsync();
}

VM对象定义如下:

public class VM : INotifyPropertyChanged
{
    private List<string> _items;
    public List<string> Items
    {
        get { return _items; }
        set
        {
            _items = value;
            _selectedItem = _items.FirstOrDefault();
            RaisePropertyChanged("Items");
            RaisePropertyChanged("SelectedItem");
        }
    }

    private string _selectedItem;
    public string SelectedItem
    {
        get { return _selectedItem; }
        set
        {
            _selectedItem = value;
            RaisePropertyChanged("SelectedItem");
        }
    }

    public VM()
    {
    }

    public async Task LoadDataAsync()
    {
        this.Items = new List<string>()
        {
            "a",
            "b",
            "c",
            "d",
            "e",
            "f",
        };
    }

    public event PropertyChangedEventHandler PropertyChanged;
    private void RaisePropertyChanged(string propName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propName));
        }
    }
}

3 个答案:

答案 0 :(得分:7)

找到一种解决方法导致以前的解决方案无法解决我的问题。

只需在绑定和选择组合框的项目或索引之间添加暂停。

以下代码:

myCombobox.ItemsSource = myList;
await Task.Delay(100);
myCombobox.SelectedIndex = 12;

希望这有帮助!

答案 1 :(得分:2)

我检查了一下,我发现你的代码没有任何问题,所以我猜这是ComboBox中的一个错误。

了解问题并找到真正的修复可能需要一些时间,因此我建议您使用一些适合您的解决方法。我尝试了以下内容,似乎有效:

  1. 将VM中的Items属性更改为ObservableCollection<string>
  2. 类型
  3. 将VM的构造函数中的属性/字段初始化为空集合。
  4. 加载项目时,只需填写集合(使用Add()方法向其添加项目),而不是替换它。
  5. 编辑:我如何填写测试的示例。

    public class VM : INotifyPropertyChanged
    {
        private ObservableCollection<string> _items;
        public ObservableCollection<string> Items
        {
            get { return _items; }
            set
            {
                _items = value;
                _selectedItem = _items.FirstOrDefault();
                RaisePropertyChanged("Items");
                RaisePropertyChanged("SelectedItem");
            }
        }
    
        private string _selectedItem;
        public string SelectedItem
        {
            get { return _selectedItem; }
            set
            {
                _selectedItem = value;
                RaisePropertyChanged("SelectedItem");
            }
        }
    
    
        public VM()
        {
            this._items = new ObservableCollection<string>();
        }
    
        public async Task LoadDataAsync()
        {
            var items = new List<string>() {
                "1",
                "b",
                "c",
                "d",
                "e",
                "f",
                "f",
                "f",
                "f",
                "f",
                "f",
            };
    
            foreach (var i in items) {
                this._items.Add(i);
            }
            this.SelectedItem = items.FirstOrDefault();
        }
    
        public event PropertyChangedEventHandler PropertyChanged;
        private void RaisePropertyChanged(string propName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propName));
            }
        }
    }
    

    这对我来说很好。

答案 2 :(得分:1)

不仅是异步的 - 如果您将_vm.Items = new List...放入 OnLoaded 事件而不是await _vm.LoadDataAsync(); - 您将遇到同样的问题。

似乎在设置DataContext之前设置 Items 后,问题就不会发生。

另一件事是,如果你没有从代码中设置所选项目,问题就不会出现(正如我已经尝试过的那样):

public ObservableCollection<string> Items
{
    get { return _items; }
    set
    {
        _items = value;
    //    _selectedItem = _items.FirstOrDefault();
        RaisePropertyChanged("Items");
     //   RaisePropertyChanged("SelectedItem");
    }
}

至于现在,我不知道为什么会这样。