WPF: Setting ListView View via DataTrigger

10,494

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));
        }
    }
}
Share:
10,494
Amirshk
Author by

Amirshk

Eager learner.

Updated on June 04, 2022

Comments

  • Amirshk
    Amirshk almost 2 years

    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
    Amirshk over 13 years
    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
    Amirshk over 13 years
    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
    Amirshk over 13 years
    Can u pls post the href for the MSDN example
  • Grammarian
    Grammarian over 13 years
    msdn.microsoft.com/en-us/library/ms771469(v=VS.85).aspx The main difference is that they use code behind rather than triggers.