【问题标题】:Binding data to an IValueConverter for a Silverlight ComboBox将数据绑定到 Silverlight ComboBox 的 IValueConverter
【发布时间】:2012-03-10 22:02:58
【问题描述】:

我有一个允许用户选择每小时偏移量(0、3、6 或 9)的 ComboBox。但是,他们看到的内容需要显示为绝对时间,这是通过将偏移量添加到基本时间而得出的。例如如果基准时间是“0600”,用户可以选择“0600”、“0900”、“1200”和“1500”。

我正在使用 IValueConverter 将此偏移时间转换为绝对时间 通过将值绑定到转换器的自定义属性,将基本时间传递给转换器。 (代码见下文)。

现在这通常可以正常工作,除了 ComboBox 中最初选择的值的情况;这始终使用 UtcNow 的默认 BaseTime,并且不使用绑定值。通过在代码中设置断点,我可以看到 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 属性的绑定直到 为 UserControl 触发 Loaded 事件后才完成,因此当显示 ComboBox 时,而不是看到“0900 "(从 BaseTime 偏移 3 小时)作为当前值,我看到的内容更像是“17:47”,(从 UtcNow 偏移 3 小时)。当我单击 ComboBox 时,下拉列表中填充了正确的时间。由于事件的顺序,只是初始值错误。

调用OnLoaded,填充ComboBox,设置SelectedIndex,调用Convert,然后设置convert的BaseTime属性(为时已晚!)。

我怎样才能达到我需要的效果?我应该在其他事件上填充 ComboBox 吗?或者有没有更好的方法将基准时间传递给转换器?

【问题讨论】:

    标签: c# silverlight data-binding combobox ivalueconverter


    【解决方案1】:

    您需要通过绑定来定义您的组合框的 ItemsSource 以使转换器工作。

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

    “ObservableCollectionWithValues”是视图模型中的属性(如果您使用 mvvm)或后面代码中的属性(这实际上不是正确的方法)。如果你不使用 mvvm 然后添加 this.DataContext = this;在您的控件的构造函数中。

    转换器呢,据我所知,不能对资源使用绑定(您只能绑定到另一个静态资源)。这意味着您的转换器不会设置 BaseTime 属性。尝试改用 ConverterParameter 将基准时间传递给转换器。

    【讨论】:

    • ItemsSource 已设置(在代码中),转换器确实适用于组合的下拉部分。 BaseTime 值直到运行时才知道 - 如何将其绑定到 ConverterParameter?我认为这只是我可以指定为 ConverterParameter 的常量值。这就是我使用绑定到转换器本身的原因(一般来说,它在我需要使用它之前没有绑定)
    【解决方案2】:

    这是一个老问题,但希望可以帮助找到此页面的任何人。

    使对象(在本例中为 CurrentBaseTime)成为 View Model 的公共属性,并确保 View Model 继承 INotifyPropertyChanged。加载值(在我的情况下,它是组合框的查找表),然后在加载后设置属性(提高属性更改)。

    然后加载您的模型。就我而言,我需要将三个查找表的元数据加载到视图模型中,然后再加载模型。然后视图调用预填充了元数据的转换器(使用依赖属性)。

    ViewModel 需要引发属性更改,否则转换器会卡在 null 上,即上述问题。

    【讨论】:

      猜你喜欢
      • 2012-04-06
      • 1970-01-01
      • 2010-10-10
      • 2013-03-16
      • 1970-01-01
      • 1970-01-01
      • 2014-06-13
      • 1970-01-01
      • 2016-06-17
      相关资源
      最近更新 更多