How to change exported property through MEF? - export

I'm studying MEF, and try to use Export attribute to export a property, and import it in an other class.
But my problem is that I want to change this property and the other class can import a new value.
For example,
[Export]
public class A{
[Import("Notes")]
public string Description{get;set;}
}
[Export]
public class B{
[Export("Notes")]
public string Text{get;set;}
}
I want once I change the Text of class B, the A.Description can get changed too.
So, how can I implement this?
Any good idea?

This approach would work for most reference type but not with string which is immutable. This means that after you change the value of B.Text, the objects referenced by A.Description and B.Text will no longer be the same (you can use Object.ReferenceEquals to test this).
One way to do what you are after using MEF is to export/import a method instead of the property:
[Export]
public class A
{
public string Description { get { return GetDescription(); } }
[Import("GetNotes")]
Func<string> GetDescription;
}
[Export]
public class B
{
public string Text { get; set; }
[Export("GetNotes")]
string GetText()
{
return Text;
}
}
Finally note that there are other ways to do this. The most common in .NET is with events.

Related

Serialize a derived class without access to base class

I need to serialize a derived class in my Windows Phone 7 Project for tombstoning state.
But I don't have access to the code to the base class - exposed by a Library -.
//don't have access to this class
public class A
{
public string member1 {get;set;}
}
[DataContract]
public class B : A
{
public B(){}; //CTOR
[DataMember]
public string member2 {get;set;}
}
When the system try to serialize (I save it to PhoneApplicationPage.State => so it's auto serializing) : it's not working, the exception (InvalidDataContractException) says "Type 'B' cannot inherit from a type that is not marked with DataContractAttribute or SerializableAttribute. Consider marking the base type 'A' with DataContractAttribute or SerializableAttribute, or removing them from the derived type."
Should I implement a custom serializer ? How can I do that (in Windows Phone 7)
Rather than derive from the library class, you could have a member variable that of that type and expose the properties of the library class member via custom getters and setters:
[DataContract]
public class MyClass
{
BaseClass Wrapped { get; set; }
public MyClass()
{
Wrapped = new BaseClass( );
}
[DataMember]
public string member1
{
get { return Wrapped.member1; }
set { Wrapped.member1= value; }
}
}

Property Injection with AutoFixture

I've been fighting with the following issue for a day or so now. Despite having used AutoFixture for years, I can't get my head around this issue.
I have an abstract class:
public abstract class AbstractClass
{
public IChildClass Child {get; set;}
};
The IChildInterface:
public interface IChildClass
{
string Name {get; set;}
}
The implementation of the interface:
public class ChildClass : IChildClass
{
public string Name {get; set;}
}
I then have a derived class of AbstractClass:
public class MyClass : AbstractClass
{
public MyClass()
{
Initialize();
}
private void Initialize()
{
var nameOfChild = Child.Name;
}
}
In my unit test for MyClass I do the following:
var fixture = new Fixture().Customize(new AutoMoqCustomization());
var sut = fixture.Create<MyClass>();
But get an NullReferenceException on Child.Name. I've tried using Register and Customize for IChildClass and AbstractClass, no luck. Even a custom implementation of ISpecimenBuilder, doesn't help in this case.
Does anyone have a good idea on how to get around this?
The above code will never work because Initialize gets called in the Ctor. Autofixture is initializing the object and the property hasn't been injected just as yet. There are several work arounds for the above but as it stands... Child will always be null in the Initialize method.

MEF Importing ViewModel that needs data, to View for Silverlight

I'm not sure the best way to get this accomplished. Here's my view:
public partial class MyPage : Page
{
[Import]
public MyVM ViewModel
{
get { return DataContext as MyVM ; }
set { DataContext = value; }
}
public String EventName { get; set; }
public MyPage()
{
InitializeComponent();
CompositionInitializer.SatisfyImports(this);
}
// Executes when the user navigates to this page.
protected override void OnNavigatedTo(NavigationEventArgs e)
{ }
}
And my VM:
[Export]
public class MyVM : ViewModelBase
{
public MyVM ()
{
}
}
This works great. However, I need to get data from either the viewmodel that has my string, or the URL. Either way, I'm not sure the best way to get the string to MyVW using MEF.
I thought ok I'll use Messaging from MVVMLight, but the MyVM class isn't instantiated yet to receive the broadcast from the other ViewModel. So then I thought well, I'll try this:
[Export]
public class MyVM : ViewModelBase
{
public MyVM ([Import("hello")]string hello)
{
}
}
and then put this in the view:
[Export("hello")]
public String MyHello { get; set; }
but that gave me an error. Cannot call SatisfyImports on a object of type 'Form A' because it is marked with one or more ExportAttributes.
So what's the best way to accomplish this?
To share data between views I usually inject a SharedData object into my ViewModels.
[Import(RequiredCreationPolicy = CreationPolicy.Shared)]
public ISharedData SharedData { get; set; }
I'm also using the Caliburn Micro framework so I'm not passing data around via the URL querystring. By convention CM will parse out URL parameters and inject them into properties on your VM but I'm not sure if this functionality only applies to Windows Phone development.
from here
Examine the Page’s QueryString. Look
for properties on the VM that match
the QueryString parameters and inject
them, performing the necessary type
coercion.
When you say you want to possibly pass data from the view to the vm, that should happen through databinding.

Custom Class ToString() Override not showing up in WPF ComboBox

I have a WPF application built with MVVM and am trying to display a custom class in a combobox. I am still getting the Namespace.Asset despite overriding the ToString Method to something easier on the eyes. What am I doing wrong?
XAML code
<ComboBox ItemsSource="{Binding Drivers}" SelectedItem="{Binding SelectedDriver}" Grid.Row="20" Grid.Column="1" Grid.ColumnSpan="3"/>
ViewModel Code
public List<Driver> Drivers
{
get
{
return this.drivers;
}
set
{
this.drivers = value;
this.RaisePropertyChanged("Drivers");
}
}
public Driver SelectedDriver
{
get
{
return this.selectedDriver;
}
set
{
this.selectedDriver = value;
this.RaisePropertyChanged("SelectedDriver");
}
}
One of the custom classes code with overriden ToString
public class ExperimentalDriver : Driver
{
public override DriverResponse GetDriverResponse(double time)
{
... random unrelated code....
}
public override string ToString()
{
return "Experimental Driver";
}
}
You might need to set the ToString() on the base class
Something like:
public class Driver
{
protected string displayName;
public override string ToString()
{
return displayName;
}
}
Then your class constructors for your sub classes would simply set the displayName
public class ExperimentalDriver : Driver
{
public ExperimentalDriver()
{
displayName = "Experimental Driver";
}
}
Ok I figured it out. I have an abstract class "Driver" in that abstract class I added the following code to require all my derived classes to have a ToString() method
public new abstract string ToString();
When I remove it the problem goes away.

MVVM with aggregated model classes - how to wrap in ViewModels?

I'm currently trying to create a small application using the MVVM pattern. However I don't really know how to correctly wrap up aggregated Model classes in my ViewModel. From what little I know about MVVM, you're not supposed to expose Models in your ViewModel as properties or else you could directly bind to the Model from your View. So it seems I have to wrap the nested Model in another ViewModel, but this imposes some problems while synching Model and ViewModel later on.
So how do you do that efficiently?
I'll give a short example. Let's suppose I have the following model classes:
public class Bar
{
public string Name { get; set; }
}
public class Foo
{
public Bar NestedBar { get; set; }
}
Now I create two ViewModel classes accordingly, wrapping the Models, but run into problems with the FooViewModel:
public class BarViewModel
{
private Bar _bar;
public string Name
{
get { return _bar.Name; }
set { _bar.Name = value; }
}
}
public class FooViewModel
{
private Foo _foo;
public BarViewModel Bar
{
get { return ???; }
set { ??? = value; }
}
}
Now what do I do with the Bar-property of FooViewModel? For "get" to work I need to return a BarViewModel instance. Do I create a new field of that type in FooViewModel and just wrap the _foo.NestedBar object in there? Changes to that field's properties should propagate down to the underlying Bar instance, right?
What if I need to assign another BarViewModel instance to that property, like so:
foo.Bar = new BarViewModel();
Now that won't propagate down to the model, which still holds the old instance of type Bar. I'd need to create a new Bar object based on the new BarViewModel and assing it to _foo, but how do you do that elegantly? It's pretty trivial in this sample, but if Bar is much more complex with lots of properties, that'll be a lot of typing... not to mention it'd be very prone to errors, if you forget to set one of the properties.
#Goblin
There are some flaws with your code: e.g. what if I get a list of Foo objects from database and I want to wrap each of them in an ObservableCollection?
then your Constructor of FooViewModel should accept the Foo model as parameter and not create it inside the Constructor!
Normally you do this to wrap a model into a viewmodel and put it the same time into a bindable Collection:
IEnumerable<Foo> foos = fooRepository.GetFoos();
foos.Select( m => viewmodelCollection.Add(new ViewModel(m,e.g.Service)));
The models properties are not copied to the ViewModel hell no!!! The ViewModel does delegate its properties to the model properties like:
public class FooViewModel
{
private Foo _foo;
public FooViewModel(Foo foo,IService service)
{
_foo = foo;
}
public string FoosName
{
get{return _foo.Name };
set
{
if(_foo.Name == value)
return;
_foo.Name = value;
this.NotifyPropertyChanged("FoosName");
}
}
}
And like Goblin said all UI-Specific interfaces like:
IDataErrorInfo
INotifyPropertyChanged
IEditableObject
etc...
are implemented the by the ViewModel ONLY.
My above answer only makes sense if you are doing DDD - if you are not - you can solve your problem like this - simply 'flattening' the model:
public class FooViewModel
{
private Foo _foo;
public string Name
{
get { return _foo.Name; }
set { _foo.Name = value; }
}
public string BarProperty
{
get { return _foo.Bar.Property; }
set { _foo.Bar.Property = value; }
}
}
Or you could do like I showed in the prior example - just ignore everything about Aggregates... should still work.
Okay - first things first - using the term Aggregate implies you are adhering to DDD? If you are - you are doing an encapsulation no-no :-). One Aggregate should never be allowed to edit another Aggregate. If what you have is that both are really Aggregate they would become associated (which is perfectly 'legal' in a DDD-sense - but then your propety on the FooViewModel wouldn't be of type BarViewModel, but rather type Bar. That way Bar would (as it should) be responsible for updating itself - and we only maintain the link in FooViewModel.
However, if what you are doing is AggregateRoot with a ValueType child - then here is what you could do given a slightly modified domain model:
public class Foo
{
public string SomeProperty { get; set; }
public Bar Bar { get; set; }
public void Save()
{
//Magically saves to persistent storage...
}
}
public class Bar
{
public Bar(string someOtherProperty)
{
SomeOtherProperty = someOtherProperty;
}
public string SomeOtherProperty { get; private set; }
}
And then for the ViewModels:
public class FooViewModel
{
private Foo _foo;
public FooViewModel()
{
Bar = new BarViewModel();
}
public BarViewModel Bar { get; private set; }
public void SetFoo(Foo foo)
{
_foo = foo;
SomeProperty = foo.SomeProperty;
Bar.SetBar(foo.Bar);
}
public string SomeProperty { get; set; }
public void SaveChanges()
{
_foo.SomeProperty = SomeProperty;
_foo.Bar = Bar.CreateUpdatedBar();
_foo.Save();
}
}
public class BarViewModel
{
public string SomeOtherProperty { get; set; }
public void SetBar(Bar bar)
{
SomeOtherProperty = bar.SomeOtherProperty;
}
public Bar CreateUpdatedBar()
{
return new Bar(SomeOtherProperty);
}
}
This way - the FooViewModel is now capable of controlling the BarViewModel (which does nothing but accept a valuetype - and create a new one when asked). This also solves a common UI-problem ('How do we edit an object that has no setters?' - answer: 'We don't - we create a new one'). A lot of fleshing out is missing (INotifyPropertyChanged, dirty-tracking etc., but those are easy if you get through this leap of thinking :-).
I hope this makes a wee bit of sense :-) Otherwise, I'll be happy to elaborate.

Resources