XAML ListView - Change Image Source for selected item

﹥>﹥吖頭↗ 提交于 2019-12-20 04:06:39

问题


I'm using a ListView with a Custom Template, something like this:

<ListView.ItemTemplate>
    <DataTemplate>
        <Grid HorizontalAlignment="Center" Width="220" Height="220">
            <Image x:Name="image" Stretch="UniformToFill" 
                    Source="{Binding Brand.Image, 
                             ConverterParameter=transparent, 
                             Converter={StaticResource LogoToUriConverter}}"/>
            <StackPanel VerticalAlignment="Bottom">
                <TextBlock Text="{Binding Name}" 
                            Foreground="{StaticResource ApplicationColor}" 
                            Style="{StaticResource TitleTextStyle}" 
                            Height="30" Margin="15,0,15,0"/>
                <TextBlock Text="{Binding Name}" 
                            Foreground="{StaticResource ApplicationColor}" 
                            Style="{StaticResource CaptionTextStyle}" 
                            TextWrapping="NoWrap" Margin="15,0,15,10"/>
            </StackPanel>
        </Grid>
    </DataTemplate>
</ListView.ItemTemplate>

Now when an Item is selected I would like to have the image source for selected item changed to a new one.

Brand.Image is not a DependencyProperty because it comes from an external DataObject.

So, I think that in WPF I could use a Trigger to change it manually.

But since in winRT it does not work anymore, I've looked into VSM, but I'm not figuring out how can I accomplish that.

Can someone provide me a real example how could it be done?

Thank you


回答1:


I was able to solve this, in a tricky way, but I got it to work:

  1. Using an ExtendedVisualStateManager, (it was available for .NET through ExpressionBlend dlls, but not for WinRT, so I got it from here: http://nroute.codeplex.com/SourceControl/changeset/69480#nRoute5/nRoute.Framework.Metro/Components/ExtendedVisualStateManager.cs)

  2. Having that I just catch an OnSelected Event and use the new VisualStateManager to do that:

    ExtendedVisualStateManager.GoToElementState(sender as Grid, "Selected2", true);

Here's the full XAML for the ItemTemplate:

<DataTemplate>
<Grid x:Name="ItemGrid" HorizontalAlignment="Center" Width="220" Height="220" PointerPressed="GridItemTapped">
    <Image x:Name="image" Stretch="UniformToFill" Source="{Binding Brand.Name, ConverterParameter=white, Converter={StaticResource LogoToUriConverter}}"/>
    <Image x:Name="image_colored" Stretch="UniformToFill" Visibility="Collapsed" Source="{Binding Brand.Name, ConverterParameter=colored, Converter={StaticResource LogoToUriConverter}}"/>
    <StackPanel VerticalAlignment="Bottom">
        <TextBlock Text="{Binding Name}" Foreground="White" Style="{StaticResource TitleTextStyle}" Height="30" Margin="15,0,15,0"/>
        <TextBlock Text="{Binding Name}" Foreground="White" Style="{StaticResource CaptionTextStyle}" TextWrapping="NoWrap" Margin="15,0,15,10"/>
    </StackPanel>
    <VisualStateManager.CustomVisualStateManager>
        <vsm:ExtendedVisualStateManager/>
    </VisualStateManager.CustomVisualStateManager>
    <VisualStateManager.VisualStateGroups>
        <VisualStateGroup x:Name="SelectionStates">
            <VisualState x:Name="Selected2">
                <Storyboard>
                    <ObjectAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="image" Storyboard.TargetProperty="Visibility">
                        <DiscreteObjectKeyFrame KeyTime="00:00:00.0000000">
                            <DiscreteObjectKeyFrame.Value>
                                Collapsed
                            </DiscreteObjectKeyFrame.Value>
                        </DiscreteObjectKeyFrame>
                    </ObjectAnimationUsingKeyFrames>
                    <ObjectAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="image_colored" Storyboard.TargetProperty="Visibility">
                        <DiscreteObjectKeyFrame KeyTime="00:00:00.0000000">
                            <DiscreteObjectKeyFrame.Value>
                                Visible
                            </DiscreteObjectKeyFrame.Value>
                        </DiscreteObjectKeyFrame>
                    </ObjectAnimationUsingKeyFrames>
                </Storyboard>
            </VisualState>
        </VisualStateGroup>
    </VisualStateManager.VisualStateGroups>
</Grid>

Hope this can help anybody with the same issue.

If you have a better and easier way to achieve the same result in WinRT, please present your solution.

Thank you




回答2:


You can create a style for your ListViewItem, with a controltemplate for the triggers and a datatemplate for your data binding, like this:

   <Style x:Key="FocusedContainer" TargetType="{x:Type ListViewItem}">
        <EventSetter Event="GotKeyboardFocus" Handler="OnListBoxItemContainerFocused" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type ListViewItem}">
                    <Border x:Name="backgroundBorder">
                        <ContentPresenter Content="{TemplateBinding Content}">
                            <ContentPresenter.ContentTemplate>
                                <DataTemplate>
                                     <Grid HorizontalAlignment="Center" Width="220" Height="220">
                                <Image x:Name="image" Stretch="UniformToFill" Source="{Binding Brand.Image, ConverterParameter=transparent, Converter={StaticResource LogoToUriConverter}}"/>
                                <StackPanel VerticalAlignment="Bottom">
                                    <TextBlock Text="{Binding Name}" Foreground="{StaticResource ApplicationColor}" Style="{StaticResource TitleTextStyle}" Height="30" Margin="15,0,15,0"/>
                                    <TextBlock Text="{Binding Name}" Foreground="{StaticResource ApplicationColor}" Style="{StaticResource CaptionTextStyle}" TextWrapping="NoWrap" Margin="15,0,15,10"/>
                                </StackPanel>
                            </Grid>
                                </DataTemplate>
                            </ContentPresenter.ContentTemplate>
                        </ContentPresenter>
                    </Border>
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsSelected" Value="True">
                            <Setter TargetName="image" Property="Source" Value="{**Insert your alternate binding here**}"
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

Then configure your ListView like this:

<ListView ItemContainerStyle="{StaticResource FocusedContainer}"/>

You'll see that the style has an EventSetter: its purpose is to get the correct item selected even if you click inside some control (not directly on the background). You need to create the handler in code behind, just a couple of lines:

    private void OnListBoxItemContainerFocused(object sender, System.Windows.RoutedEventArgs e)
    { (sender as ListViewItem).IsSelected = true; }

Hope this is helpful, regards!



来源:https://stackoverflow.com/questions/14551766/xaml-listview-change-image-source-for-selected-item

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!