私は現在、新しいプロジェクトで不要な作業を避けるために、3 層ソリューションの適切なプロジェクト構造を見つけることに取り組んでいます。
プロジェクトは、コア製品で構成されます。
- EF コードの最初のモデルを保持するモデル プロジェクト
- サーバー上にビジネスロジックと通信ロジックを持つプロジェクト
- クライアント上のリポジトリ プロジェクト
- ビューとビュー モデルを含む Silverlight プロジェクト (ここでは caliburn.micro を使用します)
問題は、顧客が上記のすべてのプロジェクトの変更につながる可能性のある特別な要件を持つ可能性があることです。そこで、基本構造をそのまま使用して、同じ構造を顧客に作成できると考えました。変更がない場合は、基本クラスを拡張して何も追加しない空のクラスしかありません。
これにより、次の問題が発生します。
- 1 つのプロジェクト (既に完全に機能している) に基底クラスを持ち、モデル クラスを新しいフィールドで拡張する可能性のある別のプロジェクトを持つことは、Entity Framework (コードが最初) の問題ですか?
- ユーザー コントロールを変更するのは XAML の問題ですか? たとえば、コアに 5 つのテキスト ボックスで構成されるユーザー コントロールがあり、2 番目のボックスをラジオ ボタンに変更したいが、それ以外は何もしないとします。
顧客固有の変更を処理するためのより良い方法があれば、プロジェクト構造の変更も受け入れます。
編集:問題を解決するには、おそらく次のアプローチを使用します。
エンティティ フレームワーク:
コードを最初に使用すると、あるモデル プロジェクトを別のプロジェクトに拡張することが可能になるようです。これは、次のように書くことができることを意味します。
public class CoreAddress{
[Key]
public int AdrId{get; set;}
public string Street {get;set;}
}
public class CustomerAddress : CoreAddress{
public string StreetNumber {get; set;}
}
その作業を行うために必要なのは、DbContext 内の行だけです。
(this as IObjectContextAdapter).ObjectContext.MetadataWorkspace.LoadFromAssembly(typeof(<entity from other assembly>).Assembly);
XAML
XAML で同様の動作を得るには、Caliburn.Micro (MEF と組み合わせて) を使用する必要がありました。これはここで非常に役立ちます。
MEF を使用して動的にフェッチされる ContentControl 要素を含む UserControls を作成します。つまり、すべてのビューと ViewModel を含むコア プロジェクトが再びできたことになります。顧客のためにどこかで特別なコントロールを交換する必要がある場合は、コントロールを ContentControl に変更し、そのためのコア ビューと ViewModel を作成します (これは、変更要求の前と同じです)。ContentControl のこの ViewModel には、エクスポート インターフェイスと ExportMetadata で注釈が付けられ、優先度 1 が設定されます。次に、コア コントロールの代わりに他のコントロールを持つ別の UserControl を使用して別のプロジェクトを作成し、同じインターフェイスを持つエクスポートとして再度注釈を付けますが、優先度を高く設定すると、顧客固有のコントロールが読み込まれます。
これの短い例:
メイン ユーザー コントロールとビュー モデル:
<UserControl x:Class="SilverlightApplication5.TestView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400">
<Grid x:Name="LayoutRoot" Background="White">
<StackPanel>
<ContentControl x:Name="Item"/>
<TextBox x:Name="TextItem" Text="asdf"/>
</StackPanel>
</Grid>
</UserControl>
public class TestViewModel : Screen
{
private object viewModel;
private Lazy<IMyViewModel, IPluginMetadata>[] _orderEditorFactory;
[ImportMany(typeof(IMyViewModel), AllowRecomposition = true)]
public Lazy<IMyViewModel, IPluginMetadata>[] OrderEditorFactory
{
get { return _orderEditorFactory; }
set
{
_orderEditorFactory = value;
Item = _orderEditorFactory.OrderByDescending(lazy => lazy.Metadata.Priority).First().Value;
}
}
private object _item;
public object Item
{
get { return _item; }
set
{
_item = value;
NotifyOfPropertyChange(() => Item);
}
}
}
コア コントロール:
<UserControl x:Class="SilverlightClassLibrary2.MainControlView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400">
<StackPanel>
<TextBlock x:Name="Test" Text="Text from Core control"/>
</StackPanel>
</UserControl>
[Export(typeof (IMyViewModel))]
[ExportMetadata("Name", "Pluginc")]
[ExportMetadata("Priority", 30)]
public class MainControlViewModel : Screen, IHarnessAware, IMyViewModel
{
}
顧客固有の制御:
<UserControl x:Class="SilverlightClassLibrary1.CustomView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400">
<Grid x:Name="LayoutRoot" Background="White">
<RadioButton x:Name="Test" Content="{Binding Path=Test}"/>
</Grid>
</UserControl>
[Export(typeof(IMyViewModel))]
[ExportMetadata("Name", "Plugind")]
[ExportMetadata("Priority", 2)]
public class CustomViewModel : MainControlViewModel, IHarnessAware, IMyViewModel
{
}
エクスポート インターフェイス:
public interface IMyViewModel
{
}
ExportMetadata インターフェイス:
public interface
IPluginMetadata
{
string Name { get; }
[DefaultValue(0)]
int Priority { get; }
}
私はこれを使用して質問に答えました。これは、同様の問題をすでに解決している可能性のある他の人々からの意見にまだ興味があるからです。