0

私は WPF MVVM (Light) を初めて使用するので、助けが必要です。

私が持っているのは、マスター/詳細シナリオ、メイン ビューの TabControl、最初のタブのマスター ビュー (ProductsView)、および次のタブの複数の異なる詳細ビュー (例: DetailsView) です。

ProductsView で選択された項目 (SelectedProduct) に応じて、DetailsView で項目を取得したいのですが、すぐには取得したくありません。ユーザーがこの詳細ビューを含むタブ項目をクリックしたときだけです。

そのため、データベースからの詳細データの取得は、ユーザーが適切な詳細タブをクリックするまで延期する必要があります (まったくクリックしない可能性があります)。

これが私のxamlです:

<!-- 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はSelectedProductを現在要求されているタブアイテムのDetailsViewModelに渡す別のメッセージをタブインデックスに基づいて送信する必要があります。詳細データを更新します。

しかし、すべてではなく、タブ インデックスに基づいて、現在要求されている tabitem/DetailsView にのみメッセージを送信するにはどうすればよいでしょうか。

また、このラウンドトリップは複雑すぎるように思えます。いくつか提案をいただけますか?それとも、これは完全に間違っていますか?たぶん、これに対する別の、よりシンプルでエレガントなソリューションがありますか?

4

3 に答える 3

3

通常、私は自分のViewModelトラックTabsを持ち、イベントSelectedTabで現在のタブをロードするだけです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

あなたが探しているのはクラシックなパブ/サブ モデルだと思います。ユーザーがタブ コントロール項目をクリックしたときに発生する RequestViewOfProductDetails というイベントを持つもの。次のようなものを使用して、プライマリ ビュー モデルでパブリッシュを設定します。

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

次に、詳細ビュー モデルで、そのイベントに応答するようにビュー モデルを設定します。

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

そして、詳細タイプごとにメッセージを設定し、タブ項目を選択するたびに特定の詳細イベントを公開します。面倒ですが、それはすべてのタブを分離します。今の私だったら、違うことをするでしょう。バックグラウンド ワーカー スレッドでリクエストを行うので、特定のタブをターゲットにするという頭痛の種を回避できます。製品が選択されたら、ゲッターをディスパッチしてすべてのタブを非同期的に埋めるだけで、物事は透過的に行われます。

于 2012-06-12T18:44:06.977 に答える
0

詳細タブを選択すると、このイベントによってタブのデータが更新されます。イベント パラメータで選択した製品を渡します。

于 2015-07-28T13:32:58.740 に答える