WPF学習中「フラグに連動してButtonの有効・無効を切り替える」

コンピュータ

再生と停止及び削除ボタンを用意し、各ボタンの有効・無効を切り替えてみたいと思います。

プロジェクトの作成

mkdir プロジェクト名
cd プロジェクト名
dotnet new wpf
dotnet add package Microsoft.Xaml.Behaviors.Wpf
dotnet add package ReactiveProperty.WPF
code .

ソースコード

ファイル名:MainWindow.xaml

<Window
  x:Class="Sample55DisableButton.MainWindow"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
  xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
  xmlns:local="clr-namespace:Sample55DisableButton"
  mc:Ignorable="d"
  Title="{Binding Title.Value}" Height="450" Width="800"
  xmlns:i="clr-namespace:Microsoft.Xaml.Behaviors;assembly=Microsoft.Xaml.Behaviors">
  <Window.DataContext>
    <local:MainWindowViewModel />
  </Window.DataContext>
  <i:Interaction.Behaviors>
    <local:ViewModelCleanupBehavior />
  </i:Interaction.Behaviors>
  <Grid>
    <WrapPanel
      ItemWidth="80"
      ItemHeight="48"
      Margin="5">
      <Button Margin="5" FontSize="24" Content="再生" Command="{Binding PlayCommand}"/>
      <Button Margin="5" FontSize="24" Content="停止" Command="{Binding StopCommand}" />
      <Button Margin="5" FontSize="24" Content="削除" Command="{Binding RemoveCommand}"/>
    </WrapPanel>
  </Grid>
</Window>

ファイル名:MainWindowViewModel.cs

using System.Diagnostics;
using System;
using System.ComponentModel;
using Reactive.Bindings;
using Reactive.Bindings.Extensions;
using System.Reactive.Disposables;

using System.Windows;
using System.Linq;
using System.Reactive.Linq;

namespace Sample55DisableButton
{
    public class MainWindowViewModel : INotifyPropertyChanged, IDisposable
    {
        public event PropertyChangedEventHandler PropertyChanged;
        private CompositeDisposable Disposable { get; } = new CompositeDisposable();
        public ReactiveProperty<string> Title { get; private set; }
        public ReactiveProperty<bool> Playing{get; private set;}
        public ReactiveCommand PlayCommand{get;}
        public ReactiveCommand StopCommand{get;}
        public ReactiveCommand RemoveCommand{get;}
        public MainWindowViewModel()
        {
            Title = new ReactiveProperty<string>("タイトル").AddTo(Disposable);

            Playing = new ReactiveProperty<bool>(false).AddTo(Disposable);

            PlayCommand = Playing.Select(e=>!e).ToReactiveCommand().AddTo(Disposable);
            PlayCommand.Subscribe(_=>{

                Playing.Value = true;

                MessageBox.Show("再生");
            });

            StopCommand = Playing.ToReactiveCommand().AddTo(Disposable);
            StopCommand.Subscribe(_=>{

                Playing.Value = false;

                MessageBox.Show("停止");
            });

            RemoveCommand = Playing.Select(e=>!e).ToReactiveCommand().AddTo(Disposable);
            RemoveCommand.Subscribe(_=>{

                MessageBox.Show("削除");
            });
        }
        public void Dispose()
        {
            Debug.WriteLine("Dispose()");
            Disposable.Dispose();
        }
    }
}

ファイル名:ViewModelCleanupBehavior.cs

using System.Xml;
using System.Xml.Schema;

using Microsoft.Xaml.Behaviors;
using System;
using System.Windows;
using System.ComponentModel;

namespace Sample55DisableButton
{
    public class ViewModelCleanupBehavior : Behavior<Window>
    {
        protected override void OnAttached()
        {
            base.OnAttached();
            this.AssociatedObject.Closed += this.WindowClosed;
        }

        private void WindowClosed(object sender, EventArgs e)
        {
            (this.AssociatedObject.DataContext as IDisposable)?.Dispose();
        }

        protected override void OnDetaching()
        {
            base.OnDetaching();
            this.AssociatedObject.Closed -= this.WindowClosed;
        }
    }
}

初期は停止状態を想定し再生ボタンを有効化。
再生ボタンを押すと、再生ボタンが無効化し停止ボタンが有効化されます。
削除ボタンは停止中のみ操作可能とし再生ボタンの有効・無効と連動するようにしています。

ReactiveProperty<bool>型のPlayingがButtonの有効・無効のフラグになります。
再生ボタンではReactive.Linqの.Select()を使いフラグを反転させています。
そうなるとReactive.Linqで表現できる条件であれば、様々なオブジェクトをフラグに使うことが出来そうです。

コメント