I have a WPF MVVM App, but I want my ViewModel to be generic. What the app is suppose to do is take some Data and do CRUD operations on it without knowing the Type of the data it's getting at the compile-time. So I declared my ViewModel like this:
public class GenericViewModel<T> where T : class
{
private void ConstructorBase()
{
Type theType = typeof(T);
Properties = theType.GetProperties().ToList();
}
public GenericViewModel(DbContext _dbContextInsert) //pravi novi repository na osnovu DbContexta
{
ConstructorBase();
_R = new RepositoryGlobal<T>(_dbContextInsert);
}
public T newT { get; set; }
public T selectedT { get; set; }
public List<PropertyInfo> Properties { get; set; }
private RepositoryGlobal<T> _R;
}
Now, disregard almost everything you see inside it, the only important thing is that the Constructor is never reached. I set this ViewModel as the DataContext for the main window like this:
InitializeComponent();
this.DataContext = new GenericViewModel<Person>(new PersonDbContext());
But when I put a breakpoint inside the ViewModel's constructor, the program never gets stopped.
Any ideas?
Dependencies should be abstractions, not implementations.
Your generic view model should not create it's own repository, instead you should pass in an instance of this dependency via the constructor.
public class GenericViewModel<T> where T : class
{
protected readonly IRepository<T> _Repository;
public GenericViewModel(IRepository<T> repository)
{
_Repository = repository;
}
...
}
You would then create an instance of your repository like so:
DbContext context = new PersonDbContext();
IRepository<Person> personRepo = new PersonRepository(context);
GenericViewModel<Person> personViewModel = new GenericViewModel<Person>(personRepo);
There, your View Model's dependencies are no longer tied to a specific implementation, your code is now far more adaptable to changes. Not to mention massively easier to test.
Related
I have something like this:
public class ModelEntity : Entity
{
public override int Id { get; set; }
public string FileName { get; set; }
}
public class DataTransferObject
{
public int Id { get; set; }
public string FileName { get; set; }
}
And I would like to do something like this:
var model = _fixture.Create<ModelEntity>();
var dto = _fixture.Create<DataTransferObject>().FillWith(model);
Right now I am doing the following but I am not sure if is the right way to do it
var model = _fixture.Create<ModelEntity>();
var dto = model.AsSource().OfLikeness<DataTransferObject>().CreateProxy();
AutoFixture doesn't have a feature like that, but I think there's something better to be learned from this:
AutoFixture was originally built as a tool for Test-Driven Development (TDD), and TDD is all about feedback. In the spirit of GOOS, you should listen to your tests. If the tests are hard to write, you should consider your API design. AutoFixture tends to amplify that sort of feedback, and it may also be the case here.
It sounds like you need to be able to populate a DataTransferObject with values from a ModelEntity instance. Could this suggest that some sort of mapping would be a valuable addition to your API?
Depending on how these types are already coupled, you could consider adding a projection method to your ModelEntity class:
public class ModelEntity : Entity
{
public override int Id { get; set; }
public string FileName { get; set; }
public DataTransferObject ToDataTransferObject()
{
return new DataTransferObject
{
Id = this.Id,
FileName = this.FileName
};
}
}
However, the disadvantage of this approach is that it couples those two types to each other.
If you find that undesirable, you could instead introduce a dedicated Mapper Service, which can map a ModelEntity instance to a DataTransferObject object - and perhaps vice versa.
If, for some unfathomable reason, you don't want to introduce such a Mapper into your System Under Test, you can still add it as a reusable Service in your test project.
If you don't wish to write such a Mapper yourself, you could consider using something like AutoMapper for that purpose.
iv'e got a CompositeCommand exposed globally in my startup project
public static class Commands
{
public static readonly CompositeCommand DiceRolledCommand = new CompositeCommand();
}
in a ControlLibrary referenced by my startup project iv'e got a Control which has a DelegateCommand ,
each instance of this Control has to register it's Command with the globally exposed DiceRolledCommand.
what wold be the best practice of doing so :
here are 3 idea's of which the first 2 i don't like because they are a kinda of hack , where you take some programming component (dp) and alter it's use for your benefit , resulting in poor code and design .
1)
a regular decadency property of type CompositeCommand which will be set with DiceRolledCommand
and on it's CallBack register MyControl's DelegateCommand (OnDiceRolledCommand) .
public class MyControl : Control
{
public DelegateCommand<Tuple<int, int>> OnDiceRolledCommand { get; private set; }
public CompositeCommand GlobalDiceRolledCommand
{
get { return (CompositeCommand)GetValue(GlobalDiceRolledCommandProperty); }
set { SetValue(GlobalDiceRolledCommandProperty, value); }
}
public static readonly DependencyProperty GlobalDiceRolledCommandProperty =
DependencyProperty.Register("GlobalDiceRolledCommand", typeof(CompositeCommand), typeof(MyControl), new UIPropertyMetadata(null,GlobalDiceRolledCommandPropertyChanged));
private static void GlobalDiceRolledCommandPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var myControl= d as MyControl ;
var compoisteCommand = e.NewValue as CompositeCommand;
compoisteCommand.RegisterCommand(myControl.OnDiceRolledCommand);
}
}
<local:MyControl GlobalDiceRolledCommand="{x:Static local:Commands.DiceRolledCommand}"/>
i don't like this approach since it's a kind of manipulation where a Dependency Property is used has a Complex logical setter .
2) i could also do the same as in (1) using a third party class with an attached property which will register the OnDiceRolledCommand in an attached property's CallBack
public static class Commands
{
public static readonly CompositeCommand DiceRolledCommand = new CompositeCommand();
public static ICommand GetRegisterToDiceRolledCommand(DependencyObject obj)
{
return (ICommand)obj.GetValue(RegisterToDiceRolledCommandProperty);
}
public static void SetRegisterToDiceRolledCommand(DependencyObject obj, ICommand value)
{
obj.SetValue(RegisterToDiceRolledCommandProperty, value);
}
public static readonly DependencyProperty RegisterToDiceRolledCommandProperty =
DependencyProperty.RegisterAttached("RegisterToDiceRolledCommand", typeof(ICommand), typeof(Commands), new UIPropertyMetadata(null,OnRegisterToDiceRolledCommandProperty);
private static void OnRegisterToDiceRolledCommandProperty(DependencyObject d , DependencyPropertyChangedEventArgs e)
{
var commandToRegister = e.newValue as DelegateCommand;
DiceRolledCommand.RegisterCommand(commandToRegister );
}
}
<local:MyContorl local:Commands.RegisterToDiceRolledCommand="{Binding OnDiceRolledCommand , RelativeSource={RelativeSource Self}}"/>
i also don't like this approach for the same reason as 1 ..
3) passing the composite command as a parameter to constructor , this approach is better since it keeps
the initializing logic in the constructor where it should be , i just can't figure out how to pass
an argument to a contractor through XAML , i'm not sure if it's even possible .
public class MyControl : Control
{
public MyControl(CompositeCommand globalDiceRolledCommand)
{
.........
globalDiceRolledCommand.Register(OnDiceRolledCommand);
}
}
<local:MyControl ..... >
Some how pass parameters to contractor in order to create the element in XAML
</local:MyControl>
to summarize :
A) any thoughts about (1) and (2) .
B) thoughts of how to accomplish 3 , and if it seems like good design .
C) Any good pattern of accomplishing this scenario.
thanks in advance .
Whenever I use Global Commands like that they are usually defined in either an Infrastructure class library which every library can reference. Or they are defined in a consuming core library that each module could reference directly.
I wrote a lot of this up in a Code Project article
Part 2 here
I'm making a silverlight website.
Is it possible to make some kind of a memory where i can store some values and can recall them from different pages?
thx
I normally create a class called Session, with a property called Default that looks like this:
public class SessionBase<T> : INotifyPropertyChanged where T : class
{
public static T Default
{
get
{
var instance = Application.Current.Resources["SessionName"] as T;
if (instance == null)
{
instance = Activator.CreateInstance<T>();
Application.Current.Resources.Add("SessionName", instance);
}
return instance;
}
}
}
Then in my app.xaml I have:
<Classes:Session x:Name="SessionName"/>
This way you can access the same instance with binding and with c# (code behind). T inherits SessionBase and in that class you can store any information you want and it will remain available throughout the application session. eg:
public class Session : SessionBase<Session>
{
public int X { get; set; }
}
You will then be able to bind to X (need to raise the PropertyChanged for two way binding) and access it from c#
I have a model that looks like this:
// Subclass 1
class A
{
public B PropB { get; set; }
}
// Subclass 2
class B
{
public List<A> PropA { get; set; }
}
// And finally Model
class Model
{
public List<A> PropA { get; set; }
public List<B> PropB { get; set; }
}
Lists A and B inside Model class have references to some elements of each other.
How should the proper ViewModel look like in this case?
If there were no cross-references, that would be just 2 ObservableCollections of sub-ViewModels, but I cannot manage the situation with the references. Should each sub-ViewModel contain a references to other sub-ViewModels?
Hope that's clear enough.
You might want to have a look at Catel. It allows you to lazy-load view models based on a model. This way, you can create endless chains of view models without having to specify them first.
So, when a view detects a specific model, it will automatically convert it into a view model and you are good to go. For more information, read the docs about the nested user controls problem.
Disclaimer: I am one of the developers of Catel
I use prism v4 and MEF to load my modules. My modules contain a handful of views (MVVM) which are loaded in a ItemsControl/NavigationRegion automatically by MEF.
This works nicely, all items show up in the ItemControl. But I don't like the order in which they show. One module might contain several of the items, so changing the module load order is not enough by itself.
How can I sort the different views in the ItemsControl? Is there any way to sort them by some property?
I use prism V4, MEF and exploration due to attributes like in the StockTraderRI example.
This is actually baked into Prism4. Just apply the ViewSortHintAttribute to your views:
[ViewSortHint("100")]
class FirstView : UserControl { }
[ViewSortHint("200")]
class SecondView : UserControl { }
The default sort comparer on the regions will pick up this attribute and sort the views accordingly. You can put any string into the attribute but I tend to use medium sized numbers that allow me to easily put a new view in between existing ones.
Oh dang, this was way easier than I expected:
You can tell the region manager how to sort the views in a specific region. You just need to provide a compare function to the region.
This example sorts by a very stupid value, the function name:
private static int CompareViews(object x, object y)
{
return String.Compare(x.ToString(), y.ToString());
}
this._regionManager.Regions["MyRegion"].SortComparison = CompareViews;
Of course the region needs to be known to the region manager before you can set the SortComparison. So far the only workaround I found to achieve this was to defer to set the comparison function using the Dispatcher:
private readonly IRegionManager _regionManager;
[ImportingConstructor]
public ShellViewModel(IRegionManager regionManager)
{
this._regionManager = regionManager;
Dispatcher dp = Dispatcher.CurrentDispatcher;
dp.BeginInvoke(DispatcherPriority.ApplicationIdle, new ThreadStart(delegate
{
if (this._regionManager.Regions.ContainsRegionWithName("MyRegion"))
this._regionManager.Regions["MyRegion"].SortComparison = CompareViews;
}));
}
Of course one should use some more useful information than the class name for the sorting order, but this should be easy to solve (I'll just add an interface to all views which might be added to this region which provide a value to sort by).
I'm pretty sure you are looking for the CollectionViewSource. Bea provides some information on how to make use of it in the link.
From an MVVM stance this is how I use the ICollectionView within my ViewModel. The _scriptService.Scripts property is an ObservableCollection<T> getting wrapped in an ICollectionView which is returned to the View. The _view.Filter is being used to filter out items within the ICollection, thus changing the View. Similar to typing 'acc' and seeing all items that begin with 'acc' in your list.
public class ScriptRepositoryViewModel : AViewModel
{
private readonly IUnityContainer _container;
private readonly IScriptService _scriptService;
private readonly IEventAggregator _eventAggregator;
private ICollectionView _view;
public ScriptRepositoryViewModel(IUnityContainer container, IScriptService scriptService, IEventAggregator eventAggregator)
{
_container = container;
_scriptService = scriptService;
_eventAggregator = eventAggregator;
}
public ICollectionView Scripts
{
get
{
if (_view == null)
{
_view = CollectionViewSource.GetDefaultView(_scriptService.Scripts);
_view.Filter = Filter;
}
return _view;
}
}
}
Below is the code which takes care of the filtering, and is coming in via a DelegateCommand within Prism, this resides in the same ViewModel.
#region SearchCommand
public DelegateCommand<object> SearchCommand { get; private set; }
private String _search = String.Empty;
private void Search(object commandArg)
{
_search = commandArg as String;
_view.Refresh();
}
public bool Filter(object arg)
{
bool usingPrefix;
IScript script = arg as IScript;
if (script.FileType == ConvertPrefixToFileType(_search, out usingPrefix))
{
if (_search.Length == 2)
return true;
else
return CheckProperties(script, usingPrefix);
}
else
{
if (usingPrefix)
return false;
else
return CheckProperties(script, usingPrefix);
}
}
With the base functionality in place and making use of the ICollectionView you can apply your sorting as follows....
_view.SortDescriptions.Add(new SortDescription("PropertyName", direction));
More information on the sorting behavior can be found here, as there are some performance thoughts to keep in mind.
You could use either metadata or properties. It depends on whether you have control over the interface or not...
Views are displayed in the order they are added:
RegionManager.RegisterViewWithRegion("ListRegion", typeof(ListView));
RegionManager.RegisterViewWithRegion("ListRegion", typeof(ListView2));
RegionManager.RegisterViewWithRegion("ListRegion", typeof(ListView3));
will look like:
----region--|
| view3 |
| view2 |
| view |