2012-06-12 1 views
0

저는 WPF MVVM (Light)에 익숙하지 않아 도움이 필요합니다.WPF MVVM TabControl의 라이트 마스터 디테일, 메시지를 사용하여 선택된 항목 전달

내가 가진 것은 마스터 세부 정보 시나리오, 기본보기의 TabControl, 첫 번째 탭의 마스터보기 (제품보기) 및 다음 탭의 여러 가지 세부 정보보기 (예 : DetailsView)입니다.

ProductsView에서 선택한 항목 (SelectedProduct)에 따라 DetailsView에서 항목을 가져오고 싶지만 사용자가이 상세보기가 포함 된 tabitem을 클릭 할 때만 즉시 가져올 수 있습니다.

데이터베이스에서 세부 정보 데이터를 가져 오는 것이 사용자가 적절한 세부 정보 탭을 클릭 할 때까지 지연되어야합니다. 그는 클릭하지 않을 수도 있습니다.

<!-- Main View --> 
<UserControl x:Class="MyApp.Views.MainView"> 
    <TabControl> 
    <TabControl.Items> 
     <TabItem> 
     <views:ProductsView /> 
     </TabItem> 
     <TabItem> 
     <views:DetailsView /> 
     </TabItem> 
     <!-- More TabItems with details views --> 
    </TabControl.Items> 
    </TabControl> 
</UserControl> 

<!-- Products View --> 
<UserControl x:Class="MyApp.Views.ProductsView"> 
    <Grid DataContext="{Binding Source={StaticResource Locator}, Path=ProductsVM}"> 
    <DataGrid ItemsSource="{Binding Products}" SelectedItem="{Binding SelectedProduct}"> 
     <DataGridTextColumn Binding="{Binding Path=Model.ProductID}" Header="Product ID" /> 
    </DataGrid> 
    </Grid> 
</UserControl> 

<!-- Details View --> 
<UserControl x:Class="MyApp.Views.DetailsView"> 
    <Grid DataContext="{Binding Source={StaticResource Locator}, Path=DetailsVM.Details}"> 
    <StackPanel> 
     <TextBox Text="{Binding Path=Model.Field1}" /> 
     <TextBox Text="{Binding Path=Model.Field2}" /> 
    </StackPanel> 
    </Grid> 
</UserControl> 

그리고 코드 :

여기 내 XAML의

public class ProductsViewModel : ViewModelBase 
{ 
    private ObservableCollection<Product> products; 
    public ObservableCollection<Product> Products 
    { 
     get 
     { 
      return products; 
     } 
     set 
     { // RaisePropertyChanged 
      Set("Products", ref products, value); 
     } 
    } 

    private Product selectedProduct; 
    public Product SelectedProduct 
    { 
     get 
     { 
      return selectedProduct; 
     } 
     set 
     { // RaisePropertyChanged and broadcast message of type PropertyChangedMessage<Product> 
      Set("SelectedProduct", ref selectedProduct, value, true); 
     } 
    } 

    public ProductsViewModel(IDataService dataService) 
    { 
     this.dataService = dataService; 
     Products = dataService.GetAllProducts(); 
    } 
} 

public class DetailsViewModel : ViewModelBase 
{ 
    private Details details; 
    public Details Details 
    { 
     get 
     { 
      return details; 
     } 
     set 
     { // RaisePropertyChanged 
      Set("Details", ref details, value); 
     } 
    } 

    public DetailsViewModel(IDataService dataService) 
    { 
     this.dataService = dataService; 
     Messenger.Default.Register<PropertyChangedMessage<Product>>(this, m => Details = dataService.GetDetails(m.NewValue.Model.ProductID)); 
    } 
} 

지금이 작동하지만 제품 선택 후, 모든 세부 사항은 모든 세부 사항 탭에서 바로 인출된다. 사용자가 MainView에서 탭을 클릭하면 MainViewModel이 탭 인덱스가있는 메시지를 ProductviewModel에 보내야하고 ProductViewModel이 탭 인덱스를 기반으로 현재 요청 된 tabitem의 DetailsViewModel에 SelectedProduct를 전달하는 다른 메시지를 보내야한다고 생각했습니다. 세부 데이터를 업데이트합니다.

하지만 현재 요청한 tabitem/DetailsView에 대해서만 메시지를 보내려면 어떻게해야합니까?

또한이 라운드 트립 핑은 너무 복잡합니다. 나에게 몇 가지 제안을 해줄 수 있니? 아니면 완전히 잘못입니까? 어쩌면 거기에 또 다른, 더 간단하고 우아한 해결책이 있습니까?

답변

0

당신이 찾고있는 것은 고전적인 pub/sub 모델입니다. 사용자가 탭 컨트롤 항목을 클릭하면 RequestViewOfProductDetails라는 이벤트가 발생합니다.

Messenger.Default.Register<RequestViewOfProductDetails>(this, delegate(Product prod) 
{ 
    // fetch details 
}); 
: 당신의 세부 모델을 볼에

public MasterViewModel() 
{ 
    Messenger.Default.Send<RequestViewOfProductDetails>(_selectedProduct); 
} 

그런 다음, 해당 이벤트에 응답 할 뷰 모델을 설정합니다 : 당신은 이런 일에 기본 뷰 모델에 게시 설정할 것

그리고 각 세부 유형에 대한 메시지를 설정하고 탭 항목의 각 선택 항목에 해당 세부 사항 이벤트를 게시하십시오. 지겨운, 알아,하지만 그건 모든 탭을 구분합니다. 이제 그것이 나라면 다른 것을 할 것입니다. 백그라운드 작업자 스레드에 대한 요청을 수행하므로 특정 탭을 대상으로하는이 두통을 피할 수 있습니다. 제품을 선택하고 나면 모든 탭을 비동기 적으로 채우기 위해 getter를 전달하면 모든 것이 투명하게 처리됩니다.

3

일반적으로 내 ViewModelTabsSelectedTab뿐만 아니라 추적 할 것, 단순히 SelectedTabPropertyChanged 경우에이 같은

뭔가 현재 탭을로드합니다 :

// Not expanding these to full properties with property change 
// notifications for sake of simplicity here 
ObservableCollection<ViewModelBase> Tabs; 
ViewModelBase SelectedTab; 

void MyViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e) 
{ 
    if (e.PropertyName == "SelectedTab") 
    { 
     if (SelectedTab is IDetailsTab) 
      ((IDetailsTab)SelectedTab).LoadProduct(SelectedProduct); 

      // Or depending on your structure: 
      var productsTab = Tabs[0] as ProductsViewModel; 
      ((IDetailsTab)SelectedTab).LoadProduct(productsTab.SelectedProduct); 
    } 
} 

을하고 XAML은 보일 것이다 이렇게 :

<TabControl ItemsSource="{Binding Tabs}" SelectedItem="{Binding SelectedTab}"> 
    <TabControl.Resources> 
     <DataTemplate DataType="{x:Type local:ProductsViewModel}"> 
      <local:ProductsView /> 
     </DataTemplate> 
     <DataTemplate DataType="{x:Type local:DetailsViewModel}"> 
      <local:DetailsView /> 
     </DataTemplate> 
    </TabControl.Resources> 
</TabControl> 
0

세부 정보 탭을 선택하면 새로 고침 이 이벤트에 의해 Tab에. 선택된 제품을 이벤트 매개 변수와 함께 전달하십시오.

관련 문제