2013-07-26 4 views
2

`다양한 작업의 결과를 나타내는 항목이 포함 된 목록 상자가 있습니다. 이들은 각각 공통 기본 클래스 "ResultsViewModel"을 확장하므로 표시기에 필요한 특정 속성을 공유합니다.목록 상자의 WPF datatemplate 다형성

리소스 사전에 정의하려는 것은 태스크 결과의 각기 다른 유형에 대한 데이터 템플릿입니다. 예를 들어 태스크 A는 ResultsAViewModel의 구현 클래스를 가지며 태스크 B는 ResultsBViewModel 등을 갖습니다. 데이터 템플릿을 정의하려고합니다. 각 하위 클래스에 대해 ListBox의 ItemsSource를 ObservableCollection (부모 클래스)에 바인딩하고 WPF에 다형성을 사용하여 런타임에 사용할 데이터 템플릿을 결정합니다. 복잡성은 다양한 트리거에 따라 결과가 처리 중인지, 완료되었는지 또는 실패했는지에 따라 각 결과 유형에 대해 선택된 세 가지 데이터 템플릿 중 하나가됩니다. 따라서 파생 된 각 클래스에는 템플릿이 있습니다.

는 지금까지 내가

<ListBox Background="{StaticResource AppBackground}" Grid.Row="1" Grid.Column="1" Grid.ColumnSpan="2" Padding="10" Style="{StaticResource ResultsItemTemplate}" ItemsSource="{Binding Results}" MouseDoubleClick="ListBox_MouseDoubleClick" /> 

다음과 같이 목록 상자의 스타일로 일반적인 스타일을 적용했습니다

<!-- Region General Results styles --> 
<Style TargetType="{x:Type ListBox}" x:Key="ResultsItemTemplate" > 
    <Setter Property="Background"> 
     <Setter.Value> 
      Tan 
     </Setter.Value> 
    </Setter> 
    <Setter Property="ItemTemplate"> 
     <Setter.Value> 
      <DataTemplate> 
       <ContentControl Content="{Binding}"> 
        <ContentControl.Style> 
         <Style TargetType="{x:Type ContentControl}"> 
          <Setter Property="ContentTemplate" Value="{DynamicResource CalculatingResultsTemplate}"/> 
          <Style.Triggers> 
           <DataTrigger Binding="{Binding Path=ProcessingResult}" Value="1"> 
            <Setter Property="ContentTemplate" Value="{DynamicResource ProcessedResultsTemplate}"/> 
           </DataTrigger> 
           <DataTrigger Binding="{Binding Path=ProcessingResult}" Value="-1"> 
            <Setter Property="ContentTemplate" Value="{DynamicResource ErroredResultsTemplate}"/> 
           </DataTrigger> 
           <DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListBoxItem}}, Path=IsSelected}" Value="True"> 
            <Setter Property="Background" Value="White"/> 
           </DataTrigger> 
          </Style.Triggers> 
         </Style> 
        </ContentControl.Style> 
       </ContentControl> 
      </DataTemplate> 
     </Setter.Value> 
    </Setter> 
    <Setter Property="ItemContainerStyle"> 
     <Setter.Value> 
      <Style TargetType="{x:Type ListBoxItem}"> 
       <Setter Property="Background" Value="{StaticResource AppBackground}" /> 
       <Style.Triggers> 
        <Trigger Property="IsSelected" Value="True" > 
         <Setter Property="Background" Value="{StaticResource AppBackground}" /> 
        </Trigger> 
       </Style.Triggers> 
       <Style.Resources> 
        <SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="Transparent"/> 
        <SolidColorBrush x:Key="{x:Static SystemColors.ControlBrushKey}" Color="Transparent" /> 
       </Style.Resources> 
      </Style> 
     </Setter.Value> 
    </Setter> 
    <Setter Property="ItemsPanel"> 
     <Setter.Value> 
      <ItemsPanelTemplate> 
       <WrapPanel /> 
      </ItemsPanelTemplate> 
     </Setter.Value> 
    </Setter> 
    <Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Disabled"/> 
</Style> 

<!-- EndRegion --> 

중요한 것은 다음과 같이 그 스타일이 스타일이를 설정하는 것을 볼 수있다 ItemTemplate을 트리거에 따라 세 가지 값 중 하나로 설정합니다. 이 템플릿 키

입니다 ProcessedResultsTemplate CalculatingResultsTemplate ErroredResultsTemplate 내 리소스 사전에 데이터 템플릿입니다 각각의

.

내가 가진 문제는 각 파생 뷰 모델 유형에 대해 위의 세 가지 데이터 형식 중 하나가 필요하다는 것입니다. 그리고 열쇠로 그들을 참조하고 있습니다. 그리고 같은 키로 사전에 두 항목을 가질 수 없습니다. 예를 들어 "ProcessedResultsTemplate"키가있는 두 개의 데이터 템플릿을 만들면 DataType이 x : CalculationResultsViewModel이고 두 번째 키가 동일한 데이터 유형이 x : Type SpotStressResultsViewModel 인 경우 둘 다 동일한 키를 사용하므로 작동하지 않습니다.

그래서 여기 WPF 다형성 재미를 얻기 위해 이것을 구현하는 정확한 방법이 확실치 않습니다. 그것은 내가 잘못하고있는 기본적인 것입니까?

업데이트 : 아래의 클래스를 사용하여 datatemplate 선택기를 내려 보았습니다. 로직은 올바르게 구현되었지만 문제는 datatemplateselector가 객체가 처음 렌더링 될 때만 호출된다는 것입니다. 원래의 XAML은 특정 종속성 속성이 변경되면 데이터 형식을 변경하도록 트리거했습니다. 트리거 또는 종속성 속성을 사용하여 새 데이터 값에서 데이터 템플릿을 다시 선택하도록 datatemplateselector에 요청하려면 어떻게해야합니까?

class ResultsDataTemplateSelector : DataTemplateSelector 
{ 
    public DataTemplate CalculateOnlyProcessedTemplate { get; set; } 
    public DataTemplate CalculateOnlyCalculatingTemplate { get; set; } 
    public DataTemplate CalculateOnlyErroredTemplate { get; set; } 

    public DataTemplate SpotStressProcessedTemplate { get; set; } 
    public DataTemplate SpotStressCalculatingTemplate { get; set; } 
    public DataTemplate SpotStressErroredTemplate { get; set; } 

    public override DataTemplate SelectTemplate(object item, DependencyObject container) 
    { 
     if (item is CalculationResultsViewModel) 
     { 
      var vm = item as CalculationResultsViewModel; 

      if (vm.ProcessingResult == 1) 
       return CalculateOnlyProcessedTemplate; 

      if (vm.ProcessingResult == -1) 
       return CalculateOnlyErroredTemplate; 

      return CalculateOnlyCalculatingTemplate; 
     } 

     if (item is SpotStressResultsViewModel) 
     { 
      var vm = item as SpotStressResultsViewModel; 

      if (vm.ProcessingResult == 1) 
       return SpotStressProcessedTemplate; 

      if (vm.ProcessingResult == -1) 
       return SpotStressErroredTemplate; 

      return SpotStressCalculatingTemplate; 
     } 

     return null; 
    } 
} 
+0

사전 중 사전? –

답변

3

확실한 해결책은 올바른 템플릿을 선택하는 임의의 복잡한 의사 결정에 대한 DataTemplateSelector을 사용하는 것입니다. 실제 논리를 XAML로 이동하면 고통을 겪을 수 있습니다.

필자는 개인적으로 ViewModels가 뷰, 구성 요구 및 상호 작용에 대한 직접적인 테스트 가능하고 뚜렷한 표현이어야한다고 생각합니다. 시연중인 ViewModel은 뷰를 표현하는 대신 비즈니스 모델 객체로 보이는 것 같습니다.귀하의 ViewModel 층은 묵시적 ​​생성의 책임을 져야한다 :

  • ResultsACalculatingViewModel
  • ResultsAProcessingViewModel
  • ResultsAErrorViewModel
  • ResultsBCalculatingViewModel
  • ResultsBProcessingViewModel
  • ResultsBErrorViewModel을

그리고 당신의보기 코드는 그것들을 스타일링해야합니다. 다형성은 이러한 암시 된 ViewModel을 더 쉽게 구현할 수있는 좋은 방법이지만 UI를 만드는 사람이라면 누구에게도 관심을 가져서는 안됩니다.

관련 문제