RIA services: Load returning no data - silverlight

In the BookClub example application from nikhilk Kothary, a combobox is used to display book categories.
It is like this in the viewmodel class (the application is using the MVVM pattern):
private ReferenceDataContext _referenceData;
public BookClubModel() { // Constructor
_referenceData = new ReferenceDataContext();
_referenceData.Load(_referenceData.GetcategoriesQuery(), false);
}
Then there is a property to which the comboxbox is bound:
public IEnumerable Categories {
get {
return _referenceData.Categories;
}
}
Why is this working? Shouldn't we have a "completed" event handler for the load operation?
If I want to fill a IEnumerable property in the constructor, then it is not working:
private ReferenceDataContext _referenceData;
private IEnumerable _categories;
public BookClubModel() { // Constructor
_referenceData = new ReferenceDataContext();
_referenceData.Load(_referenceData.GetcategoriesQuery(), false);
_categories = _referenceData.Categories; _referenceData.Categories was what we were returning in the Categories property above.
}
Why does it work in one case and not for the other?
Daniel

In first case Categories is reference to _referenceData.Categories. And when _referenceData.Categories collection was updated, Categories also updated.
In second case you need event handler for Load operation, then do what you want with loaded entities.
Internally when you call Load, query to database is performing and when result is fetched then called load operation callback. Load operation is async operation and you need to keep in mind that fact

Related

Should a repository class using EF initialize context in the constructor only or for each methods?

Should it be like this
public class DataAccess
{
MyDbContext ctx;
public DataAccess()
{
ctx = new MyDbContext();
}
public List<entity> GetAll()
{
return ctx.entities.ToList();
}
}
or this
public List<entity> GetAll()
{
using (var ctx = new MyDbContext())
{
return ctx.entities.ToList();
}
}
Thanks a lot and if there is a problem in my questions, please inform me so that I may improve it.
The optimal lifetime of a DbContext depends on your requirements and may vary from case to case but in general you should prefer short-lives contexts (the second code snippet in your sample code):
Entity Framework’s contexts are meant to be used as short-lived instances in order to provide the most optimal performance experience ...
https://msdn.microsoft.com/en-gb/data/hh949853.aspx#9
if i have a viewmodel for adding new item and another viewmodel for displaying all or filtered items (the second viewmodel's view must always reflect any changes in the collection source), should the change be communicated from viewmodel to viewmodel directly, or viewmodel to repository to the second viewmodel?
The first view model could for example add the new item to an ObservableCollection of the second view model that the view binds to. So it should add the new item to the database using the respository and also add the new entity object to the source collection of the second view model one way or another.

How do I get the Model instance from inside its wrapping ViewModel?

Short version:
If I have ViewModel, containing its Model object and exposing its properties, how do I get the model "back" after it has been edited? If the Model-inside-ViewModel is public, it violates encapsulation, and if it is private, I cannot get it (right?).
Longer version:
I am implementing a part of an application which displays collections of objects. Let's say the objects are of type Gizmo, which is declared in the Model layer, and simply holds properties and handle its own serialization/deserialization.
In the Model layer, I have a Repository<T> class, which I use to handle collections of MasterGizmo and DetailGizmo. One of the properties of this repository class is an IEnumerable<T> Items { get; } where T will be some of the Gizmo subtype.
Now since Gizmo doesn't implement INPC, I have created the following classes in ViewModel layer:
GizmoViewModel, which wraps every public property of a Gizmo so that setting any property raises PropertyChanged accordingly;
[**] RepositoryViewModel<T>, which has an ObservableCollection<GizmoViewModel> whose CollectionChanged is listened to by a method that handles Adds, Removes and Updates to the repository.
Notice that the Model layer has a "Repository of Models", while the ViewModel layer has a "ViewModel with an ObservableCollection of ViewModels".
The doubt is related to the [**] part above. My RepositoryViewModel.CollectionChangedHandler method is as follows:
void CollectionChangedHandler(object sender, NotifyCollectionChangedEventArgs e)
{
switch (e.Action)
{
case NotifyCollectionChangedAction.Add:
foreach (var added in e.NewItems)
{
var gvm = added as GizmoViewModel;
if (gvm != null)
{
//// IS ANY OF THE ALTERNATIVES BELOW THE RIGHT ONE?
// Gizmo g = gvm.RetrieveModel(); ?? proper getter ??
// Gizmo g = GetModelFromViewModel(gvm); ?? external getter ??
// Gizmo g = gvm.Model; ?? public model property ??
_gizmo_repository.Add(g);
}
}
break;
....
Besides that, if anyone can detect any MVVM smell here, I'll be happy to know.
We can deal with our Models even outside the View and ViewModel layers, so leaving the model publicly accessible from ViewModel is I believe acceptable.
Let say you are creating the Models in "DataLayer" you can pass the instance of the Model to the ViewModel. To illustrate my point:
///Models ////////////////////////////
public interface IGizmo{}
public class Gizmo:IGizmo{}
public class SuperGizmo : IGizmo {}
public class SuperDuperGizmo : IGizmo { }
//////////////////////////////////////
public interface IGizmoViewModel<out T>
{
T GetModel();
}
public abstract class GizmoViewModelBase : IGizmoViewModel<IGizmo>
{
protected GizmoViewModelBase(IGizmo model)
{
_Model = model;
}
private readonly IGizmo _Model;
public IGizmo GetModel()
{
return _Model;
}
}
public class GizmoViewModel : GizmoViewModelBase
{
public GizmoViewModel(Gizmo model)
: base(model) { }
}
public class SuperDuperGizmoViewModel : GizmoViewModelBase
{
public SuperDuperGizmoViewModel(SuperDuperGizmo model)
: base(model){}
}
Your repository of Models will be updated on whatever updates it get from the ViewModel as long as you passed the same instance. So there is no need to have a repository of ViewModels to get the updates.
Reading your code, I think there is something of a mixup regarding your ViewModel and Model separation.
So, as I understand it, when your ObservableCollection of GizmoViewModel's changes, you are trying to add the Gizmo instance of the new item back to your Model?
I would approach this differently. You should create your Gizmo instances inside your Model layer, and when you do this you should add it to the Repository.
Otherwise, you haven't provided enough information - or rather, you have provided too much but it is the wrong sort of information. You need to describe the situation in which you want to do this, where these GizmoViewModels are created, etc.
From what I can see here, your GizmoViewModel has a dependency to your Repository<T>, so why not pass in the repository when you create your view model?
public class GizmoViewModel
{
private IRepository<Gizmo> _Repo;
//Underlying model (Doesn't implement INotifyPropertyChanged)
private Gizmo _Model;
//Wrapping properties
public int MyProperty
{
get { return _Model.Property; }
set
{
_Model.Property = value;
NotifyOfPropertyChange();
}
}
...
public GizmoViewModel(IRepository<Gizmo> repo)
{
_Repo = repo;
}
public void AddToRepo()
{
_Repo.Add(_Model);
}
...
It would be even better if these methods are inside the RepositoryViewModel base class. You can really go crazy with inheritance here. Perhaps something like this:
var gvm = added as IRepositoryViewModel;
if (gvm != null)
gvm.AddToRepo();
You can then simply call AddToRepo when you need to add the view model's underlying model to the repository.
Perhaps not the most elegant solution, however if encapsulation is what's worrying you, then you need to ensure that your dependencies are properly managed.
"If the Model-inside-ViewModel is public, it violates encapsulation"
Your assertion above is completely wrong and is killing your code.
By setting the Model property in ViewModel as private, you are forced to repeat your self ( code smells ), as you will need to define in your ViewModel, the same properties as you did for your Model, effectively transforming it into a Model class that mimics the Model it is supposed to expose to the View.
In MVVM the ViewModel role is to provide the View with all the presentation data and logic that it needs and for sure the Model is fundamental part of this data, by hidding it from the View you are killing MVVM.

Update a wpf label periodically

I am new to WPF and C# im trying to understand how can I update a UI element from a BL class (to keep a seperation between the logic and the UI) the bl gets periodic updates from a c++ network component and should update the form once a new argument comes in (I read on the msdn website but I want to see some concrete examples to make sure I got it right)
Because of your gets periodic updates from a c++ network component comment, I am assuming that you already have a system to update your property. I would expose that property from your business class in a view model class, a class with public properties and ICommand functions designed specifically to supply all of the required data to a view, or UserControl.
To be honest, I wouldn't have that (or any) functionality in a business class (depending what you mean by business class)... I'd personally put it straight into the view model, or have a manager/service class that exposed it.
If you insist on keeping it where it is, you'll have to implement either an event or a delegate in your business class so that users of that class can be alerted as to when the value changes. Then you could simply attach a handler to your event/delegate from the view model class and easily update the exposed property whenever the actual property changes.
So it would go a little something like this... in your business class (I am assuming that your value is an int, but you can change this if it is incorrect... the principal is the same):
public delegate void FieldUpdate(int value);
public FieldUpdate OnFieldUpdate { get; set; }
...
private int field;
public int Field
{
get { return field; }
set
{
if (value != field)
{
field = value;
if (OnFieldUpdate != null) OnFieldUpdate(field);
}
}
}
Then in your view model:
private YourBusinessClass instance = new YourBusinessClass();
public YourBusinessClass Instance
{
get { return instance; }
set { instance = value; NotifyPropertyChanged("Instance"); }
}
Attach a handler:
instance.OnFieldUpdate += OnBusinessClassFieldUpdate;
...
public void OnBusinessClassFieldUpdate(int value)
{
Instance = value;
}
Now whenever the field is updated in the business class, the view model (and data bound UI controls) will automatically update via the delegate.

Pass a collection to viewmodel and return a selected item

I have a View / ViewModel where a ProductList is loaded. This list is not visible on the screen.
What I need to do is show a new View/ViewModel (e.g. SelectProductView / SelectProductViewModel), pass the ProductList to them, and after a user selects a particular Product, close this view, and make use of selected product.
What is the best way to achieve this?
I am using MVVMLight, but I guess the ideas should not be restricted just to it.
The easiest way is to create a view, and pass collection to it, but that doesn't sound MVVM friendly. I was thinking of creating a SelectProductViewModel from the first ViewModel and pass the collection to it, but I don't know how would I automatically create SelectProductView and bind it to created SelectProductViewModel.
Edit: in my application view structure is a bit complex. I have a main view, which basically needs to host a SelectProductView, since this view must cover whole screen. MainView contains lots of child and grandchild views (through tabs), so there could be 3 different child views or grand childViews that could issue a request for a product to be selected. Also, some view will not have products preloaded, so this task should probably be propagated to a SelectProductViewModel.
Example of Structure:
MainView
/ \
ChildViewA ChildViewB
/ \ / \
GrandChildViewA1 GrandChildViewA2 GrandChildViewB1 GrandChildViewB2
So, GrandChildViewA1, ChildViewB and GrandChildViewB2 could issue a request for a product to be selected. Only the view that issued a request should get the selected product, others should not bother with it. GrandChildViewA1 will have loaded products in it, but GrandChildViewB2 will not have ProductList loaded in it. This means, for performance sake, that GrandChildViewA1 should pass product list to SelectProductViewModel, while GrandCHildViewB2 will not have Product list in it, so SelectProductViewModel should fetch data from database.
I would create a generic viewModel which defines a contract for receiving data.
public abstract class PassDataViewModel<T> : ObservableObject
{
public T Data { get; }
}
I would then create a more general ViewModel for your product list like so:
public class SelectProductViewModel : PassDataViewModel<Product>
{
private Product _selectedProduct;
private ObservableCollection<Product> _products = new ObservableCollection<Product>();
public SelectProductViewModel(IList<Product> products)
{
_selectedProduct = _products.First();
}
public IEnumerable<Product> Products
{
get { return _products; }
}
public Product SelectedProduct
{
get { return _selectedProduct; }
set
{
_selectedProduct = value;
OnPropertyChanged("SelectedProduct");
OnPropertyChanged("Data");
}
}
public Product Data
{
get { return _selectedProduct; }
}
}
You would use this in the following way:
Your first viewModel can create an instance of the SelectProductViewModel (when a command is invoked, for example)
You pass your products list to the new SelectProductViewModel instance.
Use a DataTemplate to change the view on your screen (this post will show you how to do this).
Have a property in the parent viewModel that returns the product returned from the data property of the SelectProductViewModel (you will need to propagate the PropertyChanged event to your parent viewModel).
the most easy way is to go the viewmodel first approach and use a dialogservice to show the selection view.
your viewmodel with ProductionList simply call the dialogservice and put a ProductSelectionViewmodel with ProductionList as parameter. because this is viewmodel first you have to create a datatemplate so WPF knows how to render your ProductSelectionViewmodel.
here is a link for a simple dialogservice.
btw: in my opinion viewmodel first approach is much easier when doing mvvm.
EDIT:
in your ProductionListViewModel in your SelectProductCommand
var selectProductViewModel = new SelectProductViewModel(this.ProductionList);
var result = this.uiDialogService.ShowDialog("Select Product", selectProductViewModel );
//if result true, simple get the selected product
this.SelectedProduct = selectProductViewModel.MySelectedProduct;
thats all - simple and easy

How to use a factory for DataGrid.CanUserAddRows = true

I would like to use the DataGrid.CanUserAddRows = true feature. Unfortunately, it seems to work only with concrete classes which have a default constructor. My collection of business objects doesn't provide a default constructor.
I'm looking for a way to register a factory that knows how to create the objects for the DataGrid. I had a look at the DataGrid and the ListCollectionView but none of them seems to support my scenario.
The problem:
"I'm looking for a way to register a factory that knows how to create the objects for the DataGrid". (Because my collection of business objects doesn't provide a default constructor.)
The symptoms:
If we set DataGrid.CanUserAddRows = true and then bind a collection of items to the DataGrid where the item doesn't have a default constructor, then the DataGrid doesn't show a 'new item row'.
The causes:
When a collection of items is bound to any WPF ItemControl, WPF wraps the collection in either:
a BindingListCollectionView when the collection being bound is a BindingList<T>. BindingListCollectionView implements IEditableCollectionView but doesn't implement IEditableCollectionViewAddNewItem.
a ListCollectionView when the collection being bound is any other collection. ListCollectionView implements IEditableCollectionViewAddNewItem (and hence IEditableCollectionView).
For option 2) the DataGrid delegates creation of new items to the ListCollectionView. ListCollectionView internally tests for the existence of a default constructor and disables AddNew if one doesn't exist. Here's the relevant code from ListCollectionView using DotPeek.
public bool CanAddNewItem (method from IEditableCollectionView)
{
get
{
if (!this.IsEditingItem)
return !this.SourceList.IsFixedSize;
else
return false;
}
}
bool CanConstructItem
{
private get
{
if (!this._isItemConstructorValid)
this.EnsureItemConstructor();
return this._itemConstructor != (ConstructorInfo) null;
}
}
There doesn't seem to be an easy way to override this behaviour.
For option 1) the situation is a lot better. The DataGrid delegates creation of new items to the BindingListView, which in turn delegates to BindingList. BindingList<T> also checks for the existence of a default constructor, but fortunately BindingList<T> also allows the client to set the AllowNew property and attach an event handler for supplying a new item. See the solution later, but here's the relevant code in BindingList<T>
public bool AllowNew
{
get
{
if (this.userSetAllowNew || this.allowNew)
return this.allowNew;
else
return this.AddingNewHandled;
}
set
{
bool allowNew = this.AllowNew;
this.userSetAllowNew = true;
this.allowNew = value;
if (allowNew == value)
return;
this.FireListChanged(ListChangedType.Reset, -1);
}
}
Non-solutions:
Support by DataGrid (not available)
It would reasonable to expect the DataGrid to allow the client to attach a callback, through which the DataGrid would request a default new item, just like BindingList<T> above. This would give the client the first crack at creating a new item when one is required.
Unfortunately this isn't supported directly from the DataGrid, even in .NET 4.5.
.NET 4.5 does appear to have a new event 'AddingNewItem' that wasn't available previously, but this only lets you know a new item is being added.
Work arounds:
Business object created by a tool in the same assembly: use a partial class
This scenario seems very unlikely, but imagine that Entity Framework created its entity classes with no default constructor (not likely since they wouldn't be serializable), then we could simply create a partial class with a default constructor. Problem solved.
Business object is in another assembly, and isn't sealed: create a super-type of the business object.
Here we can inherit from the business object type and add a default constructor.
This initially seemed like a good idea, but on second thoughts this may require more work than is necessary because we need to copy data generated by the business layer into our super-type version of the business object.
We would need code like
class MyBusinessObject : BusinessObject
{
public MyBusinessObject(BusinessObject bo){ ... copy properties of bo }
public MyBusinessObject(){}
}
And then some LINQ to project between lists of these objects.
Business object is in another assembly, and is sealed (or not): encapsulate the business object.
This is much easier
class MyBusinessObject
{
public BusinessObject{ get; private set; }
public MyBusinessObject(BusinessObject bo){ BusinessObject = bo; }
public MyBusinessObject(){}
}
Now all we need to do is use some LINQ to project between lists of these objects, and then bind to MyBusinessObject.BusinessObject in the DataGrid. No messy wrapping of properties or copying of values required.
The solution: (hurray found one)
Use BindingList<T>
If we wrap our collection of business objects in a BindingList<BusinessObject> and then bind the DataGrid to this, with a few lines of code our problem is solved and the DataGrid will appropriately show a new item row.
public void BindData()
{
var list = new BindingList<BusinessObject>( GetBusinessObjects() );
list.AllowNew = true;
list.AddingNew += (sender, e) =>
{e.NewObject = new BusinessObject(... some default params ...);};
}
Other solutions
implement IEditableCollectionViewAddNewItem on top of an existing collection type. Probably a lot of work.
inherit from ListCollectionView and override functionality. I was partially successful trying this, probably can be done with more effort.
I've found another solution to this problem. In my case, my objects need to be initialized using a factory, and there isn't really any way to get around that.
I couldn't use BindingList<T> because my collection must support grouping, sorting, and filtering, which BindingList<T> does not support.
I solved the problem by using DataGrid's AddingNewItem event. This almost entirely undocumented event not only tells you a new item is being added, but also allows lets you choose which item is being added. AddingNewItem fires before anything else; the NewItem property of the EventArgs is simply null.
Even if you provide a handler for the event, DataGrid will refuse to allow the user to add rows if the class doesn't have a default constructor. However, bizarrely (but thankfully) if you do have one, and set the NewItem property of the AddingNewItemEventArgs, it will never be called.
If you choose to do this, you can make use of attributes such as [Obsolete("Error", true)] and [EditorBrowsable(EditorBrowsableState.Never)] in order to make sure no one ever invokes the constructor. You can also have the constructor body throw an exception
Decompiling the control lets us see what's happening in there.
private object AddNewItem()
{
this.UpdateNewItemPlaceholder(true);
object newItem1 = (object) null;
IEditableCollectionViewAddNewItem collectionViewAddNewItem = (IEditableCollectionViewAddNewItem) this.Items;
if (collectionViewAddNewItem.CanAddNewItem)
{
AddingNewItemEventArgs e = new AddingNewItemEventArgs();
this.OnAddingNewItem(e);
newItem1 = e.NewItem;
}
object newItem2 = newItem1 != null ? collectionViewAddNewItem.AddNewItem(newItem1) : this.EditableItems.AddNew();
if (newItem2 != null)
this.OnInitializingNewItem(new InitializingNewItemEventArgs(newItem2));
CommandManager.InvalidateRequerySuggested();
return newItem2;
}
As we can see, in version 4.5, the DataGrid does indeed make use of AddNewItem. The contents of CollectionListView.CanAddNewItem are simply:
public bool CanAddNewItem
{
get
{
if (!this.IsEditingItem)
return !this.SourceList.IsFixedSize;
else
return false;
}
}
So this doesn't explain why we we still need to have a constructor (even if it is a dummy) in order for the add row option to appear. I believe the answer lies in some code that determines the visibility of the NewItemPlaceholder row using CanAddNew rather than CanAddNewItem. This might be considered some sort of bug.
I had a look at IEditableCollectionViewAddNewItem and it seems to be adding this functionality.
From MSDN
The IEditableCollectionViewAddNewItem
interface enables application
developers to specify what type of
object to add to a collection. This
interface extends
IEditableCollectionView, so you can
add, edit, and remove items in a
collection.
IEditableCollectionViewAddNewItem adds
the AddNewItem method, which takes an
object that is added to the
collection. This method is useful when
the collection and objects that you
want to add have one or more of the
following characteristics:
The objects in the CollectionView are different types.
The objects do not have a default constructor.
The object already exists.
You want to add a null object to the collection.
Although at Bea Stollnitz blog, you can read the following
The limitation of not being able to add a new item when the source has no
default constructor is very well
understood by the team. WPF 4.0 Beta 2
has a new feature that brings us a
step closer to having a solution: the
introduction of
IEditableCollectionViewAddNewItem
containing the AddNewItem method. You
can read the MSDN documentation about
this feature. The sample in MSDN shows
how to use it when creating your own
custom UI to add a new item (using a
ListBox to display the data and a
dialog box to enter the new item).
From what I can tell, DataGrid doesn’t
yet use this method though (although
it’s a bit hard to be 100% sure
because Reflector doesn’t decompile
4.0 Beta 2 bits).
That answer is from 2009 so maybe it's usable for the DataGrid now
The simplest way I could suggest to provide wrapper for your class without default constructor, in which constructor for source class will be called.
For example you have this class without default constructor:
/// <summary>
/// Complicate class without default constructor.
/// </summary>
public class ComplicateClass
{
public ComplicateClass(string name, string surname)
{
Name = name;
Surname = surname;
}
public string Name { get; set; }
public string Surname { get; set; }
}
Write a wrapper for it:
/// <summary>
/// Wrapper for complicated class.
/// </summary>
public class ComplicateClassWraper
{
public ComplicateClassWraper()
{
_item = new ComplicateClass("def_name", "def_surname");
}
public ComplicateClassWraper(ComplicateClass item)
{
_item = item;
}
public ComplicateClass GetItem() { return _item; }
public string Name
{
get { return _item.Name; }
set { _item.Name = value; }
}
public string Surname
{
get { return _item.Surname; }
set { _item.Surname = value; }
}
ComplicateClass _item;
}
Codebehind.
In your ViewModel you need to create wrapper collection for your source collection, which will handle item adding/removing in datagrid.
public MainWindow()
{
// Prepare collection with complicated objects.
_sourceCollection = new List<ComplicateClass>();
_sourceCollection.Add(new ComplicateClass("a1", "b1"));
_sourceCollection.Add(new ComplicateClass("a2", "b2"));
// Do wrapper collection.
WrappedSourceCollection = new ObservableCollection<ComplicateClassWraper>();
foreach (var item in _sourceCollection)
WrappedSourceCollection.Add(new ComplicateClassWraper(item));
// Each time new item was added to grid need add it to source collection.
// Same on delete.
WrappedSourceCollection.CollectionChanged += new NotifyCollectionChangedEventHandler(Items_CollectionChanged);
InitializeComponent();
DataContext = this;
}
void Items_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if (e.Action == NotifyCollectionChangedAction.Add)
foreach (ComplicateClassWraper wrapper in e.NewItems)
_sourceCollection.Add(wrapper.GetItem());
else if (e.Action == NotifyCollectionChangedAction.Remove)
foreach (ComplicateClassWraper wrapper in e.OldItems)
_sourceCollection.Remove(wrapper.GetItem());
}
private List<ComplicateClass> _sourceCollection;
public ObservableCollection<ComplicateClassWraper> WrappedSourceCollection { get; set; }
}
And finally, XAML code:
<DataGrid CanUserAddRows="True" AutoGenerateColumns="False"
ItemsSource="{Binding Path=Items}">
<DataGrid.Columns>
<DataGridTextColumn Header="Name" Binding="{Binding Path=Name}"/>
<DataGridTextColumn Header="SecondName" Binding="{Binding Path=Surname}"/>
</DataGrid.Columns>
</DataGrid>
I just wanted to provide an alternate solution to using a BindingList. In my situtation, the Business objects was held in an IEntitySet in a portable project (Silverlight), which did not support IBindingList.
The solution, first and foremost, is to subclass the grid, and overwrite the coerce callback for CanUserAddRows to use IEditableCollectionViewAddNewItem:
public class DataGridEx : DataGrid
{
static DataGridEx()
{
CanUserAddRowsProperty.OverrideMetadata(typeof(DataGridEx), new FrameworkPropertyMetadata(true, null, CoerceCanUserAddRows));
}
private static object CoerceCanUserAddRows(DependencyObject sender, object newValue)
{
var dataGrid = (DataGrid)sender;
var canAddValue= (bool)newValue;
if (canAddValue)
{
if (dataGrid.IsReadOnly || !dataGrid.IsEnabled)
{
return false;
}
if (dataGrid.Items is IEditableCollectionViewAddNewItem v && v.CanAddNewItem == false)
{
// The view does not support inserting new items
return false;
}
}
return canAddValue;
}
}
And then use the AddingNewItem event to create the item:
dataGrid.AddingNewItem += (sender, args) => args.NewItem = new BusinessObject(args);
And if you care for the details, here is the reason why it is a problem in the first place. The coerce callback in the framework looks like this:
private static bool OnCoerceCanUserAddOrDeleteRows(DataGrid dataGrid, bool baseValue, bool canUserAddRowsProperty)
{
// Only when the base value is true do we need to validate that the user
// can actually add or delete rows.
if (baseValue)
{
if (dataGrid.IsReadOnly || !dataGrid.IsEnabled)
{
// Read-only/disabled DataGrids cannot be modified.
return false;
}
else
{
if ((canUserAddRowsProperty && !dataGrid.EditableItems.CanAddNew) ||
(!canUserAddRowsProperty && !dataGrid.EditableItems.CanRemove))
{
// The collection view does not allow the add or delete action
return false;
}
}
}
return baseValue;
}
You see how it gets the IEditableCollectionView.CanAddNew? That means that it only enables adding when the view can insert and construct an item. The funny thing is that when we want to add a new item, it checks the IEditableCollectionViewAddNewItem.CanAddNewItem instead, which only asks if the view supports inserting new items (not creating):
object newItem = null;
IEditableCollectionViewAddNewItem ani = (IEditableCollectionViewAddNewItem)Items;
if (ani.CanAddNewItem)
{
AddingNewItemEventArgs e = new AddingNewItemEventArgs();
OnAddingNewItem(e);
newItem = e.NewItem;
}

Resources