かずきのBlog@hatena

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

ListView(ListBoxも)で単一選択モードのときに項目を追加したときの挙動を変えたい

ListViewのSelectionModeをSingleにした状態で、先頭に要素を追加したりすると、勝手に選択項目にスクロールしてしまいます。

場合によっては嬉しいのかもしれないですが余計な動作と感じることもあるので、OFFにしたい…!と思って調べたら、そういうプロパティがみつかりませんでした。

実現方法

複数選択できるMultipleだと、選択項目があっても勝手にそこへスクロールしません。なので、SelectionChangedイベントで単一選択になるように制御してやります。なので、こんなビヘイビアを作っておいて、ぽとっとすれば完了ですね。

using Microsoft.Xaml.Interactivity;
using System;
using System.Diagnostics;
using System.Linq;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;

namespace App6
{
    [TypeConstraint(typeof(ListView))]
    public class SingleSelectBehavior : DependencyObject, IBehavior
    {
        private ListView AssociatedObject { get; set; }

        DependencyObject IBehavior.AssociatedObject
        {
            get { return this.AssociatedObject; }
        }

        public void Attach(DependencyObject associatedObject)
        {
            var lv = associatedObject as ListView;
            if (lv == null)
            {
                throw new InvalidOperationException();
            }

            this.AssociatedObject = lv;
            this.AssociatedObject.SelectionChanged += AssociatedObject_SelectionChanged;
        }

        private void AssociatedObject_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            // 何か選択されたら
            if (e.AddedItems.Any())
            {
                // とりあえず1つだけ選択状態にする
                this.AssociatedObject.SelectionChanged -= AssociatedObject_SelectionChanged;
                this.AssociatedObject.SelectedItems.Clear();
                this.AssociatedObject.SelectedItems.Add(e.AddedItems.First());
                this.AssociatedObject.SelectionChanged += AssociatedObject_SelectionChanged;
            }
        }

        public void Detach()
        {
            this.AssociatedObject.SelectionChanged -= AssociatedObject_SelectionChanged;
        }
    }
}