我是WPF MVVM(Light)的新手,我需要一些帮助。
我所拥有的是主要细节场景,主视图中的TabControl,第一个选项卡中的主视图(ProductsView)以及以下选项卡中的多个不同详细信息视图(例如DetailsView)。
根据ProductsView中选择的项目(SelectedProduct),我想在DetailsView中获取项目,但不是立即获取 - 仅当用户单击包含此详细信息视图的tabitem时。
因此,从用户单击相应的详细信息选项卡(他可能根本不会单击它)时,应该以某种方式从数据库中获取详细数据。
这是我的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传递给当前请求的tabitem的DetailsViewModel,更新它的详细数据。
但是我如何仅根据选项卡索引向当前请求的tabitem / DetailsView发送消息,而不是全部?
此次往返听起来太复杂了。你能给我一些建议吗? 或者这完全错了? 也许还有另一种更简单,更优雅的解决方案吗?
答案 0 :(得分:3)
通常我会ViewModel
跟踪Tabs
和SelectedTab
,并只会加载SelectedTab
PropertyChanged
事件中的当前标签< / p>
这样的事情:
// 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>
答案 1 :(得分:0)
我认为您正在寻找的是经典的pub / sub模型。当用户单击选项卡控件项时,会引发一个名为RequestViewOfProductDetails的事件。您可以使用以下内容在主视图模型中设置发布:
public MasterViewModel()
{
Messenger.Default.Send<RequestViewOfProductDetails>(_selectedProduct);
}
然后,在您的详细信息视图模型中,您将设置视图模型以响应该事件:
Messenger.Default.Register<RequestViewOfProductDetails>(this, delegate(Product prod)
{
// fetch details
});
您可以为每种详细信息类型设置一个消息,在每个选项卡项上发布该特定详细信息事件。我知道,单调乏味,但将所有标签分开。现在,如果是我,我会做一些与众不同的事情。我会在后台工作线程上执行请求,因此您可以避免将特定选项卡作为目标。选择产品后,只需调度getter以异步填充所有选项卡,并且事情透明地发生。
答案 2 :(得分:0)
选择详细信息选项卡后,通过此事件刷新Tab上的数据。通过事件参数选择产品。