私は、ユーザーが時間オフセット(0,3,6,9)を選択できるようにするComboBoxを持っています。しかし、彼らが見るものは絶対時間として表示する必要があります。オフセットは基本時間にオフセットを加えたものです。例えば基本時刻が「0600」であれば、ユーザは「0600」、「0900」、「1200」、「1500」の中から選択する。Silverlight ComboBoxのIValueConverterにデータをバインドする
私はこのオフセット時間を絶対時間に変換するために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.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イベントが発生するので、現在の値として "0900"(BaseTimeから3hrsオフセット)が表示されず、ComboBoxが表示されたときに表示されます。 "17:47"(UtcNowから3時間オフセット)。 ComboBoxをクリックすると、ドロップダウンに正しい時刻が入力されます。これは、イベントの順序のために間違った初期値です。
OnLoadedが呼び出され、ComboBoxが塗りつぶされ、SelectedIndexが設定され、Convertが呼び出され、が呼び出されます。変換のBaseTimeプロパティが設定されています(遅すぎます)。
私が必要とする効果をどのように達成できますか?私はいくつかの他のイベントでコンボボックスに値を設定する必要がありますか?または、おそらく、コンバータにバースタイムを渡すより良い方法はありますか?
ItemsSourceが(コード内に)設定されており、コンバータはコンボのドロップダウン部分で機能します。 BaseTimeの値は実行時まで知りません。どうすればそれをConverterParameterにバインドできますか?私はそれがConverterParameterとして指定できる定数値だと思っていました。これがコンバーター自体へのバインディングを使用した理由です(一般に動作しますが、使用する前にバインドされていません) –