0

我对 WPF MVVM (Light) 很陌生,我需要一些帮助。

我所拥有的是一个主细节场景,主视图中的 TabControl,第一个选项卡中的主视图(ProductsView)和以下选项卡中的多个不同的详细信息视图(例如 DetailsView)。

根据 ProductsView 中选择的项目(SelectedProduct),我想在 DetailsView 中获取项目,但不是立即获取 - 仅当用户单击包含此详细信息视图的 tabitem 时。

因此,从数据库中获取详细数据应该以某种方式推迟到用户单击适当的详细信息选项卡时(他可能根本不会单击它)。

这是我的xml:

<!-- 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>

和代码:

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 发送另一条消息,这将更新它的详细数据。

但是我如何根据标签索引仅向当前请求的 tabitem/DetailsView 发送消息,而不是全部发送消息?

而且这种往返听起来太复杂了。你能给我一些建议吗?或者这是完全错误的?也许还有另一种更简单、更优雅的解决方案?

4

3 回答 3

3

通常我也会有我的ViewModel跟踪TabsSelectedTab,并且会简单地加载SelectedTab PropertyChanged事件中的当前选项卡

像这样的东西:

// 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>
于 2012-06-13T18:37:39.647 回答
0

我认为您正在寻找的是经典的 pub / sub 模型。当用户单击选项卡控件项时,将引发名为 RequestViewOfProductDetails 的事件。您将在主视图模型中设置发布,如下所示:

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

然后,在您的详细信息视图模型中,您将设置视图模型以响应该事件:

Messenger.Default.Register<RequestViewOfProductDetails>(this, delegate(Product prod) 
{ 
  // fetch details
});  

您将为每种详细信息类型设置一个消息,在每次选择选项卡项时发布该特定详细信息事件。乏味,我知道,但这将所有选项卡分开。现在如果是我,我会做一些不同的事情。我会在后台工作线程上执行请求,这样您就可以避免针对特定选项卡的这种头痛。选择产品后,只需调度 getter 以异步填充所有选项卡,事情就会透明地发生。

于 2012-06-12T18:44:06.977 回答
0

当您选择详细选项卡时,通过此事件刷新选项卡上的数据。通过事件参数选择的产品。

于 2015-07-28T13:32:58.740 回答