19

MVVM パターンに固執しているときに MainWindow が読み込まれると、ログイン ウィンドウを表示しようとしています。そのため、メイン ウィンドウの Loaded イベントをビューモデルのイベントにバインドしようとしています。これが私が試したことです:

MainWindowView.xaml

 <Window x:Class="ScrumManagementClient.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525"
        DataContext="ViewModel.MainWindowViewModel"
        Loaded="{Binding ShowLogInWindow}">
    <Grid>

    </Grid>
 </Window>

MainWindowViewModel.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ScrumManagementClient.ViewModel
{
    class MainWindowViewModel : ViewModelBase
    {
        public void ShowLogInWindow(object sender, EventArgs e)
        {
            int i = 0;
        }
    }
}

「Loaded="{Binding ShowLogInWindow}" is not valid. '{Binding ShowLogInWindow}' is not a valid event handler method name. Only instance methods on the generated or code-behind class is valid." というエラー メッセージが表示されます。

4

5 に答える 5

36

System.Windows.Interactivity dll を使用する必要があります。

次に、XAML に名前空間を追加します。

xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"

次に、次のようなことができます。

<i:Interaction.Triggers>
    <i:EventTrigger EventName="Loaded">
        <i:InvokeCommandAction Command="{Binding MyICommandThatShouldHandleLoaded}" />
    </i:EventTrigger>
</i:Interaction.Triggers>

ICommand(または、Prism を使用する場合は DelegateCommand、MVVMLight を使用する場合は RelayCommand) を使用する必要があり、ウィンドウの DataContext はその ICommand を保持する必要があることに注意してください。

于 2011-10-25T10:32:29.937 に答える
7

アタッチされた動作を使用します。それはMVVMで許可されています....

(以下のコードは、そのようにコンパイルされる場合とコンパイルされない場合があります)

XAML ...

   <Window x:Class="..."
           ...
           xmlns:local="... namespace of the attached behavior class ..."
           local:MyAttachedBehaviors.LoadedCommand="{Binding ShowLogInWindowCommand}">
     <Grid>
     </Grid>
  </Window> 

コードビハインド...

  class MainWindowViewModel : ViewModelBase
  {
      private ICommand _showLogInWindowCommand;

      public ICommand ShowLogInWindowCommand
      {
         get
         {
              if (_showLogInWindowCommand == null)
              {
                  _showLogInWindowCommand = new DelegateCommand(OnLoaded)
              }
              return _showLogInWindowCommand;
         }
      }

      private void OnLoaded()
      {
          //// Put all your code here....
      }
  } 

そして、付属の動作...

  public static class MyAttachedBehaviors
  {
      public static DependencyProperty LoadedCommandProperty
        = DependencyProperty.RegisterAttached(
             "LoadedCommand",
             typeof(ICommand),
             typeof(MyAttachedBehaviors),
             new PropertyMetadata(null, OnLoadedCommandChanged));

      private static void OnLoadedCommandChanged
           (DependencyObject depObj, DependencyPropertyChangedEventArgs e)
      {
          var frameworkElement = depObj as FrameworkElement;
          if (frameworkElement != null && e.NewValue is ICommand)
          {
               frameworkElement.Loaded 
                 += (o, args) =>
                    {
                        (e.NewValue as ICommand).Execute(null);
                    };
          }
      }

      public static ICommand GetLoadedCommand(DependencyObject depObj)
      {
         return (ICommand)depObj.GetValue(LoadedCommandProperty);
      }

      public static void SetLoadedCommand(
          DependencyObject depObj,
          ICommand  value)
      {
         depObj.SetValue(LoadedCommandProperty, value);
      }
  }

DelegateCommandソース コードはインターネット上で見つけることができます... MVVM で利用できる最も適した ICommand API です。

edit:19.07.2016 2 つの小さな構文エラーを修正

于 2011-10-25T11:34:06.403 に答える
3

アップデート:

ここで、少し異なる構文を使用する、より柔軟な新しいバージョンのメソッド バインディングについて投稿しました。

http://www.singulink.com/CodeIndex/post/updated-ultimate-wpf-event-method-binding

完全なコード リストは次の場所にあります。

https://gist.github.com/mikernet/7eb18408ffbcc149f1d9b89d9483fc19

今後の更新はブログに投稿されますので、最新バージョンを確認することをお勧めします。

元の回答:

.NET 4.5+ では、イベントのマークアップ拡張機能がサポートされるようになりました。これを使用して、次のように使用できるメソッド バインディングを作成しました。

<!--  Basic usage  -->
<Button Click="{data:MethodBinding OpenFromFile}" Content="Open" />

<!--  Pass in a binding as a method argument  -->
<Button Click="{data:MethodBinding Save, {Binding CurrentItem}}" Content="Save" />

<!--  Another example of a binding, but this time to a property on another element  -->
<ComboBox x:Name="ExistingItems" ItemsSource="{Binding ExistingItems}" />
<Button Click="{data:MethodBinding Edit, {Binding SelectedItem, ElementName=ExistingItems}}" />

<!--  Pass in a hard-coded method argument, XAML string automatically converted to the proper type  -->
<ToggleButton Checked="{data:MethodBinding SetWebServiceState, True}"
                Content="Web Service"
                Unchecked="{data:MethodBinding SetWebServiceState, False}" />

<!--  Pass in sender, and match method signature automatically -->
<Canvas PreviewMouseDown="{data:MethodBinding SetCurrentElement, {data:EventSender}, ThrowOnMethodMissing=False}">
    <controls:DesignerElementTypeA />
    <controls:DesignerElementTypeB />
    <controls:DesignerElementTypeC />
</Canvas>

    <!--  Pass in EventArgs  -->
<Canvas MouseDown="{data:MethodBinding StartDrawing, {data:EventArgs}}"
        MouseMove="{data:MethodBinding AddDrawingPoint, {data:EventArgs}}"
        MouseUp="{data:MethodBinding EndDrawing, {data:EventArgs}}" />

<!-- Support binding to methods further in a property path -->
<Button Content="SaveDocument" Click="{data:MethodBinding CurrentDocument.DocumentService.Save, {Binding CurrentDocument}}" />

モデル メソッド シグネチャを表示します。

public void OpenFromFile();
public void Save(DocumentModel model);
public void Edit(DocumentModel model);

public void SetWebServiceState(bool state);

public void SetCurrentElement(DesignerElementTypeA element);
public void SetCurrentElement(DesignerElementTypeB element);
public void SetCurrentElement(DesignerElementTypeC element);

public void StartDrawing(MouseEventArgs e);
public void AddDrawingPoint(MouseEventArgs e);
public void EndDrawing(MouseEventArgs e);

public class Document
{
    // Fetches the document service for handling this document
    public DocumentService DocumentService { get; }
}

public class DocumentService
{
    public void Save(Document document);
}

詳細はこちら: http://www.singulink.com/CodeIndex/post/building-the-ultimate-wpf-event-method-binding-extension

完全なクラス コードは、 https ://gist.github.com/mikernet/4336eaa8ad71cb0f2e35d65ac8e8e161 から入手できます。

于 2016-07-05T18:46:02.910 に答える
0

動作を使用するより一般的な方法は、 AttachedCommandBehavior V2 別名 ACBで提案されており、複数のイベントからコマンドへのバインディングもサポートしています。

以下は非常に基本的な使用例です。

<Window x:Class="Example.YourWindow"
        xmlns:local="clr-namespace:AttachedCommandBehavior;assembly=AttachedCommandBehavior"
        local:CommandBehavior.Event="Loaded"
        local:CommandBehavior.Command="{Binding DoSomethingWhenWindowIsLoaded}"
        local:CommandBehavior.CommandParameter="Some information"
/>
于 2012-12-12T12:51:20.357 に答える
-1

VS 2013 Update 5 では、「タイプ 'System.Reflection.RuntimeEventInfo' のオブジェクトをタイプ 'System.Reflection.MethodInfo' にキャストできません」を回避できませんでした。代わりに、「コア」ディレクトリに単純なインターフェイスを作成しました

interface ILoad
    {
        void load();
    }

私のビューモデルには、すでに ILoad を実装する load() 関数がありました。私の .xaml.cs では、ILoad を介して ViewModel の load() を呼び出します。

private void ml_Loaded(object sender, RoutedEventArgs e)
{
    (this.ml.DataContext as Core.ILoad).load();
}

xaml.cs は POCO ILoad を除いて ViewModel について何も知りません。ViewModel は xaml.cs について何も知りません。ml_loaded イベントは、ViewModel の load() にマップされます。

于 2015-10-27T19:19:18.597 に答える