261

私は WPF と MVVM の問題を学習しようとしていますが、問題が発生しました。この質問は似ていますが、これとまったく同じではありません(handling-dialogs-in-wpf-with-mvvm) ...

MVVM パターンを使用して記述された「ログイン」フォームがあります。

このフォームには、通常のデータ バインディングを使用して XAML でビューにバインドされているユーザー名とパスワードを保持する ViewModel があります。また、通常のデータバインディングを使用して、フォームの「ログイン」ボタンにバインドされた「ログイン」コマンドもあります。

「Login」コマンドが起動すると、ViewModel 内の関数が呼び出され、ネットワーク経由でデータが送信されてログインされます。この関数が完了すると、次の 2 つのアクションが実行されます。

  1. ログインが無効でした - MessageBox を表示するだけで問題ありません

  2. ログインは有効でした。ログイン フォームを閉じて、true を返す必要がありDialogResultます。

問題は、ViewModel が実際のビューについて何も知らないことです。そのため、ビューを閉じて、特定の DialogResult を返すように指示するにはどうすればよいでしょうか?? CodeBehind にいくつかのコードを貼り付けたり、View を ViewModel に渡したりすることもできますが、それは MVVM のポイント全体を完全に無効にするようです...


アップデート

結局、私はMVVMパターンの「純度」に違反し、ビューにClosedイベントを発行させ、Closeメソッドを公開させました。ViewModel は を呼び出すだけview.Closeです。ビューはインターフェイスを介してのみ認識され、IOC コンテナーを介して接続されるため、テスト容易性や保守性が失われることはありません。

受け入れられた回答が-5票であることは、かなりばかげているようです! 「純粋」でありながら問題を解決することで得られる気持ちの良さはよく知っていますが、1 行のメソッドを回避するためだけに 200 行のイベント、コマンド、および動作が必要だと考えるのは私だけではありません。 「パターン」と「純度」の名前は少しばかげています....

4

25 に答える 25

336

より単純な添付プロパティを作成するというThejuan の回答に触発されました。スタイルもトリガーもありません。代わりに、これを行うことができます:

<Window ...
        xmlns:xc="clr-namespace:ExCastle.Wpf"
        xc:DialogCloser.DialogResult="{Binding DialogResult}">

これは、WPF チームが正しく理解し、最初に DialogResult を依存関係プロパティにしたかのようにクリーンです。ViewModel にプロパティを配置して INotifyPropertyChanged を実装するだけbool? DialogResultで、ViewModel はプロパティを設定するだけでウィンドウを閉じる (そしてその DialogResult を設定する) ことができます。あるべきMVVM。

DialogCloser のコードは次のとおりです。

using System.Windows;

namespace ExCastle.Wpf
{
    public static class DialogCloser
    {
        public static readonly DependencyProperty DialogResultProperty =
            DependencyProperty.RegisterAttached(
                "DialogResult",
                typeof(bool?),
                typeof(DialogCloser),
                new PropertyMetadata(DialogResultChanged));

        private static void DialogResultChanged(
            DependencyObject d,
            DependencyPropertyChangedEventArgs e)
        {
            var window = d as Window;
            if (window != null)
                window.DialogResult = e.NewValue as bool?;
        }
        public static void SetDialogResult(Window target, bool? value)
        {
            target.SetValue(DialogResultProperty, value);
        }
    }
}

これもブログに載せました。

于 2010-07-25T14:06:54.007 に答える
67

私の観点からは、「ログイン」ウィンドウだけでなく、あらゆる種類のウィンドウにも同じアプローチが使用されるため、この質問はかなり良いものです。多くの提案を確認しましたが、どれも私にとっては問題ありません。MVVM デザイン パターンの記事から引用した私の提案を確認してください。

各 ViewModel クラスは、型のイベントとプロパティをWorkspaceViewModel持つものから継承する必要があります。プロパティのデフォルトの実装は、イベントを発生させます。RequestCloseCloseCommandICommandCloseCommandRequestClose

ウィンドウを閉じるには、ウィンドウのOnLoadedメソッドをオーバーライドする必要があります。

void CustomerWindow_Loaded(object sender, RoutedEventArgs e)
{
    CustomerViewModel customer = CustomerViewModel.GetYourCustomer();
    DataContext = customer;
    customer.RequestClose += () => { Close(); };
}

またはOnStartupあなたのアプリの方法:

    protected override void OnStartup(StartupEventArgs e)
    {
        base.OnStartup(e);

        MainWindow window = new MainWindow();
        var viewModel = new MainWindowViewModel();
        viewModel.RequestClose += window.Close;
        window.DataContext = viewModel;

        window.Show();
    }

RequestCloseのイベントとCloseCommandプロパティの実装WorkspaceViewModelはかなり明確だと思いますが、それらが一貫していることを示します。

public abstract class WorkspaceViewModel : ViewModelBase
// There's nothing interesting in ViewModelBase as it only implements the INotifyPropertyChanged interface
{
    RelayCommand _closeCommand;
    public ICommand CloseCommand
    {
        get
        {
            if (_closeCommand == null)
            {
                _closeCommand = new RelayCommand(
                   param => Close(),
                   param => CanClose()
                   );
            }
            return _closeCommand;
        }
    }

    public event Action RequestClose;

    public virtual void Close()
    {
        if ( RequestClose != null )
        {
            RequestClose();
        }
    }

    public virtual bool CanClose()
    {
        return true;
    }
}

そして、のソースコードRelayCommand:

public class RelayCommand : ICommand
{
    #region Constructors

    public RelayCommand(Action<object> execute, Predicate<object> canExecute)
    {
        if (execute == null)
            throw new ArgumentNullException("execute");

        _execute = execute;
        _canExecute = canExecute;
    }
    #endregion // Constructors

    #region ICommand Members

    [DebuggerStepThrough]
    public bool CanExecute(object parameter)
    {
        return _canExecute == null ? true : _canExecute(parameter);
    }

    public event EventHandler CanExecuteChanged
    {
        add { CommandManager.RequerySuggested += value; }
        remove { CommandManager.RequerySuggested -= value; }
    }

    public void Execute(object parameter)
    {
        _execute(parameter);
    }

    #endregion // ICommand Members

    #region Fields

    readonly Action<object> _execute;
    readonly Predicate<object> _canExecute;

    #endregion // Fields
}

PSこれらのソースについて私をひどく扱わないでください!昨日それらがあれば、数時間節約できたでしょう...

PPSコメントや提案は大歓迎です。

于 2010-01-20T11:05:21.800 に答える
10

ログイン ダイアログが作成される最初のウィンドウであると仮定して、LoginViewModel クラス内でこれを試してください。

    void OnLoginResponse(bool loginSucceded)
    {
        if (loginSucceded)
        {
            Window1 window = new Window1() { DataContext = new MainWindowViewModel() };
            window.Show();

            App.Current.MainWindow.Close();
            App.Current.MainWindow = window;
        }
        else
        {
            LoginError = true;
        }
    }
于 2009-12-28T20:09:09.047 に答える
9

これはシンプルでクリーンな解決策です。ViewModel にイベントを追加し、そのイベントが発生したときにウィンドウを閉じるように指示します。

詳細については、私のブログ投稿、ViewModel からウィンドウを閉じるを参照してください。

XAML:

<Window
  x:Name="this"
  xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"  
  xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions">
  <i:Interaction.Triggers>
    <i:EventTrigger SourceObject="{Binding}" EventName="Closed">
      <ei:CallMethodAction
        TargetObject="{Binding ElementName=this}"
        MethodName="Close"/>
    </i:EventTrigger>
  </i:Interaction.Triggers>
<Window>

ビューモデル:

private ICommand _SaveAndCloseCommand;
public ICommand SaveAndCloseCommand
{
  get
  {
    return _SaveAndCloseCommand ??
      (_SaveAndCloseCommand = new DelegateCommand(SaveAndClose));
  }
}
private void SaveAndClose()
{
  Save();
  Close();
}

public event EventHandler Closed;
private void Close()
{
  if (Closed != null) Closed(this, EventArgs.Empty);
}

注: この例では Prism を使用していますがDelegateCommand( Prism: Commandingを参照)、どのICommand実装でも使用できます。

この公式パッケージのビヘイビアーを使用できます。

于 2011-10-06T08:14:18.963 に答える
6

これを処理する方法は、ViewModel にイベント ハンドラーを追加することです。ユーザーが正常にログインすると、イベントが発生します。私のビューでは、このイベントにアタッチし、イベントが発生したらウィンドウを閉じます。

于 2009-04-28T21:08:34.630 に答える
4

これは私が最初にしたことであり、うまくいきますが、かなり長くて醜いようです(グローバルな静的なものは決して良くありません)

1: アプリ.xaml.cs

public partial class App : Application
{
    // create a new global custom WPF Command
    public static readonly RoutedUICommand LoggedIn = new RoutedUICommand();
}

2: ログインフォーム.xaml

// bind the global command to a local eventhandler
<CommandBinding Command="client:App.LoggedIn" Executed="OnLoggedIn" />

3: ログインフォーム.xaml.cs

// implement the local eventhandler in codebehind
private void OnLoggedIn( object sender, ExecutedRoutedEventArgs e )
{
    DialogResult = true;
    Close();
}

4: LoginFormViewModel.cs

// fire the global command from the viewmodel
private void OnRemoteServerReturnedSuccess()
{
    App.LoggedIn.Execute(this, null);
}

その後、このコードをすべて削除し、そのLoginFormViewModelビューで Close メソッドを呼び出しました。それは最終的にはるかに素晴らしく、従うのが簡単になりました. パターンの要点は、アプリが何をしているかを人々が理解しやすい方法を提供することです。この場合、MVVM を使用していない場合よりも理解がはるかに難しくなり、アンチパターンになりました。

于 2009-02-02T00:31:41.560 に答える
3

参考までに、私はこの同じ問題に遭遇し、グローバルや静的を必要としない回避策を見つけたと思いますが、それは最良の答えではないかもしれません. 私はあなたたちにそれを自分で決めさせます。

私の場合、表示されるウィンドウをインスタンス化する ViewModel (ViewModelMain と呼びましょう) は、LoginFormViewModel についても認識しています (上記の状況を例として使用)。

そこで、LoginFormViewModel に ICommand 型のプロパティを作成しました (CloseWindowCommand と呼びましょう)。次に、ウィンドウで .ShowDialog() を呼び出す前に、LoginFormViewModel の CloseWindowCommand プロパティを、インスタンス化したウィンドウの window.Close() メソッドに設定します。次に、LoginFormViewModel 内で、CloseWindowCommand.Execute() を呼び出してウィンドウを閉じるだけです。

これはちょっとした回避策/ハックだと思いますが、MVVM パターンを実際に壊すことなくうまく機能します。

あなたが好きなだけこのプロセスを批判してください、私はそれを取ることができます! :)

于 2009-04-29T18:04:12.957 に答える
3

わかりました、この質問はほぼ6年前のもので、適切な答えだと思うものをここでまだ見つけることができないので、私の「2セント」を共有させてください...

私には実際には2つの方法があります.1つ目は単純なものです.2つ目は正しいものです.正しいものを探している場合は、#1をスキップして#2にジャンプしてください:

1. 迅速かつ簡単 (完全ではありません)

小さなプロジェクトしかない場合は、ViewModelでCloseWindowActionを作成するだけです。

        public Action CloseWindow { get; set; } // In MyViewModel.cs

ビューを作成する人、またはビューのコード ビハインドで、アクションが呼び出すメソッドを設定しただけです。

(MVVMはビューとビューモデルの分離に関するものであることを思い出してください...ビューのコードビハインドはまだビューであり、適切な分離がある限り、パターンに違反していません)

一部の ViewModel が新しいウィンドウを作成する場合:

private void CreateNewView()
{
    MyView window = new MyView();
    window.DataContext = new MyViewModel
                             {
                                 CloseWindow = window.Close,
                             }; 
    window.ShowDialog();
}

または、メイン ウィンドウに表示する場合は、ビューのコンストラクターの下に配置します。

public MyView()
{
    InitializeComponent();           
    this.DataContext = new MainViewModel
                           {
                                CloseWindow = this.Close
                           };
}

ウィンドウを閉じたいときは、ViewModel で Action を呼び出すだけです。


2. 正しい方法

現在、それを行う適切な方法はPrism (IMHO) を使用することであり、それについてはすべてここで見つけることができます。

インタラクション リクエストを作成し、新しいウィンドウで必要なデータを入力し、起動し、閉じて、データを受信することさえできます。これらはすべてカプセル化され、MVVM で承認されています。ユーザーまたは([OK]ボタン)ウィンドウとデータが必要な場合など、ウィンドウがどのように閉じられたかのステータスも取得します。これはもう少し複雑で回答 #1 ですが、より完全であり、Microsoft が推奨するパターンです。CanceledAccepted

私が提供したリンクにはすべてのコード スニペットと例が含まれているため、ここにコードを配置する必要はありません。Prism クイック スタートのダウンロードの記事を読んで実行してください。もう少し詳細に理解するのは本当に簡単です。動作させますが、メリットはウィンドウを閉じるだけではありません。

于 2015-06-13T23:17:02.067 に答える
3

これはおそらく非常に遅いですが、同じ問題に遭遇し、自分に合った解決策を見つけました。

ダイアログなしでアプリを作成する方法がわかりません(おそらくそれは単なるマインドブロックです)。だから私はMVVMで行き詰まり、ダイアログを表示していました。だから私はこのCodeProjectの記事に出くわしました:

http://www.codeproject.com/KB/WPF/XAMLDialog.aspx

これは、基本的にウィンドウを別のウィンドウのビジュアル ツリー内に配置できるようにする UserControl です (xaml では許可されていません)。また、IsShowing というブール値の DependencyProperty も公開します。

通常は resourcedictionary のようなスタイルを設定できます。これは、コントロールの Content プロパティがトリガーを介して != null の場合に基本的にダイアログを表示します。

<Style TargetType="{x:Type d:Dialog}">
    <Style.Triggers>
        <Trigger Property="HasContent"  Value="True">
            <Setter Property="Showing" Value="True" />
        </Trigger>
    </Style.Triggers>
</Style>

ダイアログを表示するビューでは、次のようにします。

<d:Dialog Content="{Binding Path=DialogViewModel}"/>

ViewModel では、プロパティを値に設定するだけです (注: ViewModel クラスは、ビューが何かが起こったことを知るために INotifyPropertyChanged をサポートする必要があります)。

そのようです:

DialogViewModel = new DisplayViewModel();

ViewModel を View と一致させるには、resourcedictionary に次のようなものが必要です。

<DataTemplate DataType="{x:Type vm:DisplayViewModel}">
    <vw:DisplayView/>
</DataTemplate>

以上で、ダイアログを表示するためのワンライナー コードが得られます。問題は、上記のコードだけではダイアログを閉じることができないことです。そのため、DisplayViewModel が継承する ViewModel 基本クラスにイベントを配置し、上記のコードの代わりに次のように記述する必要があります。

        var vm = new DisplayViewModel();
        vm.RequestClose += new RequestCloseHandler(DisplayViewModel_RequestClose);
        DialogViewModel = vm;

次に、コールバックを介してダイアログの結果を処理できます。

これは少し複雑に思えるかもしれませんが、基礎が築かれれば、非常に簡単です。繰り返しますが、これは私の実装です。他にもあると確信しています:)

これが役に立てば幸いです、それは私を救いました。

于 2009-05-28T18:08:04.913 に答える
3

ViewModel に、View が登録するイベントを公開させることができます。次に、ViewModel がビューを閉じる時間を決定すると、ビューを閉じるイベントを発生させます。特定の結果値を返したい場合は、ViewModel にそのためのプロパティがあります。

于 2011-02-23T22:00:27.900 に答える
2

膨大な数の回答に追加するために、次を追加したいと思います。ViewModel に ICommand があり、そのコマンドでウィンドウを閉じる (またはその他のアクションを実行する) と仮定すると、次のようなものを使用できます。

var windows = Application.Current.Windows;
for (var i=0;i< windows.Count;i++ )
    if (windows[i].DataContext == this)
        windows[i].Close();

完璧ではなく、テストが難しいかもしれませんが(静的なものをモック/スタブするのは難しいため)、他のソリューションよりもクリーンです(IMHO)。

エリック

于 2011-03-05T02:11:26.623 に答える
1

私は Joe White のソリューションを実装しましたが、「DialogResult can only set only after Window is created and shown as dialog」というエラーが時折発生するという問題に遭遇しました。

View を閉じた後も ViewModel を保持していましたが、後で同じ VM を使用して新しい View を開いたこともあります。古いビューがガベージ コレクションされる前に新しいビューを閉じると、閉じたウィンドウでDialogResultChanged が DialogResultプロパティを設定しようとしたため、エラーが発生したようです。

私の解決策は、DialogResultChanged を変更て、ウィンドウのIsLoadedプロパティを確認することでした。

private static void DialogResultChanged(
    DependencyObject d,
    DependencyPropertyChangedEventArgs e)
{
    var window = d as Window;
    if (window != null && window.IsLoaded)
        window.DialogResult = e.NewValue as bool?;
}

この変更を行った後、閉じたダイアログへの添付ファイルは無視されます。

于 2012-07-15T19:56:36.243 に答える
1

プログラムで作成されたウィンドウにユーザーコントロールを表示する必要があったため、Joe White の回答とAdam Mills の回答のコードをブレンドすることになりました。したがって、DialogCloser はウィンドウ上にある必要はなく、ユーザー コントロール自体にある場合があります。

<UserControl ...
    xmlns:xw="clr-namespace:Wpf"
    xw:DialogCloser.DialogResult="{Binding DialogResult}">

また、DialogCloser は、ウィンドウ自体にアタッチされていない場合、ユーザー コントロールのウィンドウを見つけます。

namespace Wpf
{
  public static class DialogCloser
  {
    public static readonly DependencyProperty DialogResultProperty =
        DependencyProperty.RegisterAttached(
            "DialogResult",
            typeof(bool?),
            typeof(DialogCloser),
            new PropertyMetadata(DialogResultChanged));

    private static void DialogResultChanged(
        DependencyObject d,
        DependencyPropertyChangedEventArgs e)
    {
      var window = d.GetWindow();
      if (window != null)
        window.DialogResult = e.NewValue as bool?;
    }

    public static void SetDialogResult(DependencyObject target, bool? value)
    {
      target.SetValue(DialogResultProperty, value);
    }
  }

  public static class Extensions
  {
    public static Window GetWindow(this DependencyObject sender_)
    {
      Window window = sender_ as Window;        
      return window ?? Window.GetWindow( sender_ );
    }
  }
}
于 2014-03-27T16:13:37.730 に答える
1

ウィンドウをコマンドパラメータとして渡さないのはなぜですか?

C#:

 private void Cancel( Window window )
  {
     window.Close();
  }

  private ICommand _cancelCommand;
  public ICommand CancelCommand
  {
     get
     {
        return _cancelCommand ?? ( _cancelCommand = new Command.RelayCommand<Window>(
                                                      ( window ) => Cancel( window ),
                                                      ( window ) => ( true ) ) );
     }
  }

XAML:

<Window x:Class="WPFRunApp.MainWindow"
        x:Name="_runWindow"
...
   <Button Content="Cancel"
           Command="{Binding Path=CancelCommand}"
           CommandParameter="{Binding ElementName=_runWindow}" />
于 2010-10-11T18:49:37.310 に答える
0

私はこのように行きます:

using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;    
using GalaSoft.MvvmLight.Messaging; 

// View

public partial class TestCloseWindow : Window
{
    public TestCloseWindow() {
        InitializeComponent();
        Messenger.Default.Register<CloseWindowMsg>(this, (msg) => Close());
    }
}

// View Model

public class MainViewModel: ViewModelBase
{
    ICommand _closeChildWindowCommand;

    public ICommand CloseChildWindowCommand {
        get {
            return _closeChildWindowCommand?? (_closeChildWindowCommand = new RelayCommand(() => {
                Messenger.Default.Send(new CloseWindowMsg());
        }));
        }
    }
}

public class CloseWindowMsg
{
}
于 2014-08-08T21:34:02.103 に答える
0

もう 1 つの解決策は、DialogResult のようなビュー モデルで INotifyPropertyChanged を使用してプロパティを作成し、コード ビハインドで次のように記述することです。

public class SomeWindow: ChildWindow
{
    private SomeViewModel _someViewModel;

    public SomeWindow()
    {
        InitializeComponent();

        this.Loaded += SomeWindow_Loaded;
        this.Closed += SomeWindow_Closed;
    }

    void SomeWindow_Loaded(object sender, RoutedEventArgs e)
    {
        _someViewModel = this.DataContext as SomeViewModel;
        _someViewModel.PropertyChanged += _someViewModel_PropertyChanged;
    }

    void SomeWindow_Closed(object sender, System.EventArgs e)
    {
        _someViewModel.PropertyChanged -= _someViewModel_PropertyChanged;
        this.Loaded -= SomeWindow_Loaded;
        this.Closed -= SomeWindow_Closed;
    }

    void _someViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        if (e.PropertyName == SomeViewModel.DialogResultPropertyName)
        {
            this.DialogResult = _someViewModel.DialogResult;
        }
    }
}

最も重要なフラグメントは_someViewModel_PropertyChanged. DialogResultPropertyNameの public const 文字列にすることができますSomeViewModel

ViewModel でこれを行うのが難しい場合に備えて、この種のトリックを使用して View Controls にいくつかの変更を加えます。ViewModel で OnPropertyChanged を使用すると、View で必要なことを何でも実行できます。ViewModel は引き続き「ユニット テスト可能」であり、コード ビハインドのいくつかの小さなコード行は違いはありません。

于 2012-03-21T12:54:08.607 に答える
0

私はすべての回答を読みましたが、それらのほとんどは十分ではないか、さらに悪いと言わざるを得ません.

ダイアログウィンドウを表示し、ダイアログ結果を返す責任があるDialogServiceクラスを使用して、これを美しく処理できます。実装と使用法を示すサンプル プロジェクトを作成しました。

最も重要な部分は次のとおりです。

//we will call this interface in our viewmodels
public interface IDialogService
{
    bool? ShowDialog(object dialogViewModel, string caption);
}

//we need to display logindialog from mainwindow
public class MainWindowViewModel : ViewModelBase
{
    public string Message {get; set;}
    public void ShowLoginCommandExecute()
    {
        var loginViewModel = new LoginViewModel();
        var dialogResult = this.DialogService.ShowDialog(loginViewModel, "Please, log in");

        //after dialog is closed, do someting
        if (dialogResult == true && loginViewModel.IsLoginSuccessful)
        {
            this.Message = string.Format("Hello, {0}!", loginViewModel.Username);
        }
    }
}


public class DialogService : IDialogService
{
    public bool? ShowDialog(object dialogViewModel, string caption)
    {
        var contentView = ViewLocator.GetView(dialogViewModel);
        var dlg = new DialogWindow
        {
            Title = caption
        };
        dlg.PART_ContentControl.Content = contentView;

        return dlg.ShowDialog();
    }
}

これは単純なことではありませんか?EventAggregator や他の同様のソリューションよりも簡単で、読みやすく、最後にデバッグが簡単ですか?

ご覧のとおり、私のビュー モデルでは、こちらの投稿で説明されている ViewModel の最初のアプローチを使用しています: WPF で ViewModel から View を呼び出すためのベスト プラクティス

もちろん、実際には、DialogService.ShowDialog実行するボタンやコマンドなど、ダイアログを構成するためのより多くのオプションが必要です。これを行うにはさまざまな方法がありますが、範囲外です:)

于 2015-03-14T18:12:27.137 に答える
0

これはバグのないシンプルなソリューションです (ソース コード付き)。

  1. からViewModelを派生させますINotifyPropertyChanged

  2. ViewModel で観察可能なプロパティCloseDialogを作成する

    public void Execute()
    {
        // Do your task here
    
        // if task successful, assign true to CloseDialog
        CloseDialog = true;
    }
    
    private bool _closeDialog;
    public bool CloseDialog
    {
        get { return _closeDialog; }
        set { _closeDialog = value; OnPropertyChanged(); }
    }
    
    public event PropertyChangedEventHandler PropertyChanged;
    
    private void OnPropertyChanged([CallerMemberName]string property = "")
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(property));
        }
    }
    

    }

  3. このプロパティの変更のためにビューでハンドラーをアタッチします

        _loginDialogViewModel = new LoginDialogViewModel();
        loginPanel.DataContext = _loginDialogViewModel;
        _loginDialogViewModel.PropertyChanged += OnPropertyChanged;
    
  4. これでほぼ完了です。イベントハンドラのmakeでDialogResult = true

    protected void OnPropertyChanged(object sender, PropertyChangedEventArgs args)
    {
        if (args.PropertyName == "CloseDialog")
        {
            DialogResult = true;
        }
    }
    
于 2015-05-30T12:50:33.223 に答える
0

/anyに a を作成Dependency Propertyします(または閉じたい)。以下のように:ViewUserControlWindow

 public bool CloseTrigger
        {
            get { return (bool)GetValue(CloseTriggerProperty); }
            set { SetValue(CloseTriggerProperty, value); }
        }

        public static readonly DependencyProperty CloseTriggerProperty =
            DependencyProperty.Register("CloseTrigger", typeof(bool), typeof(ControlEventBase), new PropertyMetadata(new PropertyChangedCallback(OnCloseTriggerChanged)));

        private static void OnCloseTriggerChanged(DependencyObject dp, DependencyPropertyChangedEventArgs e)
        {
            //write Window Exit Code
        }

ViewModel のプロパティからバインドします。

<Window x:Class="WpfStackOverflowTempProject.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow"  Width="525"
        CloseTrigger="{Binding Path=CloseWindow,Mode=TwoWay}"

プロパティインVeiwModel:

private bool closeWindow;

    public bool CloseWindow
    {
        get { return closeWindow; }
        set 
        { 
            closeWindow = value;
            RaiseChane("CloseWindow");
        }
    }

CloseWindowViewModelの値を変更して、閉じる操作をトリガーします。:)

于 2016-02-08T10:39:27.833 に答える
0

これはビューモデルを介してこれを行う方法の質問には答えませんが、XAML + ブレンド SDK のみを使用してそれを行う方法を示しています。

今回は、Blend SDK から 2 つのファイルをダウンロードして使用することにしました。どちらも NuGet を介して Microsoft からパッケージとして入手できます。ファイルは次のとおりです。

System.Windows.Interactivity.dll および Microsoft.Expression.Interactions.dll

Microsoft.Expression.Interactions.dll は、ビューモデルやその他のターゲットでプロパティを設定したり、メソッドを呼び出したりする機能などの優れた機能を提供し、内部に他のウィジェットも備えています。

一部の XAML:

<Window x:Class="Blah.Blah.MyWindow"
    ...
    xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
    xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
  ...>
 <StackPanel>
    <Button x:Name="OKButton" Content="OK">
       <i:Interaction.Triggers>
          <i:EventTrigger EventName="Click">
             <ei:ChangePropertyAction
                      TargetObject="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}"
                      PropertyName="DialogResult"
                      Value="True"
                      IsEnabled="{Binding SomeBoolOnTheVM}" />                                
          </i:EventTrigger>
    </Button>
    <Button x:Name="CancelButton" Content="Cancel">
       <i:Interaction.Triggers>
          <i:EventTrigger EventName="Click">
             <ei:ChangePropertyAction
                      TargetObject="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}"
                      PropertyName="DialogResult"
                      Value="False" />                                
          </i:EventTrigger>
    </Button>

    <Button x:Name="CloseButton" Content="Close">
       <i:Interaction.Triggers>
                <i:EventTrigger EventName="Click">
                    <!-- method being invoked should be void w/ no args -->
                    <ei:CallMethodAction
                        TargetObject="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}"
                        MethodName="Close" />
                </i:EventTrigger>
            </i:Interaction.Triggers>
    </Button>
 <StackPanel>
</Window>

単純な OK/Cancel 動作だけを行う場合は、ウィンドウが Window.ShowDialog() で表示されている限り、IsDefault および IsCancel プロパティを使用して回避できることに注意してください。
個人的には、IsDefault プロパティが true に設定されているボタンに問題がありましたが、ページが読み込まれると非表示になりました。表示された後にうまく再生したくないようだったので、代わりに上記のように Window.DialogResult プロパティを設定しているだけで、うまくいきます。

于 2015-04-02T00:05:04.480 に答える
-2

ウィンドウを閉じる必要がある場合は、これをビューモデルに入れるだけです。

タダ

  foreach (Window window in Application.Current.Windows)
        {
            if (window.DataContext == this)
            {
                window.Close();
                return;
            }
        }
于 2014-01-31T08:02:41.513 に答える
-8
Application.Current.MainWindow.Close() 

もういい!

于 2011-07-21T09:52:06.503 に答える