Silverlight ComboBox强制重新选择SelectedItem

时间:2011-05-02 21:00:43

标签: silverlight binding combobox selection

我有一个绑定到ComboBox的项目列表。当用户选择项目时,我想取消选择并改为选择其他项目。这必须发生在SelectedItem绑定的属性的setter中。我正在使用Silverlight 3。

ComboBox中每个项目的数据模型:

public class DataItem
{
    public int Id { get; set; }
    public string Name { get; set; }
}

设置为DataContext的对象:

public class DataContainer : INotifyPropertyChanged
{

    public DataContainer()
    {
        itemList = new List<DataItem>();
        itemList.Add(new DataItem() { Id = 1, Name = "First" });
        itemList.Add(new DataItem() { Id = 2, Name = "Second" });
        itemList.Add(new DataItem() { Id = 3, Name = "Third" });
    }

    public event PropertyChangedEventHandler PropertyChanged;

    private DataItem selectedItem;
    public DataItem SelectedItem
    {
        get { return selectedItem; }
        set
        {
            if (value != null && value.Id == 2)
                value = itemList[0];
            selectedItem = value;
            NotifyPropertyChanged("SelectedItem");
        }
    }

    private List<DataItem> itemList;
    public List<DataItem> ItemList
    {
        get { return itemList; }
        set { itemList = value; NotifyPropertyChanged("DataList"); }
    }

    protected void NotifyPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }

}

xaml的相关位:

<StackPanel>
    <StackPanel Orientation="Horizontal">
        <ComboBox x:Name="comboBox" DisplayMemberPath="Name" Width="100" ItemsSource="{Binding ItemList}" SelectedItem="{Binding Path=SelectedItem, Mode=TwoWay}"/>
        <Button Content="Set to First" Width="100" Click="Button_Click"/>
    </StackPanel>
    <StackPanel Orientation="Horizontal">
        <TextBlock Text="Selected item: "/>
        <TextBlock Text="{Binding SelectedItem.Id}"/>
        <TextBlock Text=" - "/>
        <TextBlock Text="{Binding SelectedItem.Name}"/>
    </StackPanel>
</StackPanel>

当用户选择第二个项目时,看起来像我的代码选择第一个项目。实际上,所选项目设置为“First”,而ComboBox仍然显示“Second”,就像它被选中一样。

有没有办法强制ComboBox重绘或重新考虑它应该在视觉上标记为选中的内容?

我是从上面提到的Button_Click方法做到的,它可以工作:

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        var c = DataContext as DataContainer;
        if (c != null)
        {
            c.SelectedItem = null;
            c.SelectedItem = c.ItemList[0];
        }
    }

但是设置为null然后设置我想要的值如果我在setter中按照我的需要设置它就不起作用。

2 个答案:

答案 0 :(得分:0)

我可能已经为您找到了解决方案。通过执行以下操作,我能够得到我认为您要求工作的内容:

public DataItem SelectedItem
{
    get { return _selectedItem; }
    set
    {
        if (value != null && value.Id == 2)
        {
            value = itemList[0];
            UpdateUI();  // Call this to force the UI to update.
        }
        _selectedItem = value;
        NotifyPropertyChanged("SelectedItem");

    }
}

private void UpdateUI()
{
    ThreadPool.QueueUserWorkItem(
        o =>
        {
            Thread.Sleep(1);

            Deployment.Current.Dispatcher.BeginInvoke(()=>
            {
                _selectedItem = null;
                NotifyPropertyChanged("SelectedItem");
                _selectedItem = itemList[0];
                NotifyPropertyChanged("SelectedItem");
            });
        });
}

我希望我能解释一下为什么这有效,但我只能猜测。基本上,它退出UI线程,然后通过Dispatcher.BeginInvoke()调用重新进入片刻。这似乎使ComboBox控制时间从用户交互中更新自身,然后响应Dispatcher执行。

我发现的一个问题是,在多次执行线程代码后,Silverlight似乎有点不稳定。增加Thread.Sleep时间似乎有所帮助。我认为这个解决方案适用于大多数情况,不会成为问题。

答案 1 :(得分:0)

你不必排队一个线程,等待1秒,因为建议使用grimus。这也适用于你:

public DataItem SelectedItem
{
    get { return _selectedItem; }
    set
    {
        _selectedItem = value;
        NotifyPropertyChanged("SelectedItem");

        if (value != null && value.Id == 2)
        {
            Diployment.Current.Dispatcher.BeginInvoke(() => { 
                          _selectedItem = itemList[0];               
                          NotifyPropertyChanged("SelectedItem"); });
        }


    }
}