Click here to Skip to main content
Click here to Skip to main content

A Pluggable Architecture for Building Silverlight Applications with MVVM

By , 6 Jul 2011
 

Contents

Introduction

This article is a follow-up of my previous article series on how to develop a Silverlight application using MEF, MVVM Light Toolkit, and WCF RIA Services. The architecture from that article series is suitable for building small and medium-sized LOB Silverlight applications, but with large applications of possibly hundreds of different screens, it is critical to adopt a different architecture so that we can minimize the initial download time, and fetch additional XAP files based on different user roles.

There are already several great articles on developing modular Silverlight applications, like Building Modular Silverlight Applications. What we are going to cover in this article is a pluggable architecture for MVVM applications based on MEF's DeploymentCatalog class, and we will build on the same IssueVision sample application from my previous article series.

Requirements

In order to build the sample application, you need:

  • Microsoft Visual Studio 2010 SP1
  • Silverlight 4 Toolkit April 2010 (included in the sample solution)
  • MVVM Light Toolkit V3 SP1 (included in the sample solution)

Database Setup

To install the sample database, please run SqlServer_IssueVision_Schema.sql and SqlServer_IssueVision_InitialDataLoad.sql included in the solution. SqlServer_IssueVision_Schema.sql creates the database schema and database user IVUser; SqlServer_IssueVision_InitialDataLoad.sql loads all the data needed to run this application, including the initial application user ID user1 and Admin user ID admin1, with passwords all set as P@ssword1234.

Also, make sure to configure connectionStrings of the Web.config file in the project IssueVision.Web to point to your own database. Currently, it is set as follows:

<connectionStrings>
<add name="IssueVisionEntities" connectionString="metadata=res://
*/IssueVision.csdl|res://*/IssueVision.ssdl|res://
*/IssueVision.msl;provider=System.Data.SqlClient;provider 
connection string=&quot;Data Source=localhost;Initial Catalog=IssueVision;
User ID=IVUser;Password=uLwJ1cUj4asWaHwV11hW;MultipleActiveResultSets=True&quot;" 
providerName="System.Data.EntityClient" />
</connectionStrings>

Architecture

From the system diagram above, we can see that the sample application is divided into three XAP files:

  • IssueVision.Main.xap
  • IssueVision.User.xap
  • IssueVision.Admin.xap

The main XAP is called IssueVision.Main.xap, and it is built from the projects IssueVision.Main and IssueVision.Main.Model. When a user first accesses the sample application, IssueVision.Main.xap is downloaded, and it only contains the LoginForm, Home, and MainPage Views. After a user successfully logs in as a normal user, the IssueVision.User.xap file will be downloaded. This file is built from three projects: IssueVision.User, IssueVision.User.Model, and IssueVision.User.ViewModel. It hosts all the screens a user can access as plug-in views, except the UserMaintenance and AuditIssue screens, which are from IssueVision.Admin.xap and are only available when someone logs in as an Admin user.

When a user logs off, both IssueVision.User.xap and IssueVision.Admin.xap are removed, with only IssueVision.Main.xap available for someone to log in later.

MVVMPlugin Library

The MVVMPlugin project defines classes that make this plug-in architecture possible; it mainly provides two types of services:

  1. Add or remove XAP files during runtime;
  2. Find and release plug-in components for either View, ViewModel, or Model.

Now, let us briefly go over the major classes within this library:

1. ExportPluginAttribute Class

/// <summary>
/// Export attribute for MVVM plugin
/// </summary>
[MetadataAttribute]
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public class ExportPluginAttribute : ExportAttribute
{
    public string Name { get; private set; }
    public PluginType Type { get; private set; }

    public ExportPluginAttribute(string name, PluginType pluginType)
        : base("MVVMPlugin")
    {
        Name = name;
        Type = pluginType;
    }
}

The ExportPluginAttribute class derives from ExportAttribute, and we can decorate it against either a UserControl or Page class, which turns it into a plug-in view available through the class PluginCatalogService.

2. PluginCatalogService Class

PluginCatalogService is the main class within the MVVMPlugin library. In order to use this class, we need to call Initialize() when the application starts:

private void Application_Startup(object sender, StartupEventArgs e)
{
    MVVMPlugin.PluginCatalogService.Initialize();
    RootVisual = new MainPage();
}

and Initialize() is defined as follows:

#region "Constructors and Initialize()"
/// <summary>
/// Default constructor
/// </summary>
private PluginCatalogService()
{
    _catalogs = new Dictionary<string, DeploymentCatalog>();
    _contextCollection = new Collection<ExportLifetimeContext<object>>();
    CompositionInitializer.SatisfyImports(this);
}

/// <summary>
/// Static constructor
/// </summary>
static PluginCatalogService()
{
    _aggregateCatalog = new AggregateCatalog();
    _aggregateCatalog.Catalogs.Add(new DeploymentCatalog());
    Container = new CompositionContainer(_aggregateCatalog);
    CompositionHost.Initialize(_container);

    Instance = new PluginCatalogService();
}

/// <summary>
/// Initialize Method
/// </summary>
public static void Initialize()
{ 
}
#endregion "Constructors and Initialize()"

When Initialize() is first called, it triggers the static constructor to initialize all the static data members inside this class, including an AggregateCatalog object, a CompositionContainer object, and the singleton instance of the class PluginCatalogService itself. The static constructor then calls the private default constructor to continue initializing any non-static data members, and lastly calls CompositionInitializer.SatisfyImports(this) which satisfies imports to the following public properties:

[ImportMany("MVVMPlugin", AllowRecomposition = true)]
public IEnumerable<Lazy<object, IPluginMetadata>> PluginsLazy { get; set; }

[ImportMany("MVVMPlugin", AllowRecomposition = true)]
public IEnumerable<ExportFactory<object, IPluginMetadata>> PluginsFactories { get; set; }

After Initialize() is called, users can then add and remove XAP files with the functions AddXap() and RemoveXap() defined like this:

#region "Public Methods for Add & Remove Xap"

/// <summary>
/// Method to add XAP
/// </summary>
/// <param name="uri"></param>
/// <param name="completedAction"></param>
public void AddXap(string uri, Action<AsyncCompletedEventArgs> completedAction = null)
{
    DeploymentCatalog catalog;
    if (!_catalogs.TryGetValue(uri, out catalog))
    {
        catalog = new DeploymentCatalog(uri);
        catalog.DownloadCompleted += (s, e) =>
        {
            if (e.Error == null)
            {
                _catalogs.Add(uri, catalog);
                _aggregateCatalog.Catalogs.Add(catalog);
            }
            else
            {
                throw new Exception(e.Error.Message, e.Error);
            }
        };

        if (completedAction != null)
            catalog.DownloadCompleted += (s, e) => completedAction(e);

        catalog.DownloadAsync();
    }
    else
    {
        if (completedAction != null)
        {
            AsyncCompletedEventArgs e = 
                 new AsyncCompletedEventArgs(null, false, null);
            completedAction(e);
        }
    }
}

/// <summary>
/// Method to remove XAP
/// </summary>
/// <param name="uri"></param>
public void RemoveXap(string uri)
{
    DeploymentCatalog catalog;
    if (_catalogs.TryGetValue(uri, out catalog))
    {
        _aggregateCatalog.Catalogs.Remove(catalog);
        _catalogs.Remove(uri);
    }
}

#endregion "Public Methods for Add & Remove Xap"

Besides adding or removing XAP files, the class PluginCatalogService also defines five functions to find and release plug-ins. They are: FindPlugin(), TryFindPlugin(), ReleasePlugin(), FindSharedPlugin(), and TryFindSharedPlugin(). The following code snippet shows how FindPlugin() and ReleasePlugin() are actually implemented:

/// <summary>
/// Method to get an instance of non-shared plugin
/// </summary>
/// <param name="pluginName"></param>
/// <param name="pluginType"></param>
/// <returns></returns>
public object FindPlugin(string pluginName, PluginType? pluginType = null)
{
    ExportLifetimeContext<object> context;
    if (pluginType == null)
    {
        context = PluginsFactories.Single(
        n => (n.Metadata.Name == pluginName)).CreateExport();
    }
    else
    {
        context = PluginsFactories.Single(
          n => (n.Metadata.Name == pluginName && 
                   n.Metadata.Type == pluginType)).CreateExport();
    }
    _contextCollection.Add(context);
    return context.Value;
}

/// <summary>
/// Method to release non-shared plugin
/// </summary>
/// <param name="plugin"></param>
/// <returns></returns>
public bool ReleasePlugin(object plugin)
{
    ExportLifetimeContext<object> context = 
       _contextCollection.FirstOrDefault(n => n.Value.Equals(plugin));
    if (context == null) return false;
    _contextCollection.Remove(context);
    context.Dispose();
    return true;
}

Model Class

Now that we know how the MVVMPlugin library works, it is time to explore how this library can help us build MVVM composable parts within a Silverlight application. First, let us check how Model classes are defined.

[Export(typeof(IIssueVisionModel))]
[PartCreationPolicy(CreationPolicy.Shared)]
public class IssueVisionModel : IIssueVisionModel
{
    ......
}

Model classes are marked with MEF's Export attribute, and the PartCreationPolicy is set as Shared. They are all exported as interfaces and imported by ViewModel classes. We cannot use the ImportingConstructor attribute to import a Model interface any more because a ViewModel class can reside within a composable part and every import has to be marked with AllowDefault=true and AllowRecomposition=true. This is necessary because any import without setting AllowRecomposition=true will cause MEF to throw an exception when removing that part during runtime. So, in order to get a reference to the shared Model interface, we need to use the Container property of the PluginCatalogService class and call GetExportedValue<T>().

#region "Constructor"
public AllIssuesViewModel()
{
    _issueVisionModel = 
      PluginCatalogService.Container.GetExportedValue<IIssueVisionModel>();

    // Set up event handling
    _issueVisionModel.SaveChangesComplete += _issueVisionModel_SaveChangesComplete;
    _issueVisionModel.GetAllIssuesComplete += _issueVisionModel_GetAllIssuesComplete;
    _issueVisionModel.PropertyChanged += _issueVisionModel_PropertyChanged;

    // load all issues
    _issueVisionModel.GetAllIssuesAsync();
}
#endregion "Constructor"

In addition to importing Model classes inside the constructor of ViewModel classes, we can also define a public property and use the Import attribute to get a reference to the Model class. The following example is from class MainPageViewModel.

private IIssueVisionModel _issueVisionModel;

[Import(AllowDefault=true, AllowRecomposition=true)]
public IIssueVisionModel IssueVisionModel
{
  get { return _issueVisionModel; }
  set
  {
    if (!ReferenceEquals(_issueVisionModel, value))
    {
      if (_issueVisionModel != null)
      {
        _issueVisionModel.PropertyChanged -= IssueVisionModel_PropertyChanged;
        if (value == null)
        {
          ICleanup cleanup = _issueVisionModel as ICleanup;
          if (cleanup != null) cleanup.Cleanup();
        }
      }
      _issueVisionModel = value;
      if (_issueVisionModel != null)
      {
        _issueVisionModel.PropertyChanged += IssueVisionModel_PropertyChanged;
      }
    }
  }
}

From the code snippet above, we can see that before setting the property back to null, a call to the Cleanup() function of the Model class is performed. This Cleanup() function makes sure that any event handler is unregistered so that the Model object can be disposed without causing any memory leaks. The Cleanup() function below is from the Model class IssueVisionModel:

#region "ICleanup Interface implementation"
public void Cleanup()
{
  if (_ctx != null)
  {
    // unregister event handler
    _ctx.PropertyChanged -= _ctx_PropertyChanged;
    _ctx = null;
  }
}
#endregion "ICleanup Interface implementation"

This concludes our discussion about the Model classes; we will check how ViewModel classes are defined inside a composable part next.

ViewModel Class

To define a ViewModel class within a composable part, we need to mark the class with the ExportPlugin attribute and specify its name and type.

[ExportPlugin(ViewModelTypes.AllIssuesViewModel, PluginType.ViewModel)]
[PartCreationPolicy(CreationPolicy.NonShared)]
public class AllIssuesViewModel : ViewModelBase
{
    ......
}

Next, we set the DataContext of any plug-in view with a function call of FindPlugin(), as follows:

#region "Constructor"
public AllIssues()
{
    InitializeComponent();
    // add the IssueEditor
    issueEditorContentControl.Content = new IssueEditor();
    // initialize the UserControl Width & Height
    Content_Resized(this, null);

    // register any AppMessages here

    if (!ViewModelBase.IsInDesignModeStatic)
    {
      // set DataContext
      DataContext = PluginCatalogService.Instance.FindPlugin(
        ViewModelTypes.AllIssuesViewModel, PluginType.ViewModel);
    }
}
#endregion "Constructor"

We need to register any AppMessages before setting the DataContext. This will ensure that the AppMessages are ready, if we need to send messages inside the constructor of the ViewModel class.

Finally, we call ReleasePlugin() within the Cleanup() function when the ViewModel object is no longer needed. This is important because, without calling ReleasePlugin(), MEF will continue to keep this ViewModel object alive, thus causing memory leaks.

#region "ICleanup interface implementation"

public void Cleanup()
{
    // call Cleanup on its ViewModel
    ((ICleanup)this.DataContext).Cleanup();
    // call Cleanup on IssueEditor
    var issueEditor = issueEditorContentControl.Content as ICleanup;
    if (issueEditor != null)
        issueEditor.Cleanup();
    issueEditorContentControl.Content = null;
    // cleanup itself
    Messenger.Default.Unregister(this);
    // call ReleasePlugin on its ViewModel
    PluginCatalogService.Instance.ReleasePlugin(DataContext);
    DataContext = null;
}

#endregion "ICleanup interface implementation"

Plug-in View Class

Likewise, we take similar steps to create a plug-in view class. First, we mark a custom UserControl with the ExportPlugin attribute and set its type as PluginType.View.

[ExportPlugin(ViewTypes.AllIssuesView, PluginType.View)]
public partial class AllIssues : UserControl, ICleanup
{
    ......
}

Then, we use the functions FindPlugin() and ReleasePlugin() to add or remove references to the plug-in view object, as follows:

#region "ChangeScreenNoAnimationMessage"

private void OnChangeScreenNoAnimationMessage(string changeScreen)
{
    object currentScreen;
    // call Cleanup() on the current screen before switching
    var cleanUp = this.mainPageContent.Content as ICleanup;
    if (cleanUp != null)
        cleanUp.Cleanup();

    // reset noErrorMessage
    _noErrorMessage = true;

    switch (changeScreen)
    {
        case ViewTypes.HomeView:
            currentScreen = new Home();
            break;
        case ViewTypes.MyProfileView:
            currentScreen = 
              _catalogService.FindPlugin(ViewTypes.MyProfileView);
            break;
        default:
            throw new NotImplementedException();
    }
    // change main page content without animation
    currentScreen = 
      mainPageContent.ChangeMainPageContent(currentScreen, false);
    // call ReleasePlugin on replaced screen
    _catalogService.ReleasePlugin(currentScreen);
}

#endregion "ChangeScreenNoAnimationMessage"

This concludes our discussion about the plug-in view class. One additional step before building the solution is to set the "Copy Local" option to False for some of the references in the projects IssueVision.User and IssueVision.Admin. This is to make sure that any assembly already included in IssueVision.Main.xap does not get copied again into either IssueVision.User.xap or IssueVision.Admin.xap so that we can minimize the download size.

Remarks

First, let me reiterate that every import within a composable part, whether it is inside a plugin view, ViewModel, or Model, has to be marked with AllowDefault=true and AllowRecomposition=true. Without setting the import as recomposable, MEF will throw an exception when removing that part during runtime.

Lastly, the sizes of the three XAP files are: IssueVision.Main.xap is 1180 KB, while IssueVision.User.xap is 35 KB, and IssueVision.Admin.xap is 19 KB. This seems to suggest that this new architecture is only a good choice for large LOB Silverlight applications. For small and medium-sized applications like this sample is, it really does not make much of a difference for the initial download.

I hope you find this article useful, and please rate and/or leave feedback below. Thank you!

History

  • August 2010 - Initial release
  • March 2011 - Updated and built with Visual Studio 2010 SP1
  • July 2011 - Update to fix multiple bugs

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Weidong Shen
Software Developer (Senior)
United States United States
Member
Weidong has been an information system professional since 1990. He has a Master's degree in Computer Science, and is currently a MCSD .NET

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
Questionhow to access single host application in 4 different silverlight Application?membermdrizwan_126 Sep '12 - 0:44 
Hello,
 
I have 4 different Silverlight Modules developed on 4 different PCs and i have Host application and Domain Logic, DataBase on 5th PC. I Should be able to Access domain Logic,DataBase,etc from 5th PC into 4 different Silverlight Modules on other PCs.
 
Any help Appreciated !!!
 
Regards
QuestionHow to add Excel import & export functionalitymemberibrahim.steed19 Aug '12 - 22:46 
Hi Weidong,
 
As you know, Excel import & export is an important and often used functionality. So how to add Excel import&export code based on your Application?
 
Is it better to add Excel import&export code to MODEL classes like Project Model class?
 
Thanks!
AnswerRe: How to add Excel import & export functionalitymemberWeidong Shen20 Aug '12 - 15:53 
Why you cannot make those calls directly from your ViewModel classes, just curious?
GeneralRe: How to add Excel import & export functionalitymemberibrahim.steed20 Aug '12 - 22:56 
Yes, as you said, I can make these calls directly from ViewModel. In response to these calls, the Import&Export is supposed to be implemented in MODEL class. Am I right?
GeneralRe: How to add Excel import & export functionalitymemberWeidong Shen21 Aug '12 - 15:07 
I think the Model class is just another layer of encapsulation. If you have just a few Import&Export calls, you can do that directly from your ViewModel class. But, if you have lots of special functions with Import&Export calls, it may be better to create its own Model class.
 
It all depends on which way makes your ViewModel class simpler and easier to understand.
 
Thanks,
GeneralRe: How to add Excel import & export functionalitymemberibrahim.steed26 Aug '12 - 15:29 
the function with Import is to read content in the specified EXCEL template, like CELL[x,y] corresponding to specific property in some CLASS, then submit the new added objects into database. And Export vise versa.
Generalthere is no chance to call the CLEANUP method of the MODEL classes [modified]memberibrahim.steed23 Jul '12 - 15:16 
Hi Weidong,
 
As you mentioned in this article, there are 2 alternative ways to import MODEL classes into VIEWMODEL:
1 - importing Model classes inside the constructor of ViewModel classes.
2 - defining a public property and use the Import attribute to get a reference to the Model class.
 
My understanding is your application source code uses the first way.
 
My doubt is I can not find the place in VIEWMODEL where the CLEANUP method of the MODEL classes for the first way is called, although MODEL classes implemented CLEANUP interface already.
 
Thanks !

modified 23 Jul '12 - 21:32.

GeneralRe: there is no chance to call the CLEANUP method of the MODEL classesmemberWeidong Shen23 Jul '12 - 16:59 
The MODEL class is shared, and therefore there is only one copy maintained by MEF, and it is disposed only when the application is shutdown.
 
Thanks,
GeneralRe: there is no chance to call the CLEANUP method of the MODEL classesmemberibrahim.steed23 Jul '12 - 18:04 
Thanks for you instant reply !
 
So the CLEANUP method of the MODEL classes will be called by MvvmLight or not when application is shutdown ?
 
Or as you said, MODEL object will be just disposed when application is shutdown ?
GeneralRe: there is no chance to call the CLEANUP method of the MODEL classesmemberWeidong Shen24 Jul '12 - 16:54 
You can actually put a breakpoint there and check when it gets called. Thanks!
Generalwhat's the difference between GetExportedValue and FindSharedPlugin [modified]memberibrahim.steed26 Jun '12 - 17:49 
Hi Weidong,
 
your serial articles about Silverlight Applicaitons are really helpful to me, thanks for your excellent work!
 
I have one question : what's the difference between the two ways to get exported part as following:
 
PluginCatalogService.Container.GetExportedValue<IIssueVisionModel>();
 
PluginCatalogService.Instance.FindSharedPlugin(ViewModelTypes.AllIssuesViewModel, PluginType.ViewModel);
 
as I see it, the purpose of the two ways is same, but FindSharedPlugin is more specific because it has one more parameter to constrain the specific class. Am I right?
 
Thanks!

modified 27 Jun '12 - 0:02.

GeneralRe: what's the difference between GetExportedValue and FindSharedPluginmemberWeidong Shen27 Jun '12 - 14:39 
The call FindSharedPlugin() is used to find a shared object of any class decorated with attribute [ExportPlugin]. Since the class IssueVisionModel is only decorated with the standard [Export] attribute, I need to call GetExportedValue() to access the shared object.
 
Thanks,
GeneralRe: what's the difference between GetExportedValue and FindSharedPlugin [modified]memberibrahim.steed27 Jun '12 - 16:52 
Thanks for your instant reply !
 
So GetExportedValue can substitute FindSharedPlugin if those class are not decorated with self-defined attribute [ExportPlugin] ? And defining a property in a class with attribute [Import] (and then access it) can also achieve the same purpose as GetExportedValue ?
 
by the way, is there any necessary to replace CollectionViewSource with DomainCollectionView to enhance the data access performance because it's better to do paging on server side for large amount data ?
 
Thanks,

modified 28 Jun '12 - 3:24.

GeneralRe: what's the difference between GetExportedValue and FindSharedPluginmemberWeidong Shen28 Jun '12 - 15:38 
The main purpose of this plugin architecture is for non-shared plugins so that you can request one and then later release it safely. For shared plugins, either approach is fine, and essentially the same.
 
I never used DomainCollectionView(actually doing mostly WPF development these days), and thanks for letting me know and I will take a further look into this.
 
Thanks,
GeneralRe: what's the difference between GetExportedValue and FindSharedPluginmemberibrahim.steed30 Jun '12 - 3:16 
Please let me know if you implement with DomainCollectionView instead, although I'll keep following your post Wink | ;)
 

Thanks!
GeneralRe: what's the difference between GetExportedValue and FindSharedPluginmemberibrahim.steed5 Jul '12 - 15:50 
Hi Weidong, in the course of study of your application. I have 2 questions as follows. Would you please take time to reply?
 
1- How is the IssueHistory data produced? I found there are records in the IssueHistory table of databaes, but I was not able to find the source code concerned in the solution to produce the data.
 
2- What's the purpose of the AuditIssue? It seems that the AuditIssueViewModel misses some code which is used to load data from IssueHistory. I don't know if I understand correctly.
 

Thanks,
GeneralRe: what's the difference between GetExportedValue and FindSharedPluginmemberWeidong Shen6 Jul '12 - 17:13 
The records inside table IssueHistory are created by three database triggers found in sql script SqlServer_IssueVision_Schema.sql. Whenever any add/delete/update happens with table Issue, a new record is created to record that change. Therefore, the IssueHistory table serves the purpose of keeping the audit trace.
 
The AuditIssue screen queries table IssueHistory to display the audit trace for any Issue of your choice.
 
Thanks,
GeneralRe: what's the difference between GetExportedValue and FindSharedPluginmemberibrahim.steed19 Jul '12 - 18:17 
maybe this post helps.
 
http://blogs.ugidotnet.org/corrado/archive/2011/01/28/paging-and-sorting-using-wcf-ria-services-sp1.aspx[^]
GeneralRe: what's the difference between GetExportedValue and FindSharedPluginmemberWeidong Shen23 Jul '12 - 16:56 
Thanks for the information. I also did an implementation of filtering, paging and sorting by using client-side LINQ queries. Here is the link:
 
http://selftrackingentity.codeplex.com/[^]
QuestionRe: A Pluggable Architecture for Building SL Apps with MVVMmemberJoeManJoe14 Dec '11 - 6:49 
Thanks,
How do you release a shared viewmodel when using the MVVM plugin? I set my view's datacontext like this:
 
if (!GalaSoft.MvvmLight.ViewModelBase.IsInDesignModeStatic)
           {
               // set DataContext
               this.DataContext = PluginCatalogService.Instance.FindSharedPlugin(ViewModelTypes.EmpContactViewModel, PluginType.ViewModel);
               _viewModel = (EmpContactViewModel)this.DataContext;
           }
 
Calling the Releaseplugin on the viewmodel using the following line does not do anything when the viewmodel is shared - even if no other view is consuming the viewmodel:
 
PluginCatalogService.Instance.ReleasePlugin(this.DataContext);
 
I took a look at the PluginCatalogServices.cs and realized that the _contextCollection.Count will always be 0, so nothing is removed or disposed of.
 
In cases where I have one view to one viewmodel, everything works well, as the ReleasePlugin method takes care of the cleanup.
 
Cheers!
J
AnswerRe: A Pluggable Architecture for Building SL Apps with MVVMmemberWeidong Shen14 Dec '11 - 10:18 
ReleasePlugin() is only intended to release non-shared plugins. I really do not know how to release a shared plugin. I think this should be a MEF question.
 
Please let me know if you find out the answer. Thanks!
QuestionAwesome...do you have anything like this for WPFmemberPaul Reed1 Sep '11 - 3:35 
This is great stuff. Do you have anything like this for WPF?
AnswerRe: Awesome...do you have anything like this for WPFmemberWeidong Shen1 Sep '11 - 13:27 
WCF RIA Services currently does not support WPF, only for Silverlight. But you can still find some samples on how to consume WCF RIA Services from a WPF client at here[^].
 
Also, I am trying to bring client-side change tracking to both WPF and Silverlight applications by using self-tracking entity classes, and you can find it here[^].
 
Thanks!
Questioncan u tell me how mudular xap file are generatingmemberwaqas200728 Jul '11 - 12:17 
hi i understand in IssueVision.Common you are defining name of   all viewmodels and views as types for MEF to load them at runtime i understand that basic intent of plug and play is to seperate viewmodel ,views layers so that MEF can load each them at run but i am confused if i have to develop a seperate module to generate MOduleabc.xap then i will do the same add view and viewmodel types in common and will generate seperate library project for views and models but how will silverlight will generate and load seperate single xap file of that added projects how it will know that these 2 or 3   projects belongs to one xap file   can you plz explain it
 

thanks
AnswerRe: can u tell me how mudular xap file are generatingmemberWeidong Shen29 Jul '11 - 16:41 
Project "IssueVision.Main" creates one XAP file named "IssueVision.Main.xap" that only includes the MainPage and LoginForm, and will be downloaded before someone logs in.
 
Project "IssueVision.User" creates another XAP file named "IssueVision.User.xap" that includes all the Views and ViewModels for a non-admin user, and project "IssueVision.Admin.xap" creates a third XAP file named "IssueVision.Admin.xap" that includes all the Views and ViewModels only available to an admin user.
 
When a user successfully logs in, the "IssueVision.User.xap" file will be downloaded from server with the following lines:
 
// load IssueVision.User.xap
_catalogService.AddXap("IssueVision.User.xap", arg => _issueVisionUserCompleted(arg));
 
And, if the user is an admin user, the third XAP "IssueVision.Admin.xap" will also be downloaded and made available:
 
// load IssueVision.Admin.xap next
_catalogService.AddXap("IssueVision.Admin.xap", arg => _issueVisionAdminCompleted(arg));
 
You should be able to see all the above logic in class MainPageViewModel.cs
 
Thanks,
Questionwhat user name/password gets you into the application?memberGreg Hazzard30 Mar '11 - 22:53 
??
AnswerRe: what user name/password gets you into the application?memberWeidong Shen31 Mar '11 - 3:39 
The initial application user ID is user1 and Admin user ID is admin1, with passwords all set as P@ssword1234.
 
They are documented on the first article series and not repeated here. Sorry.
QuestionHow about MEFmvpAbhishek Sur21 Mar '11 - 8:48 
I wrote one article on the same topic before
 
Pluggable Styles and Resources in WPF with Language Converter Tool[^]
 
I was still thinking to transform it to use MEF. Just saw your article.
Got my 5 though. Wink | ;)
Abhishek Sur
Don't forget to click "Good Answer" if you like this Solution.
Visit My Website-->


www.abhisheksur.com

AnswerRe: How about MEFmemberWeidong Shen21 Mar '11 - 8:59 
Thank you so much! I definitely will try your sample and see whether I can add pluggable Styles and Resources into my sample. Laugh | :laugh:
GeneralQuery regarding Navigationmemberindraloktech22 Jan '11 - 21:00 
Hi,
 
I have a Patient List and a Patient Edit Page. What is the best way to implement this in this architecture. The requirement is also to refresh the list once the patient is updated. Generally, what is the best approach to implement navigation in such scenarios.
 
Please help.
 
Mrunal Buch
GeneralRe: Query regarding NavigationmemberWeidong Shen23 Jan '11 - 8:04 
It is difficult to say what is the best approach for your application because it all depends.
 
If you are only working on a simple application with one or two screens, you may not need MVVM at all. On the other hand, if you works on a complex system, you certainly are not allowed to post all your requirements on line.
 
Thanks,
GeneralThis article is a fraud (please read on)...memberremesqny3 Jan '11 - 10:41 
I am going to go out on a limb here, so if I insult anyone because I am WRONG, then I apologize in advance. However, if I am anywhere near correct I am hopeful that the CodeProject.com God's figure out a way to correct the situation (if they deem it necessary to do so).
 
First, I invested A LOT of time going over the 4 articles associated with this Issue Vision, supposed issue tracker "example". I am no sleuth, but I was nonetheless fooled by these articles (as I will point out). I am also no expert, and so I rely on many articles on codeproject.com to learn. When I saw this "example" I was excited to have a framework to build upon for my own personal projects. So whatever you might say in response, yes, it's my own fault for falling for this fraud.
 
Second, this article is exactly that, a fraud. I was having trouble creating a new view in this project. No matter what I did (even what Mr. Shen suggested in his response - before he suggested it), I kept getting an error. I scanned around the messages to each of the 4 articles to see if a similar question had been asked. It had not been asked (surprisingly, leading me to believe I was truly out of my realm for what seemed like a basic task). But, and this was my first indication of the fraud, I noticed that Mr. Shen's answers to many specific "how to" questions were vague and common sense responses without any indiciation of what someone should do for their particular request. So, I posted the question of how to add views. Mr. Shen's response was so vague as to cause me to spend 1/2 hour deciding whether or not I should continue investing time with the "example". I had already invested over 20 hours reading, learning and trying to build off the example.
 
Initially, I just thought that Mr. Shen was a busy man and probably took the approach of "teacher" by trying to point me in the right direction without giving me the answer expecting me to learn it (the "teach a man to fish" scenario). I could have respected that. But then I found this: MS Line of Business Sample.
 
That, for those of you who are unaware of the fraud, is Microsoft's very own Line of Business Sample for Silverlight 4. It is exactly Issue Vision as Mr. Shen presents it. If you scroll down to the sample's "Home" page rendition, you will not it has the same language as in Issue Vision. Note that in article 1 on this, Mr. Shen states:
 
"This three part article series is my effort at creating such a sample. The choice of an issue tracking application comes from David Poll's PDC09 talk, and the design architecture is from Shawn Wildermuth's blog posts."
 
I did not find anything about this architecture from Mr. Wildermuth's posts (other than just his posts about an architecture such as that used in Issue Vision by Mr. Shen). However, I must admit that after that 1/2 hour of deliberating I abandoned the idea of trying to learn from Issue Vision because I could not figure out the errors I was getting when trying to add a new view.
 
So, IMHO, Mr. Shen failed to answer my question only because i suspect he does not know the answer. All he did was dress up Issue Vision from the MS example and called it his own.
 
I am not so naive as to believe this has never happened on codeproject.com or anywhere else on the web. However, given the response from Mr. Shen, and given my INADVERDENT discovery of the MS example, and given the time I invested with Mr. Shen's "example", I felt it warranted my post to warn others and hopefully to get codeproject.com to act. I have been using this site for over 7 years to help out with learning this stuff, and it's a shame.
 
Why do I care, you might ask? Because you know that Mr. Shen is pimping this article out there in the world claiming to have created something he did not. Plagarism, Mr. Shen, is not teaching.
 
I will be cross-posting this for maximum exposure. If Mr. Shen is able to delete comments, then the integrity of codeproject.com is seriously compromised.
GeneralRe: This article is a fraud (please read on)... [modified]memberZigenstein15 Jan '11 - 20:27 
I'm suprised that you took so much time to write the reponse given that you didn't take the time to check the sources properly!
 
If you read the first article[^], Weidong cites a PDC '09 talk[^] which goes through an online tutorial of exactly the application that you claim he "plagarised".
 
What Weidong has done is modify Microsoft's sample (with full credit to MS) to sit on a pluggable architecture. He hasn't claimed to make some brilliant issue tracking system, he has just used an example that would be familiar to many - makes it easier for the audience to identify the differences between the conventional approach and the one Weidong has illustrated.
 
Do you feel a bit silly?

modified on Sunday, January 16, 2011 2:39 AM

GeneralRe: This article is a fraud (please read on)...memberksafford29 Mar '11 - 8:42 
I concur Zigenstein, I saw this article when Weidong first submitted it, saw the IssueVision on MSDN. The one on MSDN was a "bare bones" Wcf RIA application with none of the MVVM, MEF and other stuff Weidong applied. I was trying to figure how to respond but your words were much more tactfull than I would have done.
 
Good counter Zigenstien. Great job Weidong, I am finally understanding a lot of what you have done and it has been a long arduous journey.
 
CyclingFoodmanPA
GeneralRe: This article is a fraud (please read on)...memberWeidong Shen29 Mar '11 - 8:52 
Thanks! Smile | :)
GeneralThanks for the bestmemberjhb113 Dec '10 - 13:40 
sometimes all it takes is one working example to get developers to overcome their knowledge gap and start using this cool technology.
you have achieved that and more.
well done and keep it up!
 
ps, when is your book coming out? Smile | :)
 
john , mcad.net
perth,
australia
GeneralRe: Thanks for the bestmemberWeidong Shen13 Dec '10 - 14:06 
Thank you! I prefer to write online and it costs you nothing. Smile | :)
QuestionEntities, Metadata and resource in a seperate assemblymemberindraloktech16 Nov '10 - 23:00 
Hi,
 

I have moved DataTypes, EDMX and Metadata in a seperate assembly from the IssueVision.Web project. What are the changes that need to be done to achieve this.
 
I am getting an error when using Resources in the metadata.
 
Can you please help?
 
Mrunal
AnswerRe: Entities, Metadata and resource in a seperate assemblymemberWeidong Shen17 Nov '10 - 4:03 
The sample already has DataTypes, EDMX and Metadata in a separate assembly (IssueVision.Data.Web), not in project IssueVision.Web.
 
If you get an error when using Resources in the metadata, one thing to check is whether the namespaces are correct or not.
 
Thanks,
GeneralRe: Entities, Metadata and resource in a seperate assemblymemberindraloktech1 Dec '10 - 18:20 
Hi,
 
You are right, but IssueVision.Data.Web also contains Service. I want all the entities seperate from the service assembly as well. The idea here is to reuse our entities/metadata/edmx between various projects.
 
Mrunal
GeneralRe: Entities, Metadata and resource in a seperate assemblymemberWeidong Shen3 Dec '10 - 4:39 
Thanks, that is a good idea. Would you be able to separate the service assembly from entities/metadata/edmx?
GeneralMy vote of 5memberksafford20 Oct '10 - 15:06 
Hey Weidong,
 
I have a question? I have created a project based on your structure, but things do not seem to be working right. When you create the project initially, do you create a Silverlight Project, or a Silverlight Business Project? I am wondering if you could do a tutorial on building the structure for the solution, similar to this: http://www.devtoolshed.com/tutorial-configuring-silverlight-4-entity-framework-and-wcf-ria-services-separate-component-assembli. I was using this structure before I found your IssueVision, but you utilize all the good stuff, MEF, MVVM, etc. I know I am close, however, for some reason when I look at my forms in the designer, for example the LoginForm, I am not seeing what I see on yours when it is open in the designer and my Styles are not being found even though I am merging dictionaries in the App.xaml file. Awesome job, now us mere mortals have to figure this out, but you put down an awesome structure to build on.
GeneralRe: My vote of 5memberWeidong Shen22 Oct '10 - 8:13 
I just created a Silverlight Application project, not the Silverlight Business project, and then added all other Silverlight Class Library projects and the RIA Service link.
 
On the server side, the project "IssueVision.Data.Web" is a Class Library project (not the Silverlight Class Library project).
 
Getting the styles all working is a little bit of pain.
 
Have fun!
GeneralRelease does not workmemberpotatoking.net20 Oct '10 - 9:08 
Hi
 
I just found out, that even when I release a plugin, the object instance is still alive (forever). How can I achieve that the instance gets collected by the GC one time?
GeneralRe: Release does not work [modified]memberWeidong Shen20 Oct '10 - 14:18 
Could you please be a little more specific on where this sample does not release an instance properly so that I can verify and have it fixed?
 
I am using the ReleasePlugin() function to release a plugin so that it would not be alive forever.
 
Thanks!

modified on Friday, October 22, 2010 2:03 PM

GeneralMy vote of 5memberksafford13 Oct '10 - 5:45 
Weidong, you are THE man! I saw your initial IssueVision a few months ago and got it working and tried to understand it and thought I would come back after digging into Wcf RIA Services, MVVM, and MEF some more. I am firing it up again and plan to use it as a basis for my Enterprise application. I cannot thank you enough for your work on this project as it is THE best example out there.
GeneralRe: My vote of 5memberWeidong Shen20 Oct '10 - 14:15 
Thank you very much!
QuestionHow different this is from PRISM 4 in terms of modularity using MEFmemberMilind Y26 Aug '10 - 23:28 
Just wnated to know whether you tried to use PRISM for implementing modularity using MEF. It would be great if you can share one sample if you have on or redirect me to the link where I can find a sample which demonstrates following
1. Modularity with MEF
2. MVVM pattern using MEF and WCF RIA service with custom POCO ( as I have to use Oracle database)
3. Messaging using Event aggregation.
 
Having said the I love the solution you have, but just wanted to get hold of above which is bugging me at this stage, so that I can take a very big decision on which path to go basically between MVVM light or PRISM for implementing big product with around 48 modules in it.
 
Waiting for your response as you have got complete app running with all the above. Thanks for posting such working app, really appreciated.
 
Thanks,
Milind
AnswerRe: How different this is from PRISM 4 in terms of modularity using MEFmemberWeidong Shen27 Aug '10 - 4:28 
We use PRISM at work for WPF development, and PRISM v4 is still in CTP as of today, not sure what the final feature set will be.
 
MVVM Light Toolkit is just a toolkit for MVVM pattern, while PRISM is more like an application framework to me. Which one to choose really all depends on what type of applications you are currently working on.
 
MVVMPlugin library is just my first experiment for building modular Silverlight application, and it has no dependency on MVVM Light Toolkit.
 
Thanks,
Weidong Shen
GeneralIssue with Logging inmemberutkash25 Aug '10 - 20:28 
I've installed IssueVision on a Windows Server 2008 box, and when I try to log in from a different computer, I get the following message:
 
Load operation failed for query 'Login'. Exception of type 'System.ServiceModel.DomainServices.Client.DomainOperationException' was thrown.
 
When I try to log on from the Windows Server 2008 box it seems to be able to communicate with SQL Server.
 
Any ideas as to what may be causing this exception?
-Utkash

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web04 | 2.6.130516.1 | Last Updated 6 Jul 2011
Article Copyright 2010 by Weidong Shen
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid