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

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

ただいまの
回答率

87.96%

WPF ダイアログボックスのキャンセル方法

解決済

回答 1

投稿

  • 評価
  • クリップ 0
  • VIEW 562

score 5

現在、WPFにて、ダイアログボックスを処理する簡単なプログラムを書いております。
下記サイトを参考にしております。

【C#/WPF】EventTriggerを使って、Buttonでなくてもクリック時のCommandをかけるようにする
https://qiita.com/tera1707/items/7ecde6e97a19437cbf72

現在、下記のところまで作成しました。
①メインウィンドウボタンをクリックすると、サブウィンドウがダイアログボックスで立ち上がる
②ダイアログボックスの操作でDialogResultを取得する
③DialogResultの結果をMessageBoxで表示

実現したいことは下記のとおりです。
・サブウィンドウでOKボタンを押した際、TextBox.Text=""ならば、別ダイアログボックスを出力し、入力を促す。
さらに、ボタン操作をキャンセルしたい(サブウィンドウへ再度戻る)

どのように実現すればよいかわからず困っております。
お手数をおかけしますが、ご教授いただけませんでしょうか。

現状のソースコードを下記にアップロードいたしました。
https://15.gigafile.nu/0116-dece8b0fe607e1eb5942bd27c85a0cb0c
DL Key 1192

よろしくお願いいたします。 

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

0

MVVMにこだわらないのであれば、

<Window
  x:Class="WpfApp1.SubWindow"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:local="clr-namespace:WpfApp1"
  Title="SubWindow"
  Width="800"
  Height="450">
  <Window.DataContext>
    <local:SubViewModel />
  </Window.DataContext>
  <Grid>
    <Grid.RowDefinitions>
      <RowDefinition />
      <RowDefinition />
    </Grid.RowDefinitions>
    <TextBox Text="{Binding Text}" />
    <Grid Grid.Row="1">
      <Grid.ColumnDefinitions>
        <ColumnDefinition />
        <ColumnDefinition />
      </Grid.ColumnDefinitions>
      <Button Content="Cancel" IsCancel="True" />
      <Button
        Grid.Column="1"
        Command="{Binding DoSomethingCommand}"
        CommandParameter="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}}"
        Content="OK"
        IsDefault="True" />
    </Grid>
  </Grid>
</Window>
using System.Windows;
using Prism.Commands;

namespace WpfApp1
{
    public class SubViewModel
    {
        public string Text { get; set; }
        public DelegateCommand<Window> DoSomethingCommand { get; }

        public SubViewModel()
        {
            DoSomethingCommand = new DelegateCommand<Window>((w) =>
            {
                System.Diagnostics.Debug.WriteLine("DoSomethigCommand");

                if(string.IsNullOrEmpty(Text))
                {
                    MessageBox.Show("何か入力してください。");
                }
                else
                {
                    w.DialogResult = true;
                }
            });
        }
    }
}


こんな感じでどうでしょうか。


実際には入力値はもっとあってそれぞれ検証したいのであればINotifyDataErrorInfo等を実装し、エラーがあればボタンを押せなくするのがきれいかもしれません。

<Window
  x:Class="WpfApp1.SubWindow"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
  xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
  xmlns:local="clr-namespace:WpfApp1"
  Name="SubWnd"
  Title="SubWindow"
  Width="800"
  Height="450">
  <Window.Resources>
    <ControlTemplate x:Key="ValidationTemplate">
      <StackPanel>
        <ItemsControl HorizontalAlignment="Right" ItemsSource="{Binding AdornedElement.(Validation.Errors), ElementName=validationTarget}">
          <ItemsControl.ItemTemplate>
            <DataTemplate>
              <TextBlock Foreground="Red" Text="{Binding ErrorContent}" />
            </DataTemplate>
          </ItemsControl.ItemTemplate>
        </ItemsControl>
        <AdornedElementPlaceholder x:Name="validationTarget" />
      </StackPanel>
    </ControlTemplate>
  </Window.Resources>
  <Window.DataContext>
    <local:SubViewModel />
  </Window.DataContext>
  <DockPanel>
    <StackPanel
      HorizontalAlignment="Right"
      DockPanel.Dock="Bottom"
      Orientation="Horizontal">
      <Button
        MinWidth="80"
        Margin="5"
        Command="{Binding DoSomethingCommand}"
        Content="OK">
        <i:Interaction.Triggers>
          <i:EventTrigger EventName="Click">
            <ei:ChangePropertyAction
              PropertyName="DialogResult"
              TargetObject="{Binding ElementName=SubWnd}"
              Value="True" />
          </i:EventTrigger>
        </i:Interaction.Triggers>
      </Button>
      <Button
        MinWidth="80"
        Margin="5"
        Content="Cancel"
        IsCancel="True" />
    </StackPanel>

    <StackPanel>
      <HeaderedContentControl Margin="5" Header="Text1">
        <TextBox Text="{Binding Text1, UpdateSourceTrigger=PropertyChanged}" Validation.ErrorTemplate="{StaticResource ValidationTemplate}" />
      </HeaderedContentControl>
      <HeaderedContentControl Margin="5" Header="Text2">
        <TextBox Text="{Binding Text2, UpdateSourceTrigger=PropertyChanged}" Validation.ErrorTemplate="{StaticResource ValidationTemplate}" />
      </HeaderedContentControl>
      <HeaderedContentControl Margin="5" Header="Text3">
        <TextBox Text="{Binding Text3, UpdateSourceTrigger=PropertyChanged}" Validation.ErrorTemplate="{StaticResource ValidationTemplate}" />
      </HeaderedContentControl>
    </StackPanel>
  </DockPanel>
</Window>
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Runtime.CompilerServices;
using Prism.Commands;
using Prism.Mvvm;

namespace WpfApp1
{
    public class SubViewModel : BindableBase, INotifyDataErrorInfo
    {
        [Required(ErrorMessage = "何か入力してください。")]
        public string Text1 { get => _Text1; set => SetProperty(ref _Text1, value); }
        private string _Text1;

        [MinLength(10, ErrorMessage = "10文字以上入力してください。")]
        public string Text2 { get => _Text2; set => SetProperty(ref _Text2, value); }
        private string _Text2;

        [RegularExpression("[a-z]+", ErrorMessage = "a-zの文字列を入力してください。")]
        public string Text3 { get => _Text3; set => SetProperty(ref _Text3, value); }
        private string _Text3;

        public DelegateCommand DoSomethingCommand { get; }


        public SubViewModel()
        {
            errorsContainer = new ErrorsContainer<string>(x => ErrorsChanged?.Invoke(this, new DataErrorsChangedEventArgs(x)));

            Text1 = ""; // ""に深い意味はない。初期値nullから動かしてValidatorを通してるだけ
            Text2 = "";
            Text3 = "A";

            DoSomethingCommand = new DelegateCommand(
                () => System.Diagnostics.Debug.WriteLine("DoSomethigCommand"),
                () => !HasErrors)
                .ObservesProperty(() => HasErrors);
        }


        #region INotifyDataErrorInfo
        private readonly ErrorsContainer<string> errorsContainer;
        public bool HasErrors => errorsContainer.HasErrors;
        public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;
        protected override bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
        {
            if(!base.SetProperty(ref storage, value, propertyName)) return false;

            var context = new ValidationContext(this) { MemberName = propertyName };
            var errors = new List<ValidationResult>();
            if(!Validator.TryValidateProperty(value, context, errors))
            {
                errorsContainer.SetErrors(propertyName, errors.Select(x => x.ErrorMessage));
            }
            else
            {
                errorsContainer.ClearErrors(propertyName);
            }
            RaisePropertyChanged(nameof(HasErrors));
            return true;
        }
        public IEnumerable GetErrors(string propertyName) => errorsContainer.GetErrors(propertyName);
        #endregion
    }
}

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/01/02 21:04

    非常に的確なご回答ありがとうございます。
    実現したかったことすべてが詰まっております。
    ありがとうございました。

    キャンセル

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

  • ただいまの回答率 87.96%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

同じタグがついた質問を見る