WPF DataGrid and parameterless constructors - wpf

I have a class "MyEntity", which does not have a default constructor (well, it does, yet it is not suitable for use).
I have a form with a DataGrid, which has a cool feature for creating new rows.
Problem: DataGrid cannot create new object when no parameterless constructor is defined.
Question: is there a way to provide the DataGrid with a Func that would construct the new object (= some factory method like CreateObject)? Or is there some other solution?
PS Adding a default constructor is not an option - it is not suitable for my purposes. POCO in EF4 requires objects to be created through a context factory class (calling CreateObject).

Wrap your MyEntity class in another class (MyEntityWrapper) with a default constructor and databind the grid to a collection of MyEntityWrapper objects. Put it in a VM to keep you view (the grid) and model (the collection of MyEntity object) clean.

Related

How to edit data in a binding to a custom ConfigurationElementCollection

I am using a custom ConfigurationElementCollection, which Implements INotifyCollectionChanged. Each of the elements that can be stored inside the collection (all of which inherit ConfigurationElement), also Implements INotifyPropertyChanged.
I have a config handler class that stores the collection in a property (CustomCollection), when its constructor is called. This ConfigHandler also Implements INotifyPropertyChanged.
The constructor is as follows:
_config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None)
CustomCollection = (DirectCast(_config.GetSection("CustomCollection"), CustomConfigurationSection)).CustomCollection
I can bind to CustomCollection just fine:
<DataGrid DataContext="{Binding Source={x:Static l:Handlers.ConfigHandler}}" ItemsSource="{Binding Path=CustomCollection}" />
And this displays all the elements onscreen correctly.
As soon as I try to edit one of the elements, however, I get an exception:
System.InvalidOperationException: 'EditItem' is not allowed for this view.
at System.Windows.Controls.ItemCollection.System.ComponentModel.IEditableCollectionView.EditItem(Object item)
at System.Windows.Controls.DataGrid.EditRowItem(Object rowItem)
...
How can I make this binding editable? The only way I can think to do it, is to make some more traditional classes (i.e. not configuration classes) and copy all the data into those - but that seems like a waste when I've already got all the observable properties I need set up.
Is your collection an IEnumerable<ConfigurationElement>? Enumerables cannot be edited in the DataGrid. Convert it to a List<ConfigurationElement>
ConfigurationElementCollection seems to be an IEnumerable. From msdn:
public abstract class ConfigurationElementCollection : ConfigurationElement,
ICollection, IEnumerable
You should make your class a List:
CustomCollection = (from ConfigurationElement ce in someConfigurationElementCollection select ce).ToList();

What should compose View with ViewModel and show result?

I have problem of thinking ideal solution for creating and showing window in WPF MVVM application. Some part of application needs to show some window with some data. I create VM, set its properties, create View, assign its VM (in constructor), then display window. This is done using class that I named ViewController and this class have methods with parameters for every window in my application. I think there can be better solution than this, but not overengineered.
The normal solution is you have a class that wraps and instantiates a View ViewModel pair. This is often called screen. it would look something like this.
public class Screen<TView> where TView : Window
{
public Screen(TView view, object viewModel){
//store view and viewModel props
//display view
//set viewModel as DataContext of view
}
}
This is a very rough example, there are lots of ways you can do it.
In the last I created implementation of IWindowManager, which have methods for showing required windows and these methods have parameters if needed. Methods create view model, set its properties and inject it to window. Only drawback of this solution is when new window is needed, new method must be added to interface and implementation of WindowManager.

WPF MVVM: View's ListBox with source deep in Model. How to implement?

I'm new to WPF. I need to Bind UI's ListBox to the source that is deep in Model Layer.
App scheme is on picture below. Desc:
My MainWindowViewModel Class has a Scheduler Property (Scheduler Class in Model layer).
Scheduler Class has a CurrentParser Property (Parser Class in Model layer).
Parser Class has a Result field (ParserResultMetaData Class in Model layer).
ParserResultMetaData Class has a Log field (Log is a List(Of String))
Log can be changed only programmatically from model layer (Parser adds lines during it's work).
So my question is how can I bind my ListBox to this List to match MVVM pattern.
As I get it now, ViewModel must have an ObservableCollection(Of String) witch is a copy of my List(Of String) from Model layer.
Somehow you need to notify the UI when a line is added to the collection. There are multiple ways to achieve this, but if the collection is modified from within the model layer, you need a mechanism for communicating this to other layers in one way or another.
Use an ObservableCollection in your Model layer.
While types like ObservableCollection and INotifyPropertyChanged are widely used in MVVM architectures, they are not specific to them and in some cases it can make sense to use them in the model layer directly. Using an ObservableCollection in your Parser class is one way to provide this notification mechanism. You can then bind the ItemsSource of the ListBox to Scheduler.Parser.Result.Log directly and it will update accordingly.
Create a wrapper property in your ViewModel.
If you don't want to use an ObservableCollection in your model, you can expose the List via a property in your ViewModel, for example:
public IEnumerable<string> ParserLog
{
get { return Scheduler.Parser.Result.Log; }
}
Then you need to manually notify the UI when an item is added, so you're gonna need an event (or something equivalent) which tells your ViewModel that the list changed and it needs to raise the PropertyChanged Event for the ParserLog property. Add code like this in your ViewModel:
this.Scheduler.Parser.ResultUpdated += (s, e) => this.RaisePropertyChanged("ParserLog");
This will tell the ListBox to update the items from the ParserLog property.

MVVM model instantiation

Following WPF MvvmFoundation, linking the View with the ViewModel has many choices like described on http://www.paulstovell.com/mvvm-instantiation-approaches.
However their example has nothing about how to link the ViewModel with the Model.
Traditionally I created the model first and then one or more views that render it. It seems that MVVM pushes people to create the View, which creates the ViewModel, which create the Model. I hope it's not the case as wiring a complex business model with various ModelView can else be tough.
How do you instantiate your business model classes in MVVM and link them with your ViewModels?
I normally pass Model objects as constructor params to VM. I use App class as the controller which will initialize MainWindow, MainWindowViewModel with the main model. There after the MainWindowViewModel takes care of initializing other VMs with appropriate model objects.
private void Application_Startup(object sender, StartupEventArgs e)
{
mainWindow = new MainWindow();
mainWindow.DataContext = new MainWindowViewModel(new Model());
mainWindow.Show();
}
You create your BusinessModel classes inside your ViewModel.
So in your CustomerViewModel you would say this.CurrentCustomer = new CustomerModel(), and your CustomerView would bind to the CurrentCustomer property on the ViewModel
If you are interested, I wrote up a simple sample using MVVM as an example of how the View, Model, and ViewModel interact.
I use dependency injection/MEF to do this. Just export all of my model classes all the way down the chain, and have them imported for me automatically into the ViewModel constructor.
I take a variety of different approaches depending on the situation. I've found that when it comes to getting this data linked, one size does not fit all.
For simple cases, I will have the ViewModel and the Model be the same thing. Obviously not that good for all cases, but sometimes there is just no need to go the extra mile to split the M from the VM. (Great for cases where you have, say, listbox items that have scant information)
Sometimes, especially when the model is a chunk of code you don't have access to (written by another developer) it is easy to subclass the model, and add all of your VM things (observable properties, etc.) on to it.
Lastly, I will use the approach that is mentioned by Souvik. Construct the VM with the model information that you want to use as a parameter, or allow it to be passed in otherwise. This is probably the most common approach for my larger and more complex Model / ViewModel relationships.
I am auto-passing IRepository instance to VM constructor using IoC container and everything VM needs to do with models is done via this repository. Repository is class which: Create, read, update and delete data. When I need to show some view (window), I use IViewService.ShowDialog(viewModel As ViewModelBase). In implementation of IViewService, there are views registered with VMs, so VMs only need to know other VMs and not their views (like "Show me view for this view model").

Why has the selector class an internal Constructor?

I tried to derive from the Selector class cause I need a similar functionality as the ListBox but it is no ListBox.
I had a look at the signature of the Selector class and it is (http://msdn.microsoft.com/en-us/library/system.windows.controls.primitives.selector(v=vs.95).aspx)
public abstract class Selector : ItemsControl,
ISupportInitialize
But the problem is that the constructor is internal. So it is not possible to derive from this class outside the assembly (ListBox and ComboBox are in this assembly).
I now derived from the ListBox to achieve my goal, but my question is:
Why has the selector class an internal Constructor?
Because the Selector class is abstract. You can't create instances of abstract classes, and the easiest way to make sure you can't even do that by mistake (in a regular way) is to not make a constructor available.
I don't see an entry for the constructor on the MSDN, but my bet is that it's probably a protected constructor, not an internal one.
But from what I can see, nothing stops you from deriving from Selector, and create your custom implementation.
Edit:
Reflector shows the constructor to be internal indeed, so no deriving...

Resources