2012-02-20 12 views
0

私は、ユーザーが時間オフセット(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プロパティが設定されています(遅すぎます)。

私が必要とする効果をどのように達成できますか?私はいくつかの他のイベントでコンボボックスに値を設定する必要がありますか?または、おそらく、コンバータにバースタイムを渡すより良い方法はありますか?

答えて

0

コンバーターのItemsSourceをバインディングによって定義して、コンバーターの作業を取得する必要があります。

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

「ObservableCollectionWithValuesは」(実際には正しいアプローチではありません)の後ろにコード内であなたのビューモデル(あなたがMVVMを使用している場合)、またはプロパティでプロパティです。 mvvmを使用しない場合は、this.DataContext = thisも追加します。あなたのコントロールのコンストラクタで。

私が知っているように、リソースに関してバインディングを使用することはできません(別の静的リソースにのみバインドできます)。これは、コンバーターがBaseTimeプロパティセットを取得しないことを意味します。コンバータに基本時間を渡す代わりにConverterParameterを使用してみてください。

+0

ItemsSourceが(コード内に)設定されており、コンバータはコンボのドロップダウン部分で機能します。 BaseTimeの値は実行時まで知りません。どうすればそれをConverterParameterにバインドできますか?私はそれがConverterParameterとして指定できる定数値だと思っていました。これがコンバーター自体へのバインディングを使用した理由です(一般に動作しますが、使用する前にバインドされていません) –

0

これは古い質問ですが、うまくいけば誰でもこのページを見つけるのを助けることができます。

オブジェクト(この場合はCurrentBaseTime)をビューモデルのパブリックプロパティにして、ビューモデルがINotifyPropertyChangedを継承することを確認します。値をロードします(私の場合は、コンボボックスのルックアップテーブルでした)。そして、プロパティの変更後にプロパティを変更します。

モデルをロードします。私の場合は、ビューモデルにロードするメタデータと、ロードするモデルの3つのルックアップテーブルが必要です。次に、ビューは、依存関係プロパティを使用して、メタデータが事前入力されたコンバータを呼び出します。

ViewModelはプロパティの変更を必要とします。それ以外の場合は、コンバーターにnullが付いています(上記の問題)。