我有一个ComboBox,允许用户选择每小时偏移量(0,3,6或9)。但是,他们所看到的需要显示为绝对时间,这是通过将偏移量添加到基准时间得出的。例如如果基准时间为“0600”,则用户可以选择“0600”,“0900”,“1200”和“1500”。
我正在使用IValueConverter将此偏移时间转换为绝对时间通过将值绑定到转换器的自定义属性,将基准时间传递给转换器。 (见下面的代码)。
现在这通常可以正常工作,除了ComboBox中最初选择的值的情况;这总是使用UtcNow的默认BaseTime,并且不使用绑定值。通过在代码中设置断点,我可以看到直到调用Convert whch转换初始值之后才设置BaseTime依赖项属性。
这是我正在使用的转换器类:
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吗?或者是否有更好的方法将基准时间传递给转换器?
答案 0 :(得分:0)
您需要通过绑定来定义组合框的ItemsSource以使转换器工作。
<ComboBox x:Name="forecastPeriodCombo" ItemsSource={Binding ObservableCollectionWithValues, Converter={StaticResource ForecastTimeConverter}} ... >
“ObservableCollectionWithValues”是视图模型中的属性(如果使用mvvm)或后面的代码中的属性(实际上这不是正确的方法)。如果你不使用mvvm,那么也添加this.DataContext = this;在你控制的构造函数中。
转换器怎么样,因为我知道不可能对Resources使用绑定(你只能绑定到另一个静态资源)。这意味着您的转换器不会设置BaseTime属性。尝试使用ConverterParameter将基准时间传递给转换器。
答案 1 :(得分:0)
这是一个老问题,但希望可以帮助任何人找到这个页面。
使对象(在本例中为CurrentBaseTime)成为视图模型的公共属性,并确保视图模型继承INotifyPropertyChanged。加载值(在我的例子中,它是组合框的查找表),然后在加载后设置属性(提高属性更改)。
然后加载您的模型。在我的例子中,我需要在viewmodel中加载三个值得元数据的查找表,然后加载要加载的模型。 View然后调用预填充元数据的转换器(使用依赖属性)。
ViewModel需要引发属性更改,否则转换器会遇到null,即上面的问题。