Привязка данных к IValueConverter для комбинированного списка Silverlight - PullRequest
0 голосов
/ 20 февраля 2012

У меня есть ComboBox, который позволяет пользователю выбирать часовое смещение (0, 3, 6 или 9). Однако то, что они видят, нужно показывать как абсолютное время, которое получается путем добавления смещения к базовому времени. например если базовое время равно «0600», пользователь может выбрать «0600», «0900», «1200» и «1500».

Я использую IValueConverter для преобразования этого времени смещения в абсолютное время. Базовое время передается преобразователю путем привязки значения к пользовательскому свойству преобразователя. (см. код ниже).

Теперь это обычно работает нормально, за исключением случая изначально выбранного значения в ComboBox; это всегда использует BaseTime по умолчанию UtcNow и не использует связанное значение. Устанавливая точки останова в коде, я вижу, что свойство зависимости BaseTime не устанавливается до тех пор, пока после вызова Convert не произойдет преобразование начального значения.

Это класс конвертера, который я использую:

public class ForecastTimeConverter : DependencyObject, IValueConverter
{
     // Register the dependency property we need for the BaseTime property.
     public DependencyProperty BaseTimeProperty = DependencyProperty.Register(
            "BaseTime", 
            typeof(DateTime), 
            typeof(ForecastTimeConverter),
            new PropertyMetadata(DateTime.UtcNow, BaseTimeChanged)
       );

    private static void BaseTimeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
            // this method here just so I can set a breakpoint to see when the property is set.
    }

    public DateTime BaseTime
    {
        get { return (DateTime)GetValue(BaseTimeProperty);}
        set { SetValue(BaseTimeProperty, value); }
    }

    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        string forecast_time;
        if (value is string)
        {
            try
            {
                // get forecast period, in hours.
                int hours = System.Convert.ToInt32(value as string);
                // add forecast period to base time to get final forecast time.
                DateTime forecastTime = BaseTime + new TimeSpan(hours, 0, 0);
                forecast_time = String.Format("{0:HHmm}z", forecastTime);
            }
            catch
            {
                forecast_time = "?";
            }    
        }
        else
        {
            throw new NotImplementedException("Can't convert from type '" + typeof(ValueType) + "'");
        }
        return forecast_time;
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

Полный исходный код XAML и UserControl довольно большой, поэтому здесь приведены только соответствующие биты:

<UserControl.Resources>
    <status:ForecastTimeConverter x:Key="ForecastTimeConverter" BaseTime="{Binding Path=CurrentBaseTime}" />
</UserControl.Resources>
...
<ComboBox x:Name="forecastPeriodCombo" Grid.Row="0" Grid.Column="1" Width="100" SelectionChanged="OnforecastPeriodChanged" >
    <ComboBox.ItemTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding Converter={StaticResource ForecastTimeConverter}}"/>
        </DataTemplate>
    </ComboBox.ItemTemplate>
</ComboBox>

И соответствующий код, стоящий за XAML, упрощен:

public partial class MyControl : UserControl
{
    public MyControl()
    {
        InitializeComponent();
        this.Loaded += OnLoaded;
    }

    public void OnLoaded(object sender, EventArgs e)
    {
        forecastPeriodCombo.Items.Clear();
        List<string> values = new List<string>();
        values.Add("0");
        values.Add("3");
        values.Add("6");
        values.Add("9");
        forecastPeriodCombo.ItemsSource = values;
        forecastPeriodCombo.SelectedIndex = 1;
    }
}

Проблема заключается в том, что привязка свойства BaseTime конвертера не выполняется до тех пор, пока после не сработает событие Loaded для UserControl, поэтому вместо отображения «0900» отображается ComboBox (Смещение на 3 часа от BaseTime) в качестве текущего значения, я вижу что-то вроде «17:47», (смещение на 3 часа от UtcNow). Когда я нажимаю на ComboBox, в раскрывающемся списке указывается правильное время. Это просто начальное значение, которое неверно из-за порядка событий.

OnLoaded вызывается, ComboBox заполняется, SelectedIndex установлен, Convert вызывается, затем свойство BaseTime преобразования установлено (слишком поздно!).

Как мне добиться нужного эффекта? Должен ли я заполнить ComboBox на каком-то другом событии? Или, может быть, есть лучший способ передать базовое время конвертеру?

Ответы [ 2 ]

0 голосов
/ 18 марта 2013

Это старый вопрос, но, надеюсь, он может помочь любому, кто найдет эту страницу.

Сделайте объект (в данном случае CurrentBaseTime) открытым свойством модели представления и убедитесь, что модель представления наследует INotifyPropertyChanged.Загрузите значения (в моем случае это была таблица поиска для комбинированного списка), а затем установите свойство после загрузки (повышение изменения свойства).

Затем загрузите модель.В моем случае мне нужно загрузить три мета-таблицы в таблицу просмотра, а затем загрузить модель.Затем представление вызывает конвертеры, которые предварительно заполнены метаданными (используя свойство зависимости).

ViewModel необходимо вызвать изменения свойства, в противном случае конвертеры застряли с нулем, т. Е. Проблема выше.

0 голосов
/ 24 февраля 2012

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

<ComboBox x:Name="forecastPeriodCombo" ItemsSource={Binding ObservableCollectionWithValues, Converter={StaticResource ForecastTimeConverter}} ... >

"ObservableCollectionWithValues" - это свойство в вашей модели представления (если вы используете mvvm) или свойство в вашем коде (которыйэто на самом деле не правильный подход).Если вы не используете mvvm, добавьте также this.DataContext = this;в конструкторе вашего элемента управления.

Как насчет конвертера, поскольку я знаю, что невозможно использовать привязку для ресурсов (вы можете связать только с другим статическим ресурсом).Это означает, что ваш конвертер не получит набор свойств BaseTime.Попробуйте вместо этого использовать ConverterParameter, чтобы передать базовое время конвертеру.

...