Author |
Share Topic Topic Search Topic Options
|
pponzano
Senior Member
Joined: 28-Apr-2011
Location: Italy
Posts: 165
|
Post Options
Quote Reply
Topic: Exporting templated class Posted: 18-Dec-2012 at 1:27am |
Hello, I'm lost in a cave with Exporting with templates... before I have had an interface of type IDashboard that has an ID (int) and a collection of Items of type Gauge Now I've been asked if it's possible to define another type of Gauge and continue using existing code structure..so I've defined those class
[Export(typeof(IDashBoard<Gauge<ISnapshot>, ISnapshot>))] public class DashboardViewModel : DashBoardBase<Indicatore<SNAPSHOT_INDICATORE_SELECT_Result>, SNAPSHOT_INDICATORE_SELECT_Result> { ... }
public class DashBoardBase<T,Y> : Screen, IDashBoard<T, Y> where T : GaugeBase<Y> where Y : ISnapshot { ... }
public class GaugeBase<T> : INotifyPropertyChanged where T:ISnapshot { ... }
public interface ISnapshot { DateTime DT_TS { get; set; } }
public interface IDashBoard<T,Y> : INotifyPropertyChanged where T : GaugeBase<Y> where Y : ISnapshot { BindableCollection<T> DataItems { get; set; }
T SelectedDataItem { get; set; }
int IdDashBoard { get; set; }
int IdLayout { get; } ... }
|
Before I had a dashboardfactory of type [ImportingConstructor] public DashBoardFactory() { //[ImportMany(typeof(IDashboard))] IEnumerable<IDashboard listaIndicatori this.listaIndicatori = listaIndicatori; } and it was working... now I've tried all the ways but I'm not able to set the export so that my dashboardfactory can get items [ImportingConstructor] public DashBoardFactory() { //[ImportMany(typeof(DashBoardBase<GaugeBase<ISnapshot>, ISnapshot>))] IEnumerable<DashBoardBase<GaugeBase<ISnapshot>, ISnapshot>> listaIndicatori this.listaIndicatori = listaIndicatori; var items = Cocktail.Composition.GetInstances<IDashBoard<Indicatore<ISnapshot>, ISnapshot>>(); int count = items.Count(); //0 or it says it cannot cast to type... } Any suggestion? Thanks
|
|
mgood
IdeaBlade
Joined: 18-Nov-2010
Location: Emeryville, CA
Posts: 583
|
Post Options
Quote Reply
Posted: 18-Dec-2012 at 8:29am |
Based on what you are showing here, you are exporting as IDashBoard<Gauge<ISnapshot>, ISnapshot>)) and the only line that isn't commented out is where you are trying to get instances of type IDashBoard<Indicatore<ISnapshot>, ISnapshot> directly from Cocktail.Composition. Those are not the same type contracts, so you won't get anything. The export and import contracts must match. You can also export/import by name if the type is too restrictive. [Export("Foo")] public class SomeClass {} [Export] public class AnotherClass { [ImportingConstructor] public AnotherClass([Import("Foo")] object foo) {} } The other option is open generics if you are developing on .NET 4.5. Unfortunately, open generics are not supported on Silverlight. [Export(typeof(IDashBoard<,>)] public GenericDashBoard<T, Y> : IDashBoard<T,Y> { } [Export] public class Foo { [ImportingConstructor] public Foo(IDashBoard<Indicatore<ISnapshot>, ISnapshot> dashboard) {} }
Edited by mgood - 18-Dec-2012 at 8:30am
|
|
giotis
Groupie
Joined: 26-Apr-2012
Location: Greece
Posts: 53
|
Post Options
Quote Reply
Posted: 21-Dec-2012 at 4:20pm |
I tried by your example, to create generic ViewModel but failed
[Export(typeof(GridViewViewModel<>))] public class GridViewViewModel<T> : Screen, IHandle<SavedMessage> where T : DomainModel.EntityBase {
..... copy from StaffingResourceSearchViewModel
or with Interface
public interface IGridView<T> { void Start(); T CurrentStaffingResource { get; set; } event System.ComponentModel.PropertyChangedEventHandler PropertyChanged; }
[Export(typeof(IGridView<>))] public class GridViewViewModel<T> : Screen, IGridView<T>, IHandle<SavedMessage> where T : DomainModel.EntityBase { .... var viewModel= Composition.GetInstance<IGridView<DomainModel.StaffingResource>>(); viewModel is null
MEF don't create viewModels?
In fact is possible?
thank you for your time
|
|
mgood
IdeaBlade
Joined: 18-Nov-2010
Location: Emeryville, CA
Posts: 583
|
Post Options
Quote Reply
Posted: 21-Dec-2012 at 5:11pm |
Which version of Cocktail are you using?
You need to use 2.0.5 or higher. There was a fix in 2.0.5 for this, see release notes.
Edited by mgood - 21-Dec-2012 at 5:15pm
|
|
giotis
Groupie
Joined: 26-Apr-2012
Location: Greece
Posts: 53
|
Post Options
Quote Reply
Posted: 21-Dec-2012 at 6:05pm |
Cocktail 2.2.0
I looked at Cocktail sourse code(Test project) but not work is still null
any other example to working ?
Edited by giotis - 21-Dec-2012 at 6:15pm
|
|
giotis
Groupie
Joined: 26-Apr-2012
Location: Greece
Posts: 53
|
Post Options
Quote Reply
Posted: 21-Dec-2012 at 7:36pm |
I want to create Generic ViewModels
or I making wrong to follow this way?
any help Marcel ?
|
|
mgood
IdeaBlade
Joined: 18-Nov-2010
Location: Emeryville, CA
Posts: 583
|
Post Options
Quote Reply
Posted: 22-Dec-2012 at 12:12am |
Here's a very silly example that works just fine for me. I'm not sure what's going on with your code. There's something you are not showing me.
using System.ComponentModel.Composition; using Caliburn.Micro; using Cocktail; using IdeaBlade.EntityModel; using Microsoft.VisualStudio.TestTools.UnitTesting;
public interface IGridView<T> where T : IEntity { T CurrentEntity { get; } }
[Export(typeof(IGridView<>))] public class GridView<T> : Screen, IGridView<T> where T : IEntity { private readonly IDialogManager _dialogManager; private T _currentEntity;
[ImportingConstructor] public GridView(IDialogManager dialogManager) { _dialogManager = dialogManager; }
public T CurrentEntity { get { return _currentEntity; } private set { if (Equals(value, _currentEntity)) return; _currentEntity = value; NotifyOfPropertyChange(() => CurrentEntity); } } }
namespace GenericExportTests { [TestClass] public class GenericExportExample { [TestMethod] public void ShouldInstantiateGenericViewModel() { var bootstrapper = new CocktailMefBootstrapper<object>(false); var instance = Composition.GetInstance<IGridView<Customer>>();
Assert.IsNotNull(instance); } } }
|
|
giotis
Groupie
Joined: 26-Apr-2012
Location: Greece
Posts: 53
|
Post Options
Quote Reply
Posted: 22-Dec-2012 at 11:52am |
Marcel, many thanks I dont know very well MEF but when run your example I take back an error "could not locate any instances of contract ... after add in Appbootstraper batch.AddExportedValue<IGridView<Customer>>(new GridView<Customer>(null) ); only for testis ok. I use the latest version of TempHire (vs2012) a).I hide the "StaffingResourceSearchViewModel" and I create new one like your example public interface IGridViewGeneric<T> where T : EntityBase{ T CurrentEntity { get; } }
[Export(typeof(IGridViewGeneric<>))] public class GridViewGenericViewModel<T> : Screen, IGridViewGeneric<T> where T : EntityBase {...
b)Create a new view named GridViewGenericView b).I changed the "ResourceMgtViewModel" [ImportingConstructor] public ResourceMgtViewModel(IGridViewGeneric<DomainModel.StaffingResource> searchPane, ..... but took back the same error "could not locate any instances of contract IGridViewGeneric<DomainModel.StaffingResource... I think MEF dont find the instance If you like to anwser me please with TempHire example (I mean temphire entities)
|
|
mgood
IdeaBlade
Joined: 18-Nov-2010
Location: Emeryville, CA
Posts: 583
|
Post Options
Quote Reply
Posted: 22-Dec-2012 at 4:49pm |
At this point I'm at a loss as to what you are doing wrong. The example I gave you works just fine. You can download the entire solution from my Skydrive ( http://sdrv.ms/VZ1pSj). If this doesn't work than I don't know. I also have two unit tests in the Cocktail test project to ensure open generics work and those tests pass. I can't spend more time on samples. You gonna have to hire one of our consultants to teach you MEF as so far there doesn't appear to be a bug in Cocktail's handling of open generics. Just to reiterate, I hope you are not trying to do anything of this in Silverlight, because this won't work in Silverlight as I mentioned before. This will only work in a WPF 4.5 (and Windows 8 Store) applications.
Edited by mgood - 22-Dec-2012 at 5:20pm
|
|
giotis
Groupie
Joined: 26-Apr-2012
Location: Greece
Posts: 53
|
Post Options
Quote Reply
Posted: 22-Dec-2012 at 5:40pm |
not in SilverLight
your sample is perfect , work in this case
but something missing when run under TempHire
I ll try to help you for you help me I check the Composition and the Catalog have the part GridView({0}) - exist !
but when ... var instance = Composition.GetInstance<IGridView<Foo>>(); error "Could not locate any instances of contract IGridView<Foo...
very sorry if I spend your time many thanks
Edited by giotis - 22-Dec-2012 at 5:42pm
|
|
mgood
IdeaBlade
Joined: 18-Nov-2010
Location: Emeryville, CA
Posts: 583
|
Post Options
Quote Reply
Posted: 22-Dec-2012 at 6:10pm |
Ok, I was able to reproduce the issue. TempHire uses the InterceptingCatalog from MefContrib and it looks like it is causing this issue. Unfortunately, the MefContrib project is dead, so this won't get fixed. If you want to use open generics, you gonna have to forgo the use of the InterceptingCatalog. I know of at least one other person who was having issues in their application because of the InterceptingCatalog. I will remove it from future versions in order to discourage its use. If you comment out the following method in BootstrapperBase<T> it should work, but now you gonna have to manually subscribe all your ViewModels that receive messages from the EventAggregator with a call to EventFns.Subscribe(this) in the constructor. protected override ComposablePartCatalog PrepareCompositionCatalog() { var cfg = new InterceptionConfiguration().AddInterceptor(this); return new InterceptingCatalog(base.PrepareCompositionCatalog(), cfg); }
|
|
giotis
Groupie
Joined: 26-Apr-2012
Location: Greece
Posts: 53
|
Post Options
Quote Reply
Posted: 22-Dec-2012 at 7:33pm |
What can I say, you're huge, you're beautiful, you covered the issue 100%, something good came out of our discussion, must fix the code because it is too painful to remember to subscribe each time there IHandle.
|
|