2012-02-20 3 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을 소스는 그래서 여기에 단지 관련 비트입니다, 오히려 큰 :

<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에 대해 발생하므로 ComboBox가 표시 될 때 "0900"(BaseTime에서 3 시간 오프셋)이 현재 값으로 표시되는 대신에 더 비슷한 것을 볼 수 있습니다 "17:47"(UtcNow에서 3 시간 오프셋). ComboBox를 클릭하면 드롭 다운에 올바른 시간이 채워집니다. 그것은 이벤트의 순서로 인해 잘못된 초기 값입니다.

OnLoaded가 호출되고 ComboBox가 채워지고 SelectedIndex가 설정되고 Convert가 호출되면 이 표시되고 변환의 BaseTime 속성이 설정되었습니다 (너무 늦었습니다).

내가 필요한 효과를 어떻게 얻을 수 있습니까? 다른 이벤트에서 ComboBox를 채워야합니까? 아니면 바쁜 시간을 변환기에 전달하는 더 좋은 방법이 있습니까?

답변

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)를보기 모델의 public 속성으로 만들고 뷰 모델이 INotifyPropertyChanged를 상속하는지 확인하십시오. 값을로드하십시오 (제 경우에는 콤보 상자의 찾아보기 테이블이었습니다). 그런 다음로드 후에 속성을 설정합니다 (속성 변경시 발생).

그런 다음 모델을로드하십시오. 필자의 경우에는 viewmodel에로드 할 메타 데이터와로드 할 모델의 세 가지 조회 테이블이 필요합니다. 그런 다음 뷰는 메타 데이터로 미리 채워진 변환기를 호출합니다 (종속성 속성 사용).

ViewModel은 속성 변경을 발생시켜야합니다. 그렇지 않으면 위의 문제와 같이 변환기가 null로 인해 발생합니다.

관련 문제