3
4

More than 3 years have passed since last update.

Prism.Wpf 7.2でプログレスバーのついたダイアログを作る

Posted at

はじめに

 Prismを使ってプログレスバーの付いたダイアログを作りました。
 進捗の値0~100をダイアログに送り、100のときにダイアログを閉じることができるという仕様にしました。

prism2.gif

環境

.Net Core 3.1
Prism.Wpf 7.2.0.1422

実装

View

xaml.png

ProgressDialog.xaml
<UserControl x:Class="Module1.Views.ProgressDialog"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:Module1.Views"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             Height="100"
             Width="200"
             mc:Ignorable="d" 
             xmlns:prism="http://prismlibrary.com/"
             prism:ViewModelLocator.AutoWireViewModel="True"
             xmlns:viewModels="clr-namespace:Module1.ViewModels"
             d:DataContext="{d:DesignInstance viewModels:ProgressDialogViewModel}">
    <prism:Dialog.WindowStyle>
        <Style TargetType="Window">
            <Setter Property="ResizeMode" Value="NoResize"/>
            <Setter Property="ShowInTaskbar" Value="False"/>
            <Setter Property="SizeToContent" Value="WidthAndHeight"/>
            <Setter Property="WindowStyle" Value="None"/>
            <Setter Property="BorderThickness" Value="1"/>
        </Style>
    </prism:Dialog.WindowStyle>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"></RowDefinition>
            <RowDefinition Height="Auto"></RowDefinition>
        </Grid.RowDefinitions>
        <WrapPanel Margin="10,15">
            <Label Width="30" HorizontalContentAlignment="Right" Content="{Binding Progress}"/>
            <ProgressBar Height="15" Width="130" Value="{Binding Progress}" />
        </WrapPanel>
        <Button Grid.Row="1" Height="20" Width="100" VerticalAlignment="Bottom" Margin="0,12" Content="閉じる" Command="{Binding CloseCommand}"/>
    </Grid>
</UserControl>

 ダイアログ用にプログレスバーと閉じるボタンが付いたViewを作成します。
 prism:Dialog.WindowStyleタグでダイアログとして呼び出された際のWindowStyleを制御しています。今回はできるだけダイアログを閉じられたくなかったのでWindowStyleNoneを指定しウィンドウの閉じるボタンを非表示にしています。

ViewModel

ProgressDialogViewModel
    public class ProgressDialogViewModel : BindableBase, IDialogAware
    {
        private int progress;

        public event Action<IDialogResult> RequestClose;

        public int Progress
        {
            get { return progress; }
            set { SetProperty(ref progress, value); }
        }

        public DelegateCommand CloseCommand { get; }

        public string Title => "Dialog1";

        public ProgressDialogViewModel(ProgressDialogModel model)
        {
            this.Progress = model.Progress;

            model.PropertyChanged += (_, e) =>
            {
                if (e.PropertyName == "Progress")
                {
                    this.Progress = model.Progress;
                }
            };

            this.CloseCommand =
                new DelegateCommand
                (
                    () => this.CloseDialog(),
                    () => this.Progress >= 100
                )
                .ObservesProperty(() => this.Progress);
        }

        public bool CanCloseDialog() => true;

        public void OnDialogClosed() => this.Progress = 0;

        public void OnDialogOpened(IDialogParameters parameters) { }

        private void CloseDialog()
            => RequestClose?.Invoke(new DialogResult(ButtonResult.OK));
    }

 ViewModelではViewのプログレスバーにバインドする項目としてProgressプロパティを定義しています。
 CloseCommadではダイアログを閉じるときの動作を担当しています。使用可否条件としてProgressの値が100以上であることを指定しています。
 ダイアログとして利用するためにIDialogAwareを実装しています。

Model

ProgressDialogModel
    public class ProgressDialogModel : BindableBase
    {
        private int progress;

        public int Progress
        {
            get { return progress; }
            set { SetProperty(ref progress, value); }
        }

        public ProgressDialogModel(IEventAggregator eventAggregator)
        {
            this.Progress = 0;

            eventAggregator
                .GetEvent<ProgressMessage>()
                .Subscribe(x => this.Progress = x);
        }
    }
ProgressMessage
    public class ProgressMessage : PubSubEvent<int>
    {
    }

 ModelではViewModelとバインドする項目としてProgressプロパティを定義しています。
 外部からの値受け取りはIEventAggregatorを介して行うものとしProgressMessageが発行されたときにProgressの値が変化するようにしています。

Module

Module1Module
    public class Module1Module : IModule
    {
        public void OnInitialized(IContainerProvider containerProvider)
        {
            _ = containerProvider.Resolve<ProgressDialogModel>();
        }

        public void RegisterTypes(IContainerRegistry containerRegistry)
        {
            containerRegistry.RegisterSingleton<ProgressDialogModel>();
            containerRegistry.RegisterDialog<ProgressDialog>();
        }
    }

 Moduleでは他のプロジェクトでダイアログを利用できるようDIコンテナにViewとModelを登録しています。ModelはシングルトンとしてDIコンテナに登録しました。

ダイアログ呼び出し部分

        public DelegateCommand ShowDialogCommand { get; }

        public MainWindowViewModel(IDialogService dialogService, IEventAggregator eventAggregator)
        {
            this.ShowDialogCommand =
                new DelegateCommand(() =>
                {
                    _ = Task.Run(async () =>
                    {
                        eventAggregator.GetEvent<ProgressMessage>().Publish(0);
                        await Task.Delay(1000);
                        eventAggregator.GetEvent<ProgressMessage>().Publish(33);
                        await Task.Delay(1000);
                        eventAggregator.GetEvent<ProgressMessage>().Publish(66);
                        await Task.Delay(1000);
                        eventAggregator.GetEvent<ProgressMessage>().Publish(100);
                    })
                    .ContinueWith(x => x.Exception /* エラー処理 */, TaskContinuationOptions.OnlyOnFaulted);

                    dialogService.ShowDialog(nameof(ProgressDialog), new DialogParameters(), null);
                });
        }

 ダイアログのプロジェクトとは別の画面を作り、そのViewModelにShowDialogCommandというダイアログの動作確認をするためのコマンドを用意しました。
 ShowDialogCommandでは、非同期処理呼び出しとダイアログ呼び出しの2つを実行しています。
 非同期処理では処理中にIEventAggregatorを介してProgressMessageを発行しModelに進捗を表す数値を送っています。ここでは1秒間隔でModelの進捗の値を変更しています。ContinueWithの第一引数部分には非同期処理でエラーになった際の処理を書く予定です。
 ダイアログ呼び出しはIDialogServiceShowDialogを使って定義したダイアログを呼び出しています。

おわりに

 プログレスバーの付いたダイアログを作ることができました。他の画面から呼び出せることとプログレスバーの値を処理の進み具合によって制御できることを確認できました。

・ソースコード
https://github.com/ttlatex/PrismProgressDialog

3
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
4