2011-05-02 28 views
4

我有一个绑定到组合框的项目列表。当用户选择一个项目时,我想取消选择并选择其他项目。这必须发生在SelectedItem绑定的属性的setter中。我使用Silverlight 3Silverlight组合框强制重新选择SelectedItem

在组合框的每个项目我的数据模型:

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

对象,它是设置到DataContext:XAML的

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)); 
    } 

} 

相关位:

<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> 

它看起来像我的代码,当用户选择第二个项目正在工作时选择第一个项目。被选择的项目实际上被设置为“第一”,而组合框仍然显示“第二”,就好像它被选中一样。

有什么办法强制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,然后,如果我从模子中不喜欢它,我需要我想要的值不工作。

回答

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控制时间从用户交互中自行更新,然后响应分派器执行。

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

+0

我真的希望避免这种做法。如果我无法弄清楚如何使ComboBox自行修复,那么我想我必须这样做。 – 2011-05-04 16:20:14

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"); }); 
     } 


    } 
}