Почему один и тот же код дает разные результаты?

После этого кода:

    if ((App.roamingSettings.Values.ContainsKey("FromMonthSection1")) &&
        (!string.IsNullOrWhiteSpace(App.roamingSettings.Values["FromMonthSection1"].ToString())))
    {
        comboBoxFromMonth.SelectedValue = App.roamingSettings.Values["FromMonthSection1"].ToString();
    }
    if ((App.roamingSettings.Values.ContainsKey("FromDaySection1")) &&
        (!string.IsNullOrWhiteSpace(App.roamingSettings.Values["FromDaySection1"].ToString())))
    {
        comboBoxFromDay.SelectedValue = App.roamingSettings.Values["FromDaySection1"].ToString();
    }

... работает, ComboBoxFromMonth's SelectedValue = "Август", как и ожидалось. Однако SelectedValue для comboBoxFromDay = null, хотя в окне Immediate я вижу:

App.roamingSettings.Values["FromDaySection1"].ToString()
"16"
comboBoxFromDay.Items.Count
31

Проходя через него, оператор присваивания выполняется в обоих случаях, просто comboxFromDay.SelectedValue имеет значение null даже после присваивания по какой-то причине.

Так что же может отличаться, что вызывает эти противоположные реакции с одним и тем же кодом?

XAML для двух рассматриваемых comboBox:

<ComboBox x:Name="comboBoxFromMonth" Height="24" Width="100" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="4" LostFocus="ComboBox_OnLostFocus" ></ComboBox>

<ComboBox x:Name="comboBoxFromDay" Grid.Row="1" Grid.Column="1" Height="24" Width="80" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="2" LostFocus="ComboBox_OnLostFocus"/>

XAML для всех практических целей одинаков, за исключением того, что для comboBoxFromMonth нет явного назначения Grid.Row или Grid.Column.

Кроме того, установка значений роуминга точно такая же:

if (cmbxName == "comboBoxFromMonth")
{
    App.roamingSettings.Values["FromMonthSection1"] =
        comboBoxFromMonth.SelectedValue;
}
else if (cmbxName == "comboBoxFromDay")
{
    App.roamingSettings.Values["FromDaySection1"] =
        comboBoxFromDay.SelectedValue;
}

Так как же получается, что в одном случае работает, а в другом нет?

Кстати, свойства, отображаемые на панели свойств для двух выпадающих списков, тоже одинаковы (кроме имени, конечно, и MaxDropDownHeight - 520 против бесконечности, но я уверен, что это не имеет значения).

РЕШЕНО (ИЛИ ТАК Я ДУМАЛ)

Брэндон попал в самую точку: удалив ".ToString()":

if ((App.roamingSettings.Values.ContainsKey("FromDaySection1")) &&
    (!string.IsNullOrWhiteSpace(App.roamingSettings.Values["FromDaySection1"].ToString())))
{
    comboBoxFromDay.SelectedValue = App.roamingSettings.Values["FromDaySection1"];
}

...работает.

ОБНОВИТЬ

Хорошо, так что это еще не совсем решено; вот что-то странное я заметил по этому поводу:

Движок настроек роуминга, по-видимому, решает, какой тип данных вы сохраняете.

Если вы сохраните такие значения, как «Январь», он сохранит это как строку. Если вы сохраните такие значения, как от «1» до «12», они будут сохранены как int.

Однако что, если у вас есть такие значения, как «00» (соответственно рассматриваемые как строка) И такие значения, как «10» до «59»? Несмотря на то, что они хранятся в том же сегменте (например, «ToMinuteSection1»), тип данных будет трансформироваться.

Это имеет смысл, так как ведро имеет только одно значение за раз. Если это «00», это рассматривается как строка; если это "10", это рассматривается как целое число.

Но это делает получение этих значений немного неуклюжим, потому что это работает, если значение, содержащееся в «ToMinuteSection1», является строкой (например, «00»):

comboBoxToMinute.SelectedValue = App.roamingSettings.Values["ToMinuteSection1"].ToString();

... но не в том случае, если значение рассматривается как целое число (например, "59"); тогда нужно:

comboBoxToMinute.SelectedValue = App.roamingSettings.Values["ToMinuteSection1"];

ТАК... поскольку я не знаю, что выберет пользователь, я могу сделать это, но мне кажется, что за это меня должны ударить:

int toMinute;
string toMinuteStr = App.roamingSettings.Values["ToMinuteSection1"].ToString();
bool isInt = int.TryParse(toMinuteStr, out toMinute);
if (isInt) // it should alway be an int now
{
    if (toMinute < 10)
    {
        comboBoxToMinute.SelectedValue = toMinuteStr;
    }
    else
    {
        comboBoxToMinute.SelectedValue = toMinute;
    }
}

... и на самом деле я сначала пытался сделать это так:

int toMinute;
string toMinuteStr = App.roamingSettings.Values["ToMinuteSection1"].ToString();
bool isInt = int.TryParse(toMinuteStr, out toMinute);
if (isInt)
{
    comboBoxToMinute.SelectedValue = toMinute;
}
else
{
    comboBoxToMinute.SelectedValue = toMinuteStr;
}

... но этот трюк не работает, потому что "09" прекрасно анализируется в 9, но присвоение равно null, потому что в поле со списком нет "9", просто "09"

Есть ли более элегантный способ сделать это (чем мой действующий мой неряшливый метод, показанный выше)?


person B. Clay Shannon    schedule 25.12.2012    source источник


Ответы (2)


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

Из того, что вы описали, похоже, что ваш comboBox действительно может содержать целые числа от 0 до 59, но вы хотите, чтобы все они отображались как 2 цифры (все, что меньше 10, должно иметь начальный ноль).

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

person Brandon Dybala    schedule 26.12.2012
comment
Да, для некоторых записей мне нужен начальный 0 (например, для минут); не уверен, каким должен быть ItemStringFormat для этого. - person B. Clay Shannon; 26.12.2012
comment
Google .NET Format Strings, и вы должны найти много документации, которая поможет вам понять это :) Если вы новичок в форматировании строк, я предлагаю загрузить LINQPad, чтобы попробовать небольшие фрагменты кода C#, просто чтобы увидеть, как это работает. без необходимости создавать совершенно новый проект VS или изменять код приложения. Я постоянно использую его для тестирования форматных строк, регулярных выражений и фрагментов логики, которые пока не хочу включать в свою программу. - person Brandon Dybala; 26.12.2012
comment
Кроме того, имейте в виду, что при указании строк формата в XAML есть несколько особенностей, например необходимость экранировать символы { и } определенным образом. Прошло некоторое время с тех пор, как я это сделал, поэтому я не помню деталей, но есть много обращений к Google и ТАКИХ вопросов об этом, так что это не должно быть слишком сложно найти. - person Brandon Dybala; 26.12.2012

Являются ли значения в вашем comboBox целыми числами или строками? Согласно примечаниям к документации MSDN, если значение, которое вы установили для SelectedValue, не находится в поле со списком, то оно очищает выделение (т. е. устанавливает его в нулевое значение). Если это целые числа, ваш ToString() может не найти соответствующий элемент.

person Brandon Dybala    schedule 25.12.2012