0

I don't know how to trigger template selector manually (at button click). At load time the Template1 is used, but want to change at btn press with Temaplte2. Is there something similar with OnPorpertyChanged?

I am reffering to the <ItemsControl x:Name="OptionItemsControl" ItemTemplateSelector="{StaticResource optionItemTemplateSelector}" - I want to trigger ItemTemplateSelector change...

<!-- BODY (elements)-->
        <FlipView x:Name="OptionPagesFlipView"  Grid.Row="1" TabNavigation="Cycle" SelectionChanged="OptionPagesFlipView_SelectionChanged" ItemsSource="{Binding OptionsPageItems}">
            <FlipView.ItemTemplate>
                <DataTemplate x:Name="OptionMonthPageTemplate">
                    <ScrollViewer x:Name="OptionsScrollViewer" HorizontalScrollMode="Disabled" HorizontalAlignment="Stretch" VerticalScrollBarVisibility="Auto">
                        <Grid>
                            <ItemsControl x:Name="OptionItemsControl" ItemTemplateSelector="{StaticResource optionItemTemplateSelector}" ItemsSource="{Binding OptionItems, Mode=OneWay}" Visibility="{Binding OptionsPageVisibility}">                                
                            </ItemsControl>
                            <Grid x:Name="LoadingGrid" HorizontalAlignment="Center" VerticalAlignment="Center" Visibility="{Binding LoadingGridVisibility}">
                                <Grid.RowDefinitions>
                                    <RowDefinition/>
                                </Grid.RowDefinitions>
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition/>
                                    <ColumnDefinition/>
                                </Grid.ColumnDefinitions>
                                <ProgressRing x:Name="CustomProgressRing" Height="40" Width="40" IsActive="true" Grid.Column="0" Margin="20" Foreground="White"/>
                                <TextBlock Text="Loading Data" x:Name="CustomTextBlock" Height="auto" Width="auto" FontSize="25" Grid.Column="1" Margin="20"/>
                            </Grid>
                        </Grid>
                    </ScrollViewer>
                </DataTemplate>
            </FlipView.ItemTemplate>

and the resources:

<UserControl.Resources>
    <DataTemplate x:Key="template1">
        <Grid x:Name="OptionItemGrid" Background="White" HorizontalAlignment="Stretch">
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="Auto"/>
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*" />
                <ColumnDefinition Width="*" />
                <ColumnDefinition Width="*" />
                <ColumnDefinition Width="*" />
                <ColumnDefinition Width="*" />
            </Grid.ColumnDefinitions>
            <!-- Content -->    
        </Grid>
    </DataTemplate>
    <DataTemplate x:Name="template2">
        <Grid x:Name="OptionItemGrid" Background="White" HorizontalAlignment="Stretch">
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="Auto"/>
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*" />
                <ColumnDefinition Width="*" />
                <ColumnDefinition Width="*" />
            </Grid.ColumnDefinitions>
            <!-- Content -->
        </Grid>
    </DataTemplate>

    <local:OptionDataItemTemplateSelector x:Key="optionItemTemplateSelector"
      Template1="{StaticResource template1}"
      Template2="{StaticResource template2}"/>
</UserControl.Resources>

and Template selector class:

public class OptionDataItemTemplateSelector : DataTemplateSelector
{

    public DataTemplate Template1 { get; set; }
    public DataTemplate Template2 { get; set; }

    protected override Windows.UI.Xaml.DataTemplate SelectTemplateCore(object item, Windows.UI.Xaml.DependencyObject container)
    {
        if(someCondition == 1)
            return Template1;
        else
            return Template2;         
    }
}
Alexandru Circus
  • 5,478
  • 7
  • 52
  • 89

2 Answers2

1

ItemTemplateSelector cannot be triggered unless the ItemsSource or Item's instance in the ItemsSource is not changed. So what you want to achieve using ItemTemplateSelector is bit twisted. The simple way of doing this would be to have a property on your ViewModel/CodeBehind say

bool IsClicked
{
   get{return _isClicked;}
   set
   { 
     _isClicked = value
     RaisePropertyChanged("IsClicked");
   }
}

and in the CommandHandler of button or Click event Handler toggle this property.

Now you can define just one template for your Items like below and switch its ContentTemplate depending on the property above:

  <DataTemplate x:Key="myTemplate">
     <ContentControl Content="{Binding}">
       <ContentControl.Style>
           <Style TargetType="ContentControl">
             <Setter Property="ContentTemplate" Value="{StaticResource template1}"/>
              <Style.Triggers>
                  <DataTrigger Binding="{Binding DataContext.IsClicked, RelativeSource={RelativeSource AncestorType={x:Type Window}}}" Value="false">
                       <Setter Property="ContentTemplate" Value="{StaticResource template2}"/>
                   </DataTrigger
              </Style.Triggers>
           </Style>
       </ContentControl.Style>
     </ContentControl>
  </DataTemplate>
Nitin
  • 18,344
  • 2
  • 36
  • 53
  • What I want to achieve is that when I press a button the content of the ItemControl to be changed. I defined for this 2 DataTemplates and I'm using TemplateSelector to switch between these 2 templates. I don't know if this is right way to do it... – Alexandru Circus Oct 23 '13 at 06:12
  • thats what i explained in the answer.. template selector cannot be triggered in this way.. you will have to reset the ItemsSource of your control on button click in order to fire the templateselector.. or you can use the property like explained in my answer and use triggers – Nitin Oct 23 '13 at 06:17
  • @nit I cannot agree completely on what you said about calling template selector only when ItemsSource properly changed. I hope I didnt understand you wrong. Template selector works on items-level and not on complete ListBox-level. Whenever you add an item or replace item the template selector will be called for that specific item. Else if the template selector would only listen to ItemsSource property changed it would never be applied on new added items since ItemsSource property is not changed when adding items. – dev hedgehog Oct 23 '13 at 06:51
  • The problem is I cannot use Style.Triggers (not available in windows store apps) so I must convert your xaml code to use VisualStateManager...let's see if I can make it(I'm a c#/windows beginner) – Alexandru Circus Oct 23 '13 at 06:58
  • And If I call OnpropertyChanged on my items list does not trigger the selector – Alexandru Circus Oct 23 '13 at 07:00
  • yes @devhedgehog you are correct.. but here Alexandru is not adding or removing items.. he just wants to trigger the templateselector and change the template for all the items on some user action which is not possible unless all the items are removed and readded to teh itemsSource or ItemsSource in itself is reset – Nitin Oct 23 '13 at 07:02
  • @AlexandruCircus just raising the PropertyChange wont trigger it.. you will have to actually change the reference of your ItemsSource and then RaisePropertyChange.. – Nitin Oct 23 '13 at 07:04
  • @nit - thanks for your answer - this will cost too much (re-instantiate all items) so I will focus to change that ContentControl.Style with VisualStateManager – Alexandru Circus Oct 23 '13 at 07:08
  • 1
    @AlexandruCircus nit already gave you a great idea with datatriggers. btw check this out: http://stackoverflow.com/questions/2085467/explicitly-refresh-datatemplate-from-a-datatemplateselector – dev hedgehog Oct 23 '13 at 07:32
  • @devhedgehog - thanks for pointing this out - it seems I found my way :). I will make the dataTemplate a ContentControl and use a trigger to change the ContentTemplate – Alexandru Circus Oct 23 '13 at 07:39
0

How about run through your items and set someCondition not to 1?

protected override Windows.UI.Xaml.DataTemplate SelectTemplateCore(object item, DependencyObject container)
{
    if(ITEM.someCondition == 1)
        return Template1;
    else
        return Template2;         
}

Inside SelectTemplate method you have all information you need. The item is coming from data source and the container which is the current visual for your data source item. Use those information to decide which template.

Change the condition and another template will be returned.

dev hedgehog
  • 8,698
  • 3
  • 28
  • 55
  • The condition is a hardcoded one. It loads fine, but IF I WANT TO CHANGE the template AFTER the initial load? I want to run through the SelectTemplate method at some button click in order to return Template2(of course I've set someCondition to 2 at btn click).... – Alexandru Circus Oct 23 '13 at 05:33
  • That is not possible without a bit of hacking. – dev hedgehog Oct 23 '13 at 07:29