开发者

MVVM data templates and non-direct data mapping

I've been using mvvm to develop a RIA service sl4 app and i seem to be missing something.

The MVVM and databinding works nice when your da开发者_StackOverflowta comes in the expected format for editing or when your data objects "fits the view" (grids, lists, etc). But what happens when your data doesn't really map directly?

My example

Lets say i have a product table, this defines the product its price and options. And i have a subscribed product table that will link the product and client and also have data on when the subscription ends etc...

So when i started working on my view for a "shopping list" i did this:

    <ListBox x:Name="ShopList" Grid.Row="0" ItemsSource="{Binding Products}">
        <DataTemplate>
            <StackPanel Orientation="Horizontal">
                <sdk:Label Content="{Binding ModuleName}" />
                <sdk:Label Content="{Binding DateStart, Converter={StaticResource gridDateFormatter}}" />
                <sdk:Label Content="{Binding DateEnd, Converter={StaticResource gridDateFormatter}}" />
                <telerik:RadMaskedTextBox MaskedText="{Binding UnitsToBuy}" />
                <sdk:Label Content="{Binding UnitStep}" />
                <sdk:Label Content="{Binding TotalPrice}" />
            </StackPanel>
        </DataTemplate>
    </ListBox>

So i thought well I'm gonna bind ItemsSource with a Observable collection on my ViewModel

public ObservableCollection<Product> Products

But now i have a problem, the UnitsToBuy is something not in the Product, and doesn't belong on the product. I'm strugling on how to find a clean way to deal with these kinds of scenario. Do assume i can have any number of items in that list.

Thanks.


I think what you're asking boils down to the fact that the view needs a viewmodel with more properties, not a simple model. Why not have something like this. Obviously the classes below should implement INotifyPropertyChanged.

public class CartItem
{
  public Product Product {get;set;}
  public int UnitsToBuy {get;set;}
  public int UnitsStep {get;set;}
  public decimal TotalPrice
  {
    get { return Product.Price * UnitsToBuy;}
  }
  //more properties can be added if needed
}

public class ShoppingCartViewModel
{
  public ObservableCollection<CartItem> Products {get;set;}
}

and then in xaml you don't really need to make any changes.


I'd create a new Model class that will contain what you need from Product and SubscribedProduct. You can then create a Mapper of sorts that will convert the more view-centric Model to your data-centric Model(s) (Product and SubscribedProduct).


I always build my Views specifically for a Model or group of Models. Because of this, I know what properties to expect, and which ones may be missing.

If I know a property can be missing, I will write a DataTrigger to alter the view based on the data

For example, if I had a View that was supposed to be display Products and SubscribedProducts, I might use a DataTrigger to determine what DataTemplate to display

<Style TargetType="ListBoxItem">
    <Setter Property="Template" Value="{StaticResource DefaultProductTemplate}" />
    <Style.Triggers>
        <DataTrigger Binding="{Binding Converter={StaticResource ObjectToTypeConverter}}" Value="{x:Type local:SubscribedProductModel}">
            <Setter Property="Template" Value="{StaticResource SubscribedProductTemplate}" />
        </DataTrigger>
    </Style.Triggers>
</Style>
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜