Universal Windows の GridView で特定のアイテムを選択不可にする方法
WP8 の LongListMultiSelector で特定のアイテムを選択不可にする方法 の続き(?)です。
Universal Windows アプリケーションでは、Phone アプリも Windows Runtime API (いわゆるMetro、Modern)アプリ用の API を使って実装します。そのため、今まで Phone アプリを開発していて Universal に移植する場合には多くのコントロールを置き換える必要があり、LongListSelector や Toolkit の LongListMultiSelector を使用していた場合もこれに当てはまります。
前回と同じくやりたいことは、
「ViewModel の特定にプロパティの変化に応じて、既に表示済みであっても動的に GridViewItem の選択可不可が変わること」
です。
まず、試して効果がなかった方法を挙げておきます。
※ WP8 のときに LongListMultiSelector の中にまで手を加えたのはやり過ぎだったのかもしれません。今更ですが。
1番目の方法ですが、GridViewItem の IsEnabled は ViewModel の IsEnabled をバインドしていないので効果がありません。
2番目の方法ですが、XAMLで下記のような実装をしました。
ここで、Value に対して False を静的に指定すると常時選択不可状態になることがわかりました。
3番目の方法ですが、ViewModel のプロパティに応じて Style を出し分ける StyleSelector を用意し、それを GridView にセットするというものです。
効果がなかった方法の3番目に近いです。StyleSelector を使用します。
先ほど書いたとおり、StyleSelector の SelectStyleCore は GridViewItem が表示される前に一度だけ呼ばれます。適用される ViewModel も引数として渡ってくるので、この時点でコードビハインドで IsEnabled にプロパティをバインドしてしまいます。
左が、ListViewSelectionMode.None で、全ての IsEnabled が true のとき。
真ん中が、ListViewSelectionMode.Multiple で、鍵マーク付きの IsEnabled が false のとき。
右が、ListViewSelectionMode.Multiple で、動画マーク付きの IsEnabled が false のとき。
見た目はまだこれから改善するとして、期待通りの動作になってくれました。
おわり。
Universal Windows アプリへの移植
Universal Windows アプリケーションでは、Phone アプリも Windows Runtime API (いわゆるMetro、Modern)アプリ用の API を使って実装します。そのため、今まで Phone アプリを開発していて Universal に移植する場合には多くのコントロールを置き換える必要があり、LongListSelector や Toolkit の LongListMultiSelector を使用していた場合もこれに当てはまります。
前回と同じくやりたいことは、
「ViewModel の特定にプロパティの変化に応じて、既に表示済みであっても動的に GridViewItem の選択可不可が変わること」
です。
試したこと
まず、試して効果がなかった方法を挙げておきます。
- ViewModel に IsEnabled プロパティを追加する
- ItemContainerStyle で、GridViewItem の IsEnabled プロパティに IsSelectable をバインドする
- ItemContainerStyleSelector で、IsSelectable に応じて別のStyleを適用する
※ WP8 のときに LongListMultiSelector の中にまで手を加えたのはやり過ぎだったのかもしれません。今更ですが。
1番目の方法ですが、GridViewItem の IsEnabled は ViewModel の IsEnabled をバインドしていないので効果がありません。
2番目の方法ですが、XAMLで下記のような実装をしました。
<GridView.ItemContainerStyle>
<Style TargetType="GridViewItem">
<Setter Property="IsEnabled"
Value="{Binding Path=DataContext.IsSelectable,
RelativeSource={RelativeSource Mode=Self}}" />
</Style>
</GridView.ItemContainerStyle>
Setter で IsEnabled の Value に対して ViewModel のプロパティをバインドしているのですが、効果が無いようです。上記の例だと Path が間違っているとかあるかもしれませんが、思いつく限りのパターンを試してみても期待する動作はしてくれませんでした。ここで、Value に対して False を静的に指定すると常時選択不可状態になることがわかりました。
3番目の方法ですが、ViewModel のプロパティに応じて Style を出し分ける StyleSelector を用意し、それを GridView にセットするというものです。
public class CustomStyleSelector : StyleSelector
{
public Style EnabledStyle { get; set;}
public Style DisabledStyle { get; set;}
protected override Style SelectStyleCore(object item, DependencyObject container)
{
var vm = item as MyViewModel;
if(vm.IsSelectable) {
return EnabledStyle;
} else {
return DisabledStyle;
}
}
}
出し分け自体は機能していましたが、SelectStyleCore は表示されるときに一回しか呼ばれないので、期待の動作にはなりませんでした。解決策
効果がなかった方法の3番目に近いです。StyleSelector を使用します。
先ほど書いたとおり、StyleSelector の SelectStyleCore は GridViewItem が表示される前に一度だけ呼ばれます。適用される ViewModel も引数として渡ってくるので、この時点でコードビハインドで IsEnabled にプロパティをバインドしてしまいます。
public class GridViewItemSelectivityBinder : StyleSelector
{
protected override Style SelectStyleCore(object item, DependencyObject container)
{
var selectorItem = container as GridViewItem;
selectorItem.SetBinding(GridViewItem.IsEnabledProperty, new Binding
{
Source = item as MyViewModel,
Path = new PropertyPath("IsSelectable"),
Mode = BindingMode.OneWay
});
return base.SelectStyleCore(item, container);
}
}
あとはこの GridViewItemSelectivityBinder を GridView の ItemContainerStyleSelector としてセットしておけばOKです。左が、ListViewSelectionMode.None で、全ての IsEnabled が true のとき。
真ん中が、ListViewSelectionMode.Multiple で、鍵マーク付きの IsEnabled が false のとき。
右が、ListViewSelectionMode.Multiple で、動画マーク付きの IsEnabled が false のとき。
見た目はまだこれから改善するとして、期待通りの動作になってくれました。
おわり。
コメント
コメントを投稿