0

I have a ListView with SelectionMode = None. When I change it to Multiple I want the items in the list to change their style and add a border around each of them so the user knows he can select them (see images). I'm using MVVMLight so please help in a VM way if you can. Anyway, any solution will be appreciatted. enter image description here

enter image description here

Cabuxa.Mapache
  • 762
  • 1
  • 7
  • 19

1 Answers1

0

Well, the problem here was related to access the Visual State of each element in my ListView changing it so the user could see how to interact with those ListView items. How to do it:

First, create a copy of the ListViewItem template and add your custon VisualStates:

<Style TargetType="ListViewItem" x:Key="ListViewItemExpanded">
<Setter Property="FontFamily" Value="{ThemeResource ContentControlThemeFontFamily}" />
<Setter Property="FontSize" Value="{ThemeResource ControlContentThemeFontSize}" />
<Setter Property="Background" Value="Transparent"/>
<Setter Property="TabNavigation" Value="Local"/>
<Setter Property="IsHoldingEnabled" Value="True"/>
<Setter Property="Margin" Value="0,0,18,2"/>
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
<Setter Property="VerticalContentAlignment" Value="Top"/>
<Setter Property="Template">
    <Setter.Value>
        <ControlTemplate TargetType="ListViewItem">
            <Border x:Name="OuterContainer">
                <VisualStateManager.VisualStateGroups>
                    <!-- Custom Visual States -->
                    <VisualStateGroup x:Name="CustomStates">
                        <VisualState x:Name="Edicion">
                            <Storyboard>
                                <DoubleAnimation Storyboard.TargetName="SelectedBorder"
                                    Storyboard.TargetProperty="Opacity" Duration="0" To="1" />
                            </Storyboard>
                        </VisualState>
                        <VisualState x:Name="SoloLectura">
                            <Storyboard>
                                <FadeOutThemeAnimation TargetName="SelectedBorder" />
                            </Storyboard>
                        </VisualState>
                    </VisualStateGroup>
                    ...

Second, create a UserControl for the content inside de <DataTemplate> in your ListView:

<UserControl
    x:Class="YourNamespace.YourUserControl"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    d:DesignHeight="300"
    d:DesignWidth="400">

    <Grid x:Name="GridUC">
        <TextBlock Text="{Binding Path=BindToVMProp}" Grid.Row="0" VerticalAlignment="Center" HorizontalAlignment="Center" />
    </Grid>
</UserControl>

Third, add a custom property in your UserControl ("CustomState") where you can specify the name of the VisualState you want to set and implement the logic to apply it in the UserControl's code behind.

public sealed partial class MyUserControl : UserControl
{
    public static DependencyProperty CustomStateProperty = DependencyProperty.Register(
        "CustomState",
        typeof(string),
        typeof(MyUserControl),
        new PropertyMetadata("SoloLectura", CustomStatePropertyChangedCallback));

    public string Estado
    {
        get
        {
            return (string)this.GetValue(CustomStateProperty);
        }
        set
        {
            this.SetValue(CustomStateProperty, value);
        }
    }

    static void CustomStatePropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var item = GetPadre(d as MyUserControl);
        VisualStateManager.GoToState(item, e.NewValue.ToString(), true);
    }

    /// <summary>
    /// Gets the listviewitem parent.
    /// </summary>
    private static ListViewItem GetPadre(FrameworkElement elemento)
    {
        while (elemento != null)
        {
            elemento = VisualTreeHelper.GetParent(elemento) as FrameworkElement;
            if (elemento is ListViewItem)
                break;
        }
        return elemento as ListViewItem;
    }

    public FavoritoControl()
    {
        this.InitializeComponent();
    }
}

Fourth, in the view where your UserControl is, bind the custom property in your VM and set it to your UserControl when neccesary:

xmlns:local="using:YourNamespace"
<ListView x:Name="MyList" ItemsSource="{Binding CollectionProp}">
    <ListView.ItemTemplate>
        <DataTemplate>
            <local:MyUserControl CustomState="{Binding Path=DataContext.CustomVisualSateProp, ElementName=MyList}" />
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

Where I found my answers:

listview visual state manager in item template (WinRT, Metro, XAML)

Binding [VisualStateManager] view state to a MVVM viewmodel?

Hope this helps anyone in the future :)

Community
  • 1
  • 1
Cabuxa.Mapache
  • 762
  • 1
  • 7
  • 19