読者です 読者をやめる 読者になる 読者になる

かずきのBlog@hatena

日本マイクロソフトに勤めています。XAML + C#の組み合わせをメインに、たまにASP.NETやJavaなどの.NET系以外のことも書いています。掲載内容は個人の見解であり、所属する企業を代表するものではありません。

UWPのListBox/ListViewで、選択状態によって見た目を変える

UWP

選択されてるときには、何かを出したいとか出したくないとか、そういう要件です。

まずは、バインドされてる要素が自分は今選択されているのかどうかを知っておくと話が早くなります。それについては、以下の記事を参照。

blog.okazuki.jp

あとは、このIsSelectedプロパティを見て表示・非表示あたりを切り替えてやればOKだと思われます。とりあえずやってみましょう。

データの入れ物を作ります。

using Prism.Mvvm;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace App27.ViewModels
{
    public class Person : BindableBase
    {
        private bool isSelected;

        public bool IsSelected
        {
            get { return this.isSelected; }
            set { this.SetProperty(ref this.isSelected, value); }
        }

        private string name;

        public string Name
        {
            get { return this.name; }
            set { this.SetProperty(ref this.name, value); }
        }

    }
}

ここのIsSelectedの選択状態が入るようにします。ListBoxを拡張したコントロールを作って選択状態と、上記クラスのIsSelectedをバインドしておきます。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Media;

namespace App27.Controls
{
    public class ListBoxEx : ListBox
    {
        protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
        {
            base.PrepareContainerForItemOverride(element, item);
            var b = new Binding();
            b.Path = new PropertyPath("IsSelected");
            b.Source = item;
            b.Mode = BindingMode.TwoWay;
            ((ListBoxItem)element).SetBinding(ListBoxItem.IsSelectedProperty, b);
        }

    }
}

次に、画面を組み立てます。今回は選択状態のときはボタンを消すという処理をしています。

<Page x:Class="App27.Views.MainPage"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      xmlns:local="using:App27.Views"
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
      xmlns:Mvvm="using:Prism.Windows.Mvvm"
      xmlns:Controls="using:App27.Controls"
      xmlns:ViewModels="using:App27.ViewModels"
      Mvvm:ViewModelLocator.AutoWireViewModel="True"
      mc:Ignorable="d">


    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <Controls:ListBoxEx ItemsSource="{x:Bind ViewModel.Users}">
            <ListBox.ItemTemplate>
                <DataTemplate x:DataType="ViewModels:Person">
                    <StackPanel>
                        <TextBlock Text="{x:Bind Name}" />
                        <Button x:Name="ButtonDelete"
                                Content="削除" 
                                Visibility="{x:Bind IsSelected, Mode=OneWay, Converter={StaticResource InverseBooleanToVisibilityConverter}}"/>
                    </StackPanel>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </Controls:ListBoxEx>
    </Grid>
</Page>

InverseBooleanToVisibilityConverterは、まぁ誰もが実装するような以下のようなコンバータです。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Data;

namespace App27.Converters
{
    public class BooleanToVisibilityConverter : IValueConverter
    {
        public bool IsInverse { get; set; }

        public object Convert(object value, Type targetType, object parameter, string language)
        {
            var b = (bool)value;
            if (this.IsInverse)
            {
                b = !b;
            }
            return b ? Visibility.Visible : Visibility.Collapsed;
        }

        public object ConvertBack(object value, Type targetType, object parameter, string language)
        {
            var v = (Visibility)value;
            if (this.IsInverse)
            {
                return v == Visibility.Collapsed;
            }
            else
            {
                return v == Visibility.Visible;
            }
        }
    }
}

App.xamlで以下のような雰囲気で定義しています。

<Prism:PrismUnityApplication x:Class="App27.App"
                             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                             xmlns:Prism="using:Prism.Unity.Windows"
                             xmlns:Converters="using:App27.Converters"
                             xmlns:local="using:App27"
                             RequestedTheme="Light">
    <Prism:PrismUnityApplication.Resources>
        <Converters:BooleanToVisibilityConverter x:Key="InverseBooleanToVisibilityConverter"
                                                 IsInverse="True" />
    </Prism:PrismUnityApplication.Resources>
</Prism:PrismUnityApplication>

因みにPrism.Windows使ってます!それについては下記を参照してください。

github.com