0
votes

I'm writing a uwp app. The main page contains a listbox. Each list item displays a line of text and a button. The button's visibility is 'collapsed' and I want to change its visibility to 'visible' when the item is selected.

As there are no style triggers in uwp, so far I've tried using the VisualStateManager in within a DataTemplate in the ListBox's ItemTemplate definition. That didn't work.

I've tried using the VisualStateManager with a definition of the ListBox's ItemContainerStyle. That didn't work either.

It seems to me quite a simple thing to want do yet I can't find any way of doing it. Has anyone got any ideas?

3

3 Answers

0
votes

If you're using the MVVM pattern, you can add an additional IsSelected property to your items that you're binding to the ListBox:

public bool IsSelected
{
    get { return _isSelected; }
    set
    {
        _isSelected = value;
        RaisePropertyChanged();
    }
}

On the page view model add a SelectedItem property which will set IsSelected to all the items correctly:

public Item SelectedItem
{
    get { return _selectedItem; }
    set
    {
        if (_selectedItem != value)
        {
            if (_selectedItem != null)
            {
                _selectedItem.IsSelected = false;
            }
            if (value != null)
            {
                value.IsSelected = true;
            }
            _selectedItem = value;
            RaisePropertyChanged();
        }
    }
}

Now you need to bind these two properties:

<ListBox ItemsSource="{Binding Items}" SelectedItem="{Binding SelectedItem, Mode=TwoWay}">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <StackPanel Orientation="Horizontal">
                <TextBlock Text="{Binding Name}" />
                <Button Content="Click Me" Visibility="{Binding IsSelected, Converter={StaticResource VisibilityConverter}}" />
            </StackPanel>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

You also need a converter for converting the bool value to Visibility:

public class VisibilityConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, string language)
    {
        if (value is bool)
        {
            return (bool) value ? Visibility.Visible : Visibility.Collapsed;
        }
        else
        {
            return Visibility.Collapsed;
        }
    }

    public object ConvertBack(object value, Type targetType, object parameter, string language)
    {
        throw new System.NotImplementedException();
    }
}

Declare it as a static resource on the page:

<Page.Resources>
    <local:VisibilityConverter x:Key="VisibilityConverter" />
</Page.Resources>

Without the MVVM pattern you're best off using the Cimbalino multibinding behavior. First reference the Cimbalino Toolkit. Then you can configure the multibinding in XAML:

<ListBox ItemsSource="{Binding Items}" x:Name="MyListBox">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <StackPanel Orientation="Horizontal">
                <TextBlock Text="{Binding Name}" />
                <Button Content="Click Me">
                    <interactivity:Interaction.Behaviors>
                        <behaviors:MultiBindingBehavior PropertyName="Visibility" Converter="{StaticResource VisibilityMultiConverter}">
                            <behaviors:MultiBindingItem Value="{Binding}"/>
                            <behaviors:MultiBindingItem Value="{Binding SelectedItem, ElementName=MyListBox}"/>
                        </behaviors:MultiBindingBehavior>
                    </interactivity:Interaction.Behaviors>
                </Button>
            </StackPanel>
        </DataTemplate>
    </ListBox.ItemTemplate>

Again you need a converter that checks if the item is currently selected:

public class VisibilityMultiConverter : MultiValueConverterBase
{
    public override object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        return values[0] != null && values[0] == values[1] ? Visibility.Visible : Visibility.Collapsed;
    }

    public override object[] ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new System.NotImplementedException();
    }
}

And add the converter as a page resource:

<Page.Resources>
    <local:VisibilityMultiConverter x:Key="VisibilityMultiConverter" />
</Page.Resources>
0
votes

you can use DataTriggerBehaviors and ChangePropertyAction to change the visibility of your button if you are using MVVM and Binding approach

You need to install a Nuget package Microsoft.xaml.behaviors.uwp.managed

https://www.nuget.org/packages/Microsoft.Xaml.Behaviors.Uwp.Managed/

or the most easy way is opening your page or UserControl with Blend and find the behavior and blend will install for your the necessary packages to use it.

https://blogs.msdn.microsoft.com/wsdevsol/2014/12/10/using-a-datatriggerbehavior-to-change-an-itemtemplate-in-a-windows-store-app/

Update:

You can't use VisualStateManager inside of ItemDataTemplate is not supported but there to do some tricks to use it

AdaptiveTrigger and DataTemplate

0
votes

this seems a old post but still answering for newcomers :)

Its quite easy you just have to use a SelectionChanged property in your ListBox in your .xaml page

For example:

ButtonVisibility.xaml

<ListBox
    x:Name="ListBox"
    HorizontalAlignment="Stretch"
    VerticalAlignment="Stretch"
    SelectionMode="Single"
    SelectionChanged="ListBox_SelectionChanged">
</ListBox>

Now Call the SelectionChanged event in your code behind

ButtonVisibility.xaml.cs

private void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    YourButton.Visibility = Visibility.Visible;
}