2

I'm looking for the correct way to switch between different views. My scenario is similar to the Widnows Explorer on Windows 8, where you can switch between 'extra large icons', 'small icons', 'details', etc. In Windows 8 The users do that from the 'View' ribbon of explorer (you can also change view in XP and 7).

In my case, I've a list of friends, and I want to let the user switch between 'small', 'large', and 'details' view.

Assume my view model has a list of friends:

public class FriendVM {
    public name { get; set; }
    public smallImage { get; set; }
    public largeImage { get; set; }
};

public class MainVM : INotifyPropertyChanged {
    public ObservableCollection<FriendVM> friends { get; set; }

    private string m_viewMode
    public string viewMode { 
        get { return m_viewMode; }
        set { m_viewMode=value; this.PropertyChanged( new PropertyChangedEventArags("viewMode") ); }
    }
}

In my view, I've a ribbon (on which user can change viewMode), a header (showing details about the user), and a list of friends. Depends on the view, I want to show:

  • when viewMode = "details" I've a ListView, with a GridView.
  • when viewMode = "small" I've a ListView, with ItemsPanel is a WrapPanel, and I bind the image to the smallImage
  • when viewMode = "large" I've a ListView with WrapPanel, using the largeImage property.

Here is how my XML looks like (simplified):

<Window x:Class="friends.MainWindow" ... xmlns:f="clr-namespace:friends" ...>
    <Window.DataContext>
        <f:MainVM />
    <Window.DataContext>

    <Window.Resources>
        <ControlTemplate x:Key="details">
            <ListView ItemsSource="{Binding Path=friends}">
                <ListView.View>
                    <GridView>
                        ...
                    </GridView>
            </ListView.View>
        </ControlTemplate>

        <ControlTemplate x:Key="small">
            <ListView ItemsSource="{Binding Path=friends}">
                <ListView.ItemsPanel><WrapPanel Orientation="Horizontal" />
            </ListView>
            <ListView.ItemTemplate><DataTemplate>
                <Image Source={Binding smallPicture} Width="32" Height="32" />
            </DataTemplate></ListView.ItemTemplate>
        </ControlTemplate>


        <ControlTemplate x:Key="large">
            <ListView ItemsSource="{Binding Path=friends}">
                <ListView.ItemsPanel><WrapPanel Orientation="Horizontal" />
            </ListView>
            <ListView.ItemTemplate><DataTemplate>
                <StackPanel>
                    <Image Source="{Binding largePicture}" Width="200" Height="200" />
                    <TextBlock Text="{Binding name}" />
                </StackPanel>
            </DataTemplate></ListView.ItemTemplate>
        </ControlTemplate>

    </Window.Resource>


    <DockPanel LastChildFill="True">

        <Ribbon ...>
            ...
        </Ribbon>

        <StackPanel>
            ... some header stuff
        </StackPanel>

        <ContentControl x:Name="friendList" Content="{Binding friends}" ?????? />
    </DockPanel>

</Window>

So, my question is what do I do in the ????? area. Right now, I've Template="{StaticResource small}" and it is working. Moreover, using code behind I can change the Template to any of the other resourced template (using FindResource). However, I'm not happy with this solution, as I feel it doesn't go well with MVVM pattern. If it was an "Item" (a listbox item, a tab item, etc.), then I could use a data template, and then a date template selector. But since this is a ContentControl, and ControlTemplateSelector seems to be completely broken from the design, I'm not sure what should I do.

Or, if I could put the list of friends "as is" in the tree, then maybe using data template (having TargetType=f:FriendList) I could make it work, but I don't want to instantiate another friend list. There is already one instance instantiated within the DataContext element.

Uri London
  • 10,631
  • 5
  • 51
  • 81

0 Answers0