Поле комбинированного списка Silverlight, Связывающее с данными состояние состязания

Проблема в том, что для вашего второго ввода нет обработки исключений.

travel_score = 0

while True:
    try:
        travel_score = int(input("How many times per year do you travel? Please give an integer number"))
    except ValueError:
        # if an exception raised here it propagates
        travel_score = int(input("This was not a valid input please try again"))


print ("User travels per year:", travel_score)

Лучший способ справиться с этим - это вернуть информативное сообщение пользователю, если его ввод неверен, и позволить циклу вернуться в начало и повторить запрос таким образом:

# there is no need to instantiate the travel_score variable
while True:
    try:
        travel_score = int(input("How many times per year do you travel? Please give an integer number"))
    except ValueError:
        print("This was not a valid input please try again")
    else:
        break  # <-- if the user inputs a valid score, this will break the input loop

print ("User travels per year:", travel_score)
6
задан caryden 2 March 2009 в 21:47
поделиться

5 ответов

Хорошо я нашел ответ (использующий много Отражателя, чтобы выяснить, как ComboBox работает).

Проблема существует, когда ItemSource установлен после того, как SelectedItem установлен. Когда это происходит, Combobx рассматривает его как полный Сброс выбора и очищает SelectedItem/SelectedIndex. Вы видите это здесь в Системе. Windows. Средства управления. Примитивы. Селектор (базовый класс для ComboBox):

protected override void OnItemsChanged(NotifyCollectionChangedEventArgs e)
{
    base.OnItemsChanged(e);
    int selectedIndex = this.SelectedIndex;
    bool flag = this.IsInit && this._initializingData.IsIndexSet;
    switch (e.Action)
    {
        case NotifyCollectionChangedAction.Add:
            if (!this.AddedWithSelectionSet(e.NewStartingIndex, e.NewStartingIndex + e.NewItems.Count))
            {
                if ((e.NewStartingIndex <= selectedIndex) && !flag)
                {
                    this._processingSelectionPropertyChange = true;
                    this.SelectedIndex += e.NewItems.Count;
                    this._processingSelectionPropertyChange = false;
                }
                if (e.NewStartingIndex > this._focusedIndex)
                {
                    return;
                }
                this.SetFocusedItem(this._focusedIndex + e.NewItems.Count, false);
            }
            return;

        case NotifyCollectionChangedAction.Remove:
            if (((e.OldStartingIndex > selectedIndex) || (selectedIndex >= (e.OldStartingIndex + e.OldItems.Count))) && (e.OldStartingIndex < selectedIndex))
            {
                this._processingSelectionPropertyChange = true;
                this.SelectedIndex -= e.OldItems.Count;
                this._processingSelectionPropertyChange = false;
            }
            if ((e.OldStartingIndex <= this._focusedIndex) && (this._focusedIndex < (e.OldStartingIndex + e.OldItems.Count)))
            {
                this.SetFocusedItem(-1, false);
                return;
            }
            if (e.OldStartingIndex < selectedIndex)
            {
                this.SetFocusedItem(this._focusedIndex - e.OldItems.Count, false);
            }
            return;

        case NotifyCollectionChangedAction.Replace:
            if (!this.AddedWithSelectionSet(e.NewStartingIndex, e.NewStartingIndex + e.NewItems.Count))
            {
                if ((e.OldStartingIndex <= selectedIndex) && (selectedIndex < (e.OldStartingIndex + e.OldItems.Count)))
                {
                    this.SelectedIndex = -1;
                }
                if ((e.OldStartingIndex > this._focusedIndex) || (this._focusedIndex >= (e.OldStartingIndex + e.OldItems.Count)))
                {
                    return;
                }
                this.SetFocusedItem(-1, false);
            }
            return;

        case NotifyCollectionChangedAction.Reset:
            if (!this.AddedWithSelectionSet(0, base.Items.Count) && !flag)
            {
                this.SelectedIndex = -1;
                this.SetFocusedItem(-1, false);
            }
            return;
    }
    throw new InvalidOperationException();
}

Отметьте последний случай - сброс... При загрузке нового ItemSource, Вы заканчиваете здесь, и какой-либо SelectedItem/SelectedIndex сдувается?!?!

Хорошо решение было довольно просто в конце. я просто разделил ошибочный ComboBox на подклассы и обеспечил и переопределение для этого метода следующим образом. Хотя я действительно должен был добавить a:

public class FixedComboBox : ComboBox
{
    public FixedComboBox()
        : base()
    {
        // This is here to sync the dep properties (OnSelectedItemChanged is private is the base class - thanks M$)
        base.SelectionChanged += (s, e) => { FixedSelectedItem = SelectedItem; };
    }

    // need to add a safe dependency property here to bind to - this will store off the "requested selectedItem" 
    // this whole this is a kludgy wrapper because the OnSelectedItemChanged is private in the base class
    public readonly static DependencyProperty FixedSelectedItemProperty = DependencyProperty.Register("FixedSelectedItem", typeof(object), typeof(FixedComboBox), new PropertyMetadata(null, new PropertyChangedCallback(FixedSelectedItemPropertyChanged)));
    private static void FixedSelectedItemPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
    {
        FixedComboBox fcb = obj as FixedComboBox;
        fcb.mLastSelection = e.NewValue;
        fcb.SelectedItem = e.NewValue;
    }
    public object FixedSelectedItem 
    {
        get { return GetValue(FixedSelectedItemProperty); }
        set { SetValue(FixedSelectedItemProperty, value);}
    }
    protected override void OnItemsChanged(System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
    {
        base.OnItemsChanged(e);
        if (-1 == SelectedIndex)
        {
            // if after the base class is called, there is no selection, try
            if (null != mLastSelection && Items.Contains(mLastSelection))
                SelectedItem = mLastSelection;
        }
    }

    protected object mLastSelection = null;
}

Все, что это делает, (a), сохраняют от старого SelectedItem, и затем (b) проверяют что, если после того, как ItemsChanged, если у нас нет сделанного выбора и старый SelectedItem, существует в новом списке... хорошо... Выбранный Это!

7
ответ дан 10 December 2019 в 00:45
поделиться

Не ясно из Вашего сообщения, знаете ли Вы, что необходимо изменить элементы UI на потоке UI - или у Вас будут проблемы. Вот краткий пример, который создает фоновый поток, который изменяет TextBox с текущим временем.

Ключом является MyTextBox. Dispather. BeginInvoke в Page.xaml.cs.

Page.xaml:

<UserControl x:Class="App.Page"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    Width="400" Height="300"
             Loaded="UserControl_Loaded">
    <Grid x:Name="LayoutRoot">
        <TextBox FontSize="36" Text="Just getting started." x:Name="MyTextBox">
        </TextBox>
    </Grid>
</UserControl>

Page.xaml.cs:

using System;
using System.Windows;
using System.Windows.Controls;

namespace App
{
    public partial class Page : UserControl
    {
        public Page()
        {
            InitializeComponent();
        }

        private void UserControl_Loaded(object sender, RoutedEventArgs e)
        {
            // Create our own thread because it runs forever.
            new System.Threading.Thread(new System.Threading.ThreadStart(RunForever)).Start();
        }

        void RunForever()
        {
            System.Random rand = new Random();
            while (true)
            {
                // We want to get the text on the background thread. The idea
                // is to do as much work as possible on the background thread
                // so that we do as little work as possible on the UI thread.
                // Obviously this matters more for accessing a web service or
                // database or doing complex computations - we do this to make
                // the point.
                var now = System.DateTime.Now;
                string text = string.Format("{0}.{1}.{2}.{3}", now.Hour, now.Minute, now.Second, now.Millisecond);

                // We must dispatch this work to the UI thread. If we try to 
                // set MyTextBox.Text from this background thread, an exception
                // will be thrown.
                MyTextBox.Dispatcher.BeginInvoke(delegate()
                {
                    // This code is executed asynchronously on the 
                    // Silverlight UI Thread.
                    MyTextBox.Text = text;
                });
                //
                // This code is running on the background thread. If we executed this
                // code on the UI thread, the UI would be unresponsive.
                //
                // Sleep between 0 and 2500 millisends.
                System.Threading.Thread.Sleep(rand.Next(2500));
            }
        }
    }
}

Так, если Вы хотите получить вещи асинхронно, необходимо будет использовать Управление. Диспетчер. BeginInvoke, чтобы уведомить элемент UI, что у Вас есть некоторые новые данные.

0
ответ дан 10 December 2019 в 00:45
поделиться

Вместо того, чтобы повторно связывать ItemsSource каждый раз, вам было бы проще привязать его к ObservableCollection <>, а затем вызвать Clear () для него и добавить (...) все элементы. Таким образом, привязка не сбрасывается.

Еще одна проблема заключается в том, что выбранный элемент ДОЛЖЕН быть экземпляром объектов в списке. Однажды я совершил ошибку, когда подумал, что список запросов для элемента по умолчанию был исправлен, но обновлялся при каждом вызове.

0
ответ дан 10 December 2019 в 00:45
поделиться

Я боролся с этой же проблемой, создавая каскадные поля со списком, и наткнулся на сообщение в блоге человека, который нашел простое, но удивительное решение. Вызовите UpdateLayout () после установки .ItemsSource, но перед установкой SelectedItem. Это должно заставить код блокироваться до завершения привязки данных. Я не совсем уверен, почему это исправляет, но я больше не сталкивался с состоянием гонки с тех пор ...

Источник этой информации: http://compiledexperience.com/Blog/post/Gotcha-when -databinding-a-ComboBox-in-Silverlight.aspx

1
ответ дан 10 December 2019 в 00:45
поделиться

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

http://blogs.msdn.com/b/kylemc/archive/2010/06/18/combobox-sample-for-ria-services.aspx

Я был очень доволен, поскольку это сузило синтаксис до чего-то вроде следующего.

<ComboBox Name="AComboBox" 
      ItemsSource="{Binding Data, ElementName=ASource}" 
      SelectedItem="{Binding A, Mode=TwoWay}" 
      ex:ComboBox.Mode="Async" />

Кайл

2
ответ дан 10 December 2019 в 00:45
поделиться
Другие вопросы по тегам:

Похожие вопросы: