Silverlight ComboBox принудительно повторно выбрать SelectedItem - PullRequest
4 голосов
/ 03 мая 2011

У меня есть список элементов, связанных с ComboBox. Когда пользователь выбирает элемент, я бы хотел отменить выбор и выбрать другой элемент. Это должно происходить из установщика свойства, к которому привязан SelectedItem. Я использую 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>

Похоже, мой код для выбора первого элемента, когда пользователь выбирает второй элемент, работает. Выбранный элемент фактически установлен на «Первый», в то время как ComboBox все еще отображает «Второй», как если бы он был выбран.

Есть ли способ заставить 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];
        }
    }

Но если установить нулевое значение, а затем желаемое значение, не сработает, если я сделаю это из установщика так, как мне нужно.

Ответы [ 2 ]

0 голосов
/ 05 июня 2013

Вам не нужно ставить в очередь тему с ожиданием в течение 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"); });
        }


    }
}
0 голосов
/ 03 мая 2011

Возможно, я нашел решение для вас. Я смог получить то, что, как вы думаете, вы просите, выполнив следующее:

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

Хотел бы я объяснить вам, почему это работает, но я могу только догадываться. По сути, это выход из потока пользовательского интерфейса, а затем повторный ввод через минуту через вызов Dispatcher.BeginInvoke (). Похоже, что это дает элементу управления ComboBox время для обновления от взаимодействия с пользователем, а затем отвечает на выполнение Dispatcher.

Одна проблема, которую я обнаружил, заключается в том, что Silverlight выглядит немного шатко после многократного выполнения многопоточного кода. Увеличение Thread.Sleep, кажется, помогает. Я думаю, что это решение будет работать для большинства ситуаций и не будет проблемой.

...