質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.31%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

MVVM

MVVM(Model View ViewModel)は構築上のデザインパターンで、表現ロジック(ViewModel)によってデータ(Model)からページ(View)を分離させます。

WPF

Windows Presentation Foundation (WPF) は、魅力的な外観のユーザー エクスペリエンスを持つ Windows クライアント アプリケーションを作成するための次世代プレゼンテーション システムです

Q&A

解決済

3回答

4013閲覧

【C#】【WPF】ItemsControlが空かどうかでボタンの活性非活性を制御したい

galmacher

総合スコア37

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

MVVM

MVVM(Model View ViewModel)は構築上のデザインパターンで、表現ロジック(ViewModel)によってデータ(Model)からページ(View)を分離させます。

WPF

Windows Presentation Foundation (WPF) は、魅力的な外観のユーザー エクスペリエンスを持つ Windows クライアント アプリケーションを作成するための次世代プレゼンテーション システムです

0グッド

1クリップ

投稿2018/12/15 08:24

【やろうとしていること】
画面のItemsControlのItemSourceにObservableCollection 〈Person〉を指定しています。
画面に追加ボタンとクリアボタンの2つのボタンを配置しています。
初期表示ではObservableCollectionは空で、
追加を押すとPersonクラスの名前とIDを画面表示し、クリアボタンを押すと全消しします。
中身が空の状態ではクリアボタンを非活性としたいです。

【困っていること】
クリアボタンのIsEnabledプロパティをバインドしています。
今のやり方は、追加ボタンクリック時のCommandで上記IsEnAbledをtrueにする、クリックボタンクリック時のCommandでfalseに倒すというやり方を取っています。
ObservableCollectionの中身が空かどうかで判断出来ればスマートだと思うのですが、良いやり方はありますでしょうか。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

スタイルを使った方法です。

XML

1<Button Content="クリア"> 2 <Button.Style> 3 <Style TargetType="Button"> 4 <Setter Property="IsEnabled" Value="True"/> 5 <Style.Triggers> 6 <DataTrigger Binding="{Binding Persons}" Value="{x:Null}"> 7 <Setter Property="IsEnabled" Value="False"/> 8 </DataTrigger> 9 <DataTrigger Binding="{Binding Persons.Count}" Value="0"> 10 <Setter Property="IsEnabled" Value="False"/> 11 </DataTrigger> 12 </Style.Triggers> 13 </Style> 14 </Button.Style> 15</Button>

投稿2018/12/15 08:48

編集2018/12/17 01:53
hihijiji

総合スコア4152

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Zuishin

2018/12/15 15:29

コレクションの中身が空かどうかではなく、プロパティが null かどうかでチェックされていますが、そうすると要素数が 0 の時にクリアボタンが有効になってしまいます。 削除時に要素数をチェックして 0 なら null にする処理が必要になりますし、追加時に null チェックが必要になるので、処理が少し煩雑になるのではないでしょうか。 またコマンドの有効無効とボタンの有効無効にずれが生じるのも気になります。
galmacher

2018/12/16 02:31

hihijijiさん ご回答ありがとうございます。 DataTriggerを使ったことがあまりなかったので、これを機会に色々と調べてみます。
hihijiji

2018/12/17 01:54

0を考慮してなかったので修正しました。 Countにも変更通知が付いているのでそのままバインドできます。
guest

0

ベストアンサー

CanExecute を実装したコマンドをバインドしてください。

#追記

次のコードでは、起動時に People に要素が一つ入っているのでクリアボタンが有効です。それを押すと People がクリアされてボタンが無効になります。

MainWindow.xaml

XML

1<Window x:Class="WpfApp1.MainWindow" 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 5 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 6 xmlns:local="clr-namespace:WpfApp1" 7 mc:Ignorable="d" 8 Title="MainWindow" Height="450" Width="800"> 9 <Window.DataContext> 10 <local:ViewModel/> 11 </Window.DataContext> 12 <Grid> 13 <Button Command="{Binding ClearCommand}">Clear</Button> 14 </Grid> 15</Window>

ViewModel.cs

C#

1using Reactive.Bindings; 2using System.Collections.ObjectModel; 3using System.Collections.Specialized; 4using System.ComponentModel; 5using System.Linq; 6using System.Reactive.Linq; 7using System.Runtime.CompilerServices; 8 9namespace WpfApp1 10{ 11 public class ViewModel : INotifyPropertyChanged 12 { 13 public event PropertyChangedEventHandler PropertyChanged; 14 protected virtual void OnPropertyChanged([CallerMemberName]string propertyName = null) 15 { 16 PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); 17 } 18 19 public ObservableCollection<string> People { get; } = new ObservableCollection<string>(); 20 21 public ReactiveCommand ClearCommand { get; private set; } 22 23 public ViewModel() 24 { 25 ClearCommand = Observable 26 .FromEventPattern<NotifyCollectionChangedEventArgs>(People, nameof(People.CollectionChanged)) 27 .Select(_ => People.Count > 0) 28 .ToReactiveCommand(false); 29 ClearCommand.Subscribe(People.Clear); 30 People.Add("who"); 31 } 32 } 33}

投稿2018/12/15 08:43

編集2018/12/15 15:02
Zuishin

総合スコア28673

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Zuishin

2018/12/15 08:45

ReactiveCommand だと簡単です。RoutedCommand でもできますが、CanExecuteChanged を発行するのが煩わしいです。
galmacher

2018/12/15 14:12

ご回答ありがとうございます。 ReactiveCommandを使ってやってみたいと思います。 やり方としては以下のようになるのかなと思っています。 クリアボタンのCommand = ReactiveProperty<bool>.ToReactiveCommand(); ・上記のイメージであっておりますか。 ・その場合、 ReactiveProperty<bool>のtrue/falseをObservableCollectionのCountプロパティを見て切り替えることが必要だと思いますが、どのように実現すればよいでしょうか。
Zuishin

2018/12/15 14:44

サンプルを追記しました。
Zuishin

2018/12/15 15:09

ReactiveProperty<bool>のtrue/false は必要ありません。ボタンはコマンドの CanExecute によって自動的に有効・無効になります。 他で必要ならば これと同様に.ToReactiveCommand(false) を .ToReactiveProperty(false) にして ReactiveProperty<bool> を作ってください。
galmacher

2018/12/16 02:30

毎度サンプルありがとうございます。 Countというint型の変更通知をどうやって受ければいいのだろうと思っていたのですが、 Collectionの変更通知が発生した際にCountの中身を見に行くという理解です。 勉強になります。ありがとうございました。
guest

0

ItemsControlが空かどうかでボタンの活性非活性を制御したい

Button.IsEnabledItemsControl.HasItemsをバインドするのが簡単です。
ItemsControl.HasItems Property (System.Windows.Controls) | Microsoft Learn

xml

1<Window 2 x:Class="Q164167.MainWindow" 3 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 4 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 5 Width="800" 6 Height="450" 7 ThemeMode="System"> 8 <DockPanel> 9 <UniformGrid DockPanel.Dock="Bottom" Rows="1"> 10 <Button HorizontalAlignment="Stretch" Click="AddButton_Click" Content="Add" /> 11 <Button 12 HorizontalAlignment="Stretch" 13 Click="ClearButton_Click" 14 Content="Clear" 15 IsEnabled="{Binding HasItems, ElementName=itemsControl}" /> 16 </UniformGrid> 17 <ItemsControl x:Name="itemsControl" ItemsSource="{Binding People}" /> 18 </DockPanel> 19</Window>

cs

1using System.Collections.ObjectModel; 2using System.IO; 3using System.Windows; 4 5namespace Q164167; 6 7public partial class MainWindow : Window 8{ 9 public ObservableCollection<Person> People { get; } = []; 10 11 public MainWindow() 12 { 13 InitializeComponent(); 14 DataContext = this; 15 } 16 17 private void AddButton_Click(object sender, RoutedEventArgs e) 18 => People.Add(new($"{People.Count + 1}", Path.GetRandomFileName()[..8])); 19 private void ClearButton_Click(object sender, RoutedEventArgs e) => People.Clear(); 20} 21 22public record Person(string Id, string Name);

アプリ動画


Countというint型の変更通知をどうやって受ければいいのだろうと思っていた

ObservableCollectionINotifyPropertyChangedも実装しますが、明示的な実装なのでキャストする必要があります。

cs

1((INotifyPropertyChanged)People).PropertyChanged += (s, e) => { };

ObservableCollection<T>.INotifyPropertyChanged.PropertyChanged イベント (System.Collections.ObjectModel) | Microsoft Learn

投稿2024/11/24 15:05

TN8001

総合スコア10013

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.31%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問