テストの場としてのManaged Extensibility Framework(MEF)

考慮すべき質問

質問1:MEFとINotifyPropertyChanged:エクスポートされたオブジェクトに変更を通知する方法は?
質問2:MEFを通じてコレクションとしてインポートされたプロパティの変更の通知(ImportMany)。
質問3:MEFを介してオンデマンドでXAPファイルをダウンロードします。
質問4:MVVMパターンのモーダルウィンドウ。

問題文(ウィッシュリスト)

ウィッシュリスト番号1 :1つのモジュール(シェル)がコンパイル段階でMEFを使用してモジュールを「検索」できるようにし、サードパーティのモジュールをオンデマンドで「ロード」できるようにします(「ダウンロード」ボタンをクリックするなど)。

ウィッシュリスト番号2 :また、あるエディターのウィンドウでオブジェクトの編集を開始すると、変更がすぐに別のウィンドウに転送されることを望みます。

ウィッシュリスト番号3 :エンティティ(myObject)のエディターのいくつかのオプションをアプリケーションで実行できるようにします。 2つあり、1つのエディターはアプリケーションのメインモジュールに組み込まれ、アプリケーションの起動時にすぐに使用可能になり、2つ目は一般に別のXAPファイルにあり、オンデマンドでプロジェクトにロードされた場合にのみ使用可能になります(海外のOnDemandのように聞こえます) )

ウィッシュリスト番号4 :エディターをモーダルウィンドウで開きたい。

実装で使用されるアセンブリ

この記事、特にこのソリューションでは、自分のライブラリ(クラスアセンブリ)を使用することをすぐに予約してください。 それらの1つはCalabonga.Silverlight.Framework.dllであり、偶然にもバージョンを1.0.5に更新しました。 置換可能なコンテキストを持つモーダルウィンドウ(ModalDialog)の実装用のインターフェイスを追加します。 (再び使用例がプロジェクトにあります。)したがって、モデルウィンドウをMVVMパターンで使用し、このウィンドウ内の他のViewクラスを置き換えることができます。

常にモジュールのロードと通信しないようにするために作成した2番目のアセンブリは、XapServiceと呼ばれていました。 これは、DeploymentCatalogServiceの実装です。 アセンブリは、ダウンロード可能なプロジェクト内にあり、使用例です。

「ウィッシュリスト」の実装

ご存じのとおり、ソリューションはソリューション(ソリューション)の形で用意されており、いくつかのプロジェクトがあります。 今回は、1つのソリューションで6つのプロジェクトが必要でした。 (SLN):

画像

1.「決定の構造とその一部であるプロジェクト」

MefTestはメインプロジェクトであり、この記事のコンテキストでは、これはモジュールのシェル(シェル)です。 このプロジェクトには、ウィッシュリスト1で言及されたモジュールの1つ(「スタッフ」と呼びましょう)が含まれています。 また、編集者の1人(ウィッシュリスト番号3を参照)。 ローカルモジュールウィンドウは次のようになります。

画像

2.「内部モジュールの表示」

MefTest.Webは、私の実験がホスト(起動)されるASP.NETアプリケーションです。

FormViewは外部モジュールです(「アカウンティング」などと呼びましょう)。 これは、ウィッシュリスト1に記載されているモジュールの1つです。

画像

3.「外部モジュールの表示」

ContractLibrary-契約とインターフェースのライブラリ。 このアセンブリの名前は、私の実験クラスMyObjectです。 そして、すべてのモジュールがクラスの存在を認識するように、このアセンブリはすべてのモジュールで使用されます。

AdvancedEditor-Wishlist No. 3で言及されたエディターの実装の1つ。

Wishlist 2が機能するようにINotifyPropertyChangedを実装する単純なクラスMyObjectを試します。 コードでは次のようになります。
public class MyObject : INotifyPropertyChanged
{
private string cityType;
public string Name
{
get { return name; }
set
{
name = value;
OnPropertyChanged("Name");
}
}
private string name;
public string CityType
{
get { return cityType; }
set
{
cityType = value;
OnPropertyChanged("CityType");
}
}

#region INotifyPropertyChanged Implementation
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
#endregion
}


MainPage(メインシェル)で、IDeploymentCatalogService xapファイルローダーを実装します。これにより、オンデマンドでxapファイルを読み込むことができます。

public partial class MainPage : UserControl, IPartImportsSatisfiedNotification
{
[Import]
public IDeploymentCatalogService CatalogService { get; set; }

public MainPage()
{
InitializeComponent();
CompositionInitializer.SatisfyImports(this);
}

[ImportMany(typeof(UserControl), AllowRecomposition=true)]
public UserControl[] Views { get; set; }

public void OnImportsSatisfied()
{
LayoutRoot.Children.Clear();
foreach (UserControl item in Views)
{
LayoutRoot.Children.Add(item);
}
}
}


モーダルダイアログウィンドウ(ModalDialog)

画面にさまざまなエディターを表示するために、これらのモジュールをモーダルウィンドウに表示する方法よりも賢いことは考えませんでした(すみませんが、UIインターフェースの設計は苦手です)。 モーダルダイアログの構造の本質は、「フレーム」自体がモーダルであることです。 このフレームワークの内部コンテキストは任意です。 したがって、「スタッフ」モジュール(FormLocalがシェルと呼ばれるメインプロジェクトのローカル内部モジュール)がコードビハインドを使用する場合、「アカウンティング」モジュール(FormViewを参照)はすでにMVVM(model-view-viewmodel)のルールに従って実行されます)パターン。 モーダルウィンドウの実装の詳細については、プロジェクト自体のすべてを確認できます。プロジェクト自体はダウンロードできます(記事の最後にあるリンク)。

ダイアログボックスのモダリティについて簡単に説明すると、次のように言えます-動作します! すべての機能は、エクスポートの突出元であるライブラリに 「接続」されています 。 (興味深い場合は、別の記事でModalDialogがどのように機能するかを説明します。この記事はダイアログに関するものではないためです)。 たとえば、次のようになります。

FormExternalViewModelクラスには、ウィンドウの外観のインターフェイスであるModalDialogプロパティがあります。

[Import]
public IModalDialog ModalDialog
{
get;
set;
}


ホイールを再発明しないように、SilverlightライブラリのコントロールからChildWindowコントロール(ExtendedChildWindowと呼びます)を取得し、必要な機能、特にIModalDialogをそのライブラリからリリースすることにしました。

[Export(typeof(IModalDialog))]
public class ExtendedChildWindow : ChildWindow, IModalDialog
{
public void ShowDialog()
{
this.Width = 450;
this.Height = 300;
this.Show();
}
}


FormExternalViewModelクラスにもプロパティがあります。

[ImportMany(AllowRecomposition = true)]
public IModalView[] Editors { get; set; }


IModalViewインターフェイスは、モーダルウィンドウのコンテキスト実装にすぎません。 つまり、このインターフェイスを実装するビジュアルコントロール(Viewまたはその他のがらくた)は、モーダルウィンドウに表示できます。 このプロジェクトでは、内部エディターと外部エディターという2つ以上のプロジェクトがありました。 さて、最後に、モーダルウィンドウのいわゆる「オープナー」について:

[インポート]
public IModalDialogWorker ModalDialogWorker {get; セット; }

FormExternalViewModelクラスのこのプロパティは、OpenDialogCommandコマンドから呼び出されるモーダルダイアログの「ランチャー」をCalabonga.Silverlight.Framework.dllライブラリからインポートします。

this.ModalDialogWorker.ShowDialog(this.ModalDialog, view, o, dialog =>
{
if (this.ModalDialog.DialogResult.HasValue &&
this.ModalDialog.DialogResult.Value)
{
}
});

"" ModalDialogWorker, Calabonga.Silverlight.Framework:

namespace Calabonga.Silverlight.Framework
{
[Export(typeof(IModalDialogWorker))]
public class ModalDialogWorker : IModalDialogWorker
{
public void ShowDialog(IModalDialog modalDialog, IModalView modalView, T dataContext, Action onClosed)
{
if (modalDialog == null)
throw new ArgumentNullException("modalDialog", " null");
if (modalView == null)
throw new ArgumentNullException("modalView", " null");

EventHandler onDialogClosedHandler = null;
EventHandler onViewClosedHandler = null;

if (onClosed != null)
{
onDialogClosedHandler = (s, a) =>
{
modalDialog.Closed -= onDialogClosedHandler;
onClosed(dataContext);
};

onViewClosedHandler = (s, a) =>
{
modalDialog.Closed -= onDialogClosedHandler;
modalView.Closed -= onViewClosedHandler;
modalDialog.DialogResult = a.DialogResult;
onClosed(dataContext);
};

modalDialog.Closed += onDialogClosedHandler;
modalView.Closed += onViewClosedHandler;
}

modalDialog.Content = modalView;
modalView.DataContext = dataContext;
modalDialog.ShowDialog();
}
}
}

, "" .

MEF
(shell) "" ( ), Managed Extensibility Framework (MEF). MEF , :

using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;

, , . XAP-. , , (ExportAttribute), , FormExternal FormView:

[Export(typeof(UserControl))]
public partial class FormExternal : UserControl
{
public FormExternal()
{
InitializeComponent();
}
}


, , , , . (, , ...). () . View:

[ImportMany(typeof(UserControl), AllowRecomposition=true)]
public UserControl[] Views { get; set; }


:

AllowRecomposition=true

, MEF-. , . , . , , :

public MainPage()
{
InitializeComponent();
CompositionInitializer.SatisfyImports(this);
}


MEF- IPartImportsSatisfiedNotification, :

public void OnImportsSatisfied()
{
LayoutRoot.Children.Clear();
foreach (UserControl item in Views)
{
LayoutRoot.Children.Add(item);
}
}


. :

画像

, "", CheckBox . :

private IModalView[] editors;
[ImportMany(AllowRecomposition = true)]
public IModalView[] Editors
{
get
{ return editors; }
set
{
editors = value;
checkEditor.IsEnabled = (this.Editors != null) && (this.Editors.Count() > 1);
OnPropertyChanged("Editors");
}
}


Code-Bihind ViewModel (MVVM) ( ), . , "" ... !!!

画像

. , " " , , "" (. №3 AdvancedEditor).

private void Button_Click(object sender, RoutedEventArgs e)
{
CatalogService.AddXap("FormView.xap");
CatalogService.AddXap("AdvancedEditor.xap");
(sender as Button).IsEnabled = false;
}


, , ( ) , INotifyPropertyChanged.

: Memento .

, , CheckBox . , ( ) .

画像

- . ! ?! ! 画像

Visual Studio 2010
this.ModalDialogWorker.ShowDialog(this.ModalDialog, view, o, dialog =>
{
if (this.ModalDialog.DialogResult.HasValue &&
this.ModalDialog.DialogResult.Value)
{
}
});

"" ModalDialogWorker, Calabonga.Silverlight.Framework:

namespace Calabonga.Silverlight.Framework
{
[Export(typeof(IModalDialogWorker))]
public class ModalDialogWorker : IModalDialogWorker
{
public void ShowDialog(IModalDialog modalDialog, IModalView modalView, T dataContext, Action onClosed)
{
if (modalDialog == null)
throw new ArgumentNullException("modalDialog", " null");
if (modalView == null)
throw new ArgumentNullException("modalView", " null");

EventHandler onDialogClosedHandler = null;
EventHandler onViewClosedHandler = null;

if (onClosed != null)
{
onDialogClosedHandler = (s, a) =>
{
modalDialog.Closed -= onDialogClosedHandler;
onClosed(dataContext);
};

onViewClosedHandler = (s, a) =>
{
modalDialog.Closed -= onDialogClosedHandler;
modalView.Closed -= onViewClosedHandler;
modalDialog.DialogResult = a.DialogResult;
onClosed(dataContext);
};

modalDialog.Closed += onDialogClosedHandler;
modalView.Closed += onViewClosedHandler;
}

modalDialog.Content = modalView;
modalView.DataContext = dataContext;
modalDialog.ShowDialog();
}
}
}

, "" .

MEF
(shell) "" ( ), Managed Extensibility Framework (MEF). MEF , :

using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;

, , . XAP-. , , (ExportAttribute), , FormExternal FormView:

[Export(typeof(UserControl))]
public partial class FormExternal : UserControl
{
public FormExternal()
{
InitializeComponent();
}
}


, , , , . (, , ...). () . View:

[ImportMany(typeof(UserControl), AllowRecomposition=true)]
public UserControl[] Views { get; set; }


:

AllowRecomposition=true

, MEF-. , . , . , , :

public MainPage()
{
InitializeComponent();
CompositionInitializer.SatisfyImports(this);
}


MEF- IPartImportsSatisfiedNotification, :

public void OnImportsSatisfied()
{
LayoutRoot.Children.Clear();
foreach (UserControl item in Views)
{
LayoutRoot.Children.Add(item);
}
}


. :

画像

, "", CheckBox . :

private IModalView[] editors;
[ImportMany(AllowRecomposition = true)]
public IModalView[] Editors
{
get
{ return editors; }
set
{
editors = value;
checkEditor.IsEnabled = (this.Editors != null) && (this.Editors.Count() > 1);
OnPropertyChanged("Editors");
}
}


Code-Bihind ViewModel (MVVM) ( ), . , "" ... !!!

画像

. , " " , , "" (. №3 AdvancedEditor).

private void Button_Click(object sender, RoutedEventArgs e)
{
CatalogService.AddXap("FormView.xap");
CatalogService.AddXap("AdvancedEditor.xap");
(sender as Button).IsEnabled = false;
}


, , ( ) , INotifyPropertyChanged.

: Memento .

, , CheckBox . , ( ) .

画像

- . ! ?! ! 画像

Visual Studio 2010
this.ModalDialogWorker.ShowDialog(this.ModalDialog, view, o, dialog =>
{
if (this.ModalDialog.DialogResult.HasValue &&
this.ModalDialog.DialogResult.Value)
{
}
});

"" ModalDialogWorker, Calabonga.Silverlight.Framework:

namespace Calabonga.Silverlight.Framework
{
[Export(typeof(IModalDialogWorker))]
public class ModalDialogWorker : IModalDialogWorker
{
public void ShowDialog(IModalDialog modalDialog, IModalView modalView, T dataContext, Action onClosed)
{
if (modalDialog == null)
throw new ArgumentNullException("modalDialog", " null");
if (modalView == null)
throw new ArgumentNullException("modalView", " null");

EventHandler onDialogClosedHandler = null;
EventHandler onViewClosedHandler = null;

if (onClosed != null)
{
onDialogClosedHandler = (s, a) =>
{
modalDialog.Closed -= onDialogClosedHandler;
onClosed(dataContext);
};

onViewClosedHandler = (s, a) =>
{
modalDialog.Closed -= onDialogClosedHandler;
modalView.Closed -= onViewClosedHandler;
modalDialog.DialogResult = a.DialogResult;
onClosed(dataContext);
};

modalDialog.Closed += onDialogClosedHandler;
modalView.Closed += onViewClosedHandler;
}

modalDialog.Content = modalView;
modalView.DataContext = dataContext;
modalDialog.ShowDialog();
}
}
}

, "" .

MEF
(shell) "" ( ), Managed Extensibility Framework (MEF). MEF , :

using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;


, , . XAP-. , , (ExportAttribute), , FormExternal FormView:

[Export(typeof(UserControl))]
public partial class FormExternal : UserControl
{
public FormExternal()
{
InitializeComponent();
}
}


, , , , . (, , ...). () . View:

[ImportMany(typeof(UserControl), AllowRecomposition=true)]
public UserControl[] Views { get; set; }


:

AllowRecomposition=true

, MEF-. , . , . , , :

public MainPage()
{
InitializeComponent();
CompositionInitializer.SatisfyImports(this);
}


MEF- IPartImportsSatisfiedNotification, :

public void OnImportsSatisfied()
{
LayoutRoot.Children.Clear();
foreach (UserControl item in Views)
{
LayoutRoot.Children.Add(item);
}
}


. :

画像

, "", CheckBox . :

private IModalView[] editors;
[ImportMany(AllowRecomposition = true)]
public IModalView[] Editors
{
get
{ return editors; }
set
{
editors = value;
checkEditor.IsEnabled = (this.Editors != null) && (this.Editors.Count() > 1);
OnPropertyChanged("Editors");
}
}


Code-Bihind ViewModel (MVVM) ( ), . , "" ... !!!

画像

. , " " , , "" (. №3 AdvancedEditor).

private void Button_Click(object sender, RoutedEventArgs e)
{
CatalogService.AddXap("FormView.xap");
CatalogService.AddXap("AdvancedEditor.xap");
(sender as Button).IsEnabled = false;
}


, , ( ) , INotifyPropertyChanged.

: Memento .

, , CheckBox . , ( ) .

画像

- . ! ?! ! 画像

Visual Studio 2010

Source: https://habr.com/ru/post/J107919/


All Articles