2

I have a list view and 2 resources for display the list's view: BooksGridView & ImageDetailView.

The ViewModel has a string property named ViewMode, which contains the name of the view i currently want to display. (It is changed from another control, using toolbars)

I am trying to change the selected view by using DataTrigger, but I cant seem to get the View property to change.

When i set the View resource directly, the correct view is displayed. I also added background changes to make sure the data trigger is activated, and the background did change.

So I'm obviously missing something here...

<UserControl x:Class="eLibrary.View.FilteredBooksView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:Converters="clr-namespace:eLibrary.Converters"
             xmlns:Controls="clr-namespace:eLibrary.Controls"
             xmlns:scm="clr-namespace:System.ComponentModel;assembly=WindowsBase"
             xmlns:local="clr-namespace:eLibrary"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    <UserControl.Resources>
        <Converters:CoverImageConverter x:Key="CoverImageConverter"/>
        <BooleanToVisibilityConverter x:Key="BoolToVisConverter" />

        <GridView x:Key="BooksGridView">
            ...
        </GridView>

        <Controls:TileView x:Key="ImageDetailView">
            ...
        </Controls:TileView>

        <CollectionViewSource x:Key="sortedBooks" Source="{Binding Books}">
            <CollectionViewSource.SortDescriptions>
                <scm:SortDescription PropertyName="Title" Direction="Ascending"/>
            </CollectionViewSource.SortDescriptions>
        </CollectionViewSource>

        <Style TargetType="{x:Type ListView}">
            <Style.Triggers>

                <DataTrigger Binding="{Binding Path=ViewMode}" Value="BooksGridView">
                    <Setter Property="View" Value="{StaticResource BooksGridView}"/>
                    <Setter Property="Background" Value="Red"/>
                </DataTrigger>

                <DataTrigger Binding="{Binding Path=ViewMode}" Value="ImageDetailView">
                    <Setter Property="View" Value="{StaticResource ImageDetailView}" />
                    <Setter Property="Background" Value="Blue"/>
                </DataTrigger>

            </Style.Triggers>
        </Style>

    </UserControl.Resources>

    <ListView
        VerticalAlignment="Stretch"
        Name="BooksListView"
        View="{StaticResource BooksGridView}"
        SelectionMode="Extended"
        ItemsSource="{Binding Source={StaticResource sortedBooks}}">
        <ListView.Resources>
            <Style TargetType="{x:Type ListViewItem}">
                <Setter Property="IsSelected" Value="{Binding Path=IsSelected, Mode=TwoWay}" />
                <Setter Property="Visibility" Value="{Binding Path=ShouldDisplay, Converter={StaticResource BoolToVisConverter} }" />
            </Style>
        </ListView.Resources>
    </ListView>

</UserControl>

Thanks

Amirshk
  • 8,170
  • 2
  • 35
  • 64

2 Answers2

14

Based off the sample on MSDN, the following works at changing the view based on a change in the ViewModel. The only difference I can see with your code is the use of DynamicResource:

<Window x:Class="SDKSample.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Custom View" 
    xmlns:l="clr-namespace:SDKSample" 
    Width="400" Height="500"
    SourceInitialized="Window_SourceInitialized">

    <Window.Resources>

      <DataTemplate x:Key="centralTile">
        <StackPanel Height="100" Width="90">
          <Grid Width="70" Height="70" HorizontalAlignment="Center">
            <Image Source="{Binding XPath=@Image}" Margin="6,6,6,9"/>
          </Grid>
          <TextBlock Text="{Binding XPath=@Name}" FontSize="13" 
                     HorizontalAlignment="Center" Margin="0,0,0,1" />
          <TextBlock Text="{Binding XPath=@Type}" FontSize="9" 
                     HorizontalAlignment="Center" Margin="0,0,0,1" />
        </StackPanel>
      </DataTemplate>

      <DataTemplate x:Key="iconTemplate">
        <DockPanel Height="33" Width="150">
          <Image Source="{Binding XPath=@Image}" Margin="2"/>
          <TextBlock DockPanel.Dock="Top" Text="{Binding XPath=@Name}" 
                     FontSize="13" HorizontalAlignment="Left" 
                     Margin="0,0,0,1" />
          <TextBlock Text="{Binding XPath=@Type}" FontSize="9" 
                     HorizontalAlignment="Left" Margin="0,0,0,1" />
        </DockPanel>
      </DataTemplate>

      <DataTemplate x:Key="checkbox">
        <CheckBox IsChecked="{Binding IsSelected, RelativeSource= {RelativeSource AncestorType=ListViewItem}}" 
                  Margin="0,1,1,1" >
        </CheckBox>
      </DataTemplate>

      <XmlDataProvider x:Key="myXmlDataBase" XPath="/myXmlData">
        <x:XData>
          <myXmlData xmlns="">
            <Item Name = "Fish" Type="fish" Image="images\fish.png"/>
            <Item Name = "Dog" Type="animal" Image="images\dog.png"/>
            <Item Name = "Flower" Type="plant" Image="images\flower.jpg"/>
            <Item Name = "Cat" Type="animal" Image="images\cat.png"/>
          </myXmlData>
        </x:XData>
      </XmlDataProvider>

      <DataTemplate x:Key="DisplayImage">
        <StackPanel Width="50">
          <Image Source="{Binding XPath=@Image}"/>
        </StackPanel>
      </DataTemplate>

      <GridView x:Key="gridView">
        <GridViewColumn CellTemplate="{StaticResource checkbox}"/>
        <GridViewColumn Header="Name" DisplayMemberBinding="{Binding XPath=@Name}"/>
        <GridViewColumn Header="Type" DisplayMemberBinding="{Binding XPath=@Type}"/>
        <GridViewColumn Header="Image" CellTemplate="{StaticResource DisplayImage}"/>
      </GridView>
      <l:PlainView x:Key="tileView" ItemTemplate="{StaticResource centralTile}" ItemWidth="100"/>
      <l:PlainView x:Key="iconView" ItemTemplate="{StaticResource iconTemplate}"  ItemWidth="150"/>

    <Style TargetType="{x:Type ListView}">
        <Style.Triggers>
            <DataTrigger Binding="{Binding Path=ViewName}" Value="iconView">
                <Setter Property="View" Value="{DynamicResource iconView}"/>
            </DataTrigger>
            <DataTrigger Binding="{Binding Path=ViewName}" Value="tileView">
                <Setter Property="View" Value="{DynamicResource tileView}" />
            </DataTrigger>
            <DataTrigger Binding="{Binding Path=ViewName}" Value="gridView">
                <Setter Property="View" Value="{DynamicResource gridView}" />
            </DataTrigger>
        </Style.Triggers>
    </Style>

    </Window.Resources>

  <StackPanel>
    <ListView Name="lv"
              ItemsSource="{Binding Source={StaticResource myXmlDataBase}, XPath=Item}" 
              FontSize="12" 
              Background="LightBlue" >
      <ListView.ContextMenu>
        <ContextMenu>
          <MenuItem Header="gridView" Click="SwitchViewMenu"/>
          <MenuItem Header="iconView" Click="SwitchViewMenu"/>
          <MenuItem Header="tileView" Click="SwitchViewMenu"/>
        </ContextMenu>
      </ListView.ContextMenu>


    </ListView>
    <TextBlock FontSize="16" Foreground="Blue">
      CurrentView: <TextBlock Name="currentView" Text="{Binding Path=ViewName}"/>
    </TextBlock>
    <TextBlock>
      Right-click in the content window to change the view.
      </TextBlock>

  </StackPanel>
 </Window>

Code behind file:

using System;
using System.Windows;
using System.Windows.Controls;

namespace SDKSample
{
    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>

    public partial class Window1 : Window
    {
        public Window1()
        {
            InitializeComponent();
        }

        public MainViewModel ViewModel
        {
            get { return this.DataContext as MainViewModel; }
        }

        void SwitchViewMenu(object sender, RoutedEventArgs args)
        {
            MenuItem mi = (MenuItem)sender;
            ViewModel.ViewName = mi.Header.ToString();
        }

        private void Window_SourceInitialized(object sender, EventArgs e)
        {
            ViewModel.ViewName = "gridView";
        }
    }
}

And finally the ViewModel class:

using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;

namespace SDKSample
{
    public class MainViewModel : INotifyPropertyChanged
    {
        public string ViewName
        {
            get { return viewName; }
            set
            {
                if (viewName == value)
                    return;

                viewName = value;
                NotifyPropertyChanged("ViewName");
            }
        }
        private string viewName;

        public event PropertyChangedEventHandler PropertyChanged;

        void NotifyPropertyChanged(string name)
        {
            if (this.PropertyChanged != null)
                this.PropertyChanged(this, new PropertyChangedEventArgs(name));
        }
    }
}
Grammarian
  • 6,774
  • 1
  • 18
  • 32
  • 1
    Thanks!, Two changes that made it work: The first was the DynamicResource, and the second was removing the initial View definition under the ListView. – Amirshk Nov 15 '10 at 23:48
  • Can u pls post the href for the MSDN example – Amirshk Nov 16 '10 at 17:52
  • http://msdn.microsoft.com/en-us/library/ms771469(v=VS.85).aspx The main difference is that they use code behind rather than triggers. – Grammarian Nov 16 '10 at 21:50
0

I cannot see any obvious issue with your code you provided. I would usually suggest checking that the DataTrigger is being trigger, however you have already tested that with the Background property.

Looking at sample on MSDN (link) the only difference in implementation is that, in the sample, switch the ListView.View is changed in code.

BookListView.View = this.FindResource("BooksGridView") as ViewBase;

...

Hmm, perhaps the view resource may not be able to found and it is failing.

...

All I can suggest is look at the sample. Sorry couldn't be much more help.

Dennis
  • 20,275
  • 4
  • 64
  • 80
  • Tnx, But I made sure the resource can be found by setting an illegal value which caused an exception. So its seems it finds the resource and even activates the trigger, yet for some reason the view isn't changed. – Amirshk Nov 10 '10 at 23:29