Why does Linq.Enumerable.Where break my ObservableCollection - wpf

Background:
I am writing a WPF application, strictly following the MVVM pattern. I have a BaseRepository class as a generic interface for connecting to different databases (EF is not an option), and everything works fine; this is just a technical question.
I use a wrapped ObservableCollection called NotifyingCollection, to subscribe to IEditableObject's ItemEndEdit events (my ViewModelBase entity wrapper implements INotifyPropertyChanged and IEditableObject members).
The provided code sample throws an "'EditItem' is not allowed for this view" exception when the ReadAll method is called upon editing an item in my WPF DataGrid. However, if I replace the line in the method with the commented out part, it works perfectly!
Question:
In other words, it looks like relaying the Linq.Enumerable.Where extension method instead of returning an IEnumerable version of the collection removes functionality from the custom collection; why would that happen if they are both IEnumerable?
Code Sample:
namespace MyCompany.Common.Abstracts
{
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Data.Common;
using System.Diagnostics;
using System.Linq;
using System.Linq.Expressions;
using MyCompany.Common.Extensions;
using MyCompany.Common.Utilities;
public abstract class BaseRepository<TEntity> : IDisposable where TEntity : ViewModelBase
{
protected BaseRepository()
{
this.EntitySet = new NotifyingCollection<TEntity>();
this.EntitySet.ItemEndEdit += new ViewModelBase.ItemEndEditEventHandler(ItemEndEdit);
this.EntitySet.CollectionChanged += new NotifyCollectionChangedEventHandler(CollectionChanged);
}
protected abstract NotifyingCollection<TEntity> EntitySet { get; set; }
protected virtual void PropertyChanged(object sender, PropertyChangedEventArgs e)
{
Debug.WriteLine(String.Format("Modify '{0}'", e.PropertyName), "PropertyChanged");
}
protected virtual void ItemEndEdit(IEditableObject sender)
{
this.Update(sender as TEntity);
}
protected virtual void CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
var collection = (e.Action == NotifyCollectionChangedAction.Remove) ?
e.OldItems : e.NewItems;
foreach (TEntity entity in collection)
{
switch (e.Action)
{
case NotifyCollectionChangedAction.Add:
entity.PropertyChanged += this.PropertyChanged;
this.Create(entity);
break;
case NotifyCollectionChangedAction.Remove:
entity.PropertyChanged -= this.PropertyChanged;
this.Delete(entity);
break;
default:
Debug.WriteLine(String.Format("{0} '{1}'", e.Action.ToString(), entity.DisplayName), "CollectionChanged");
break;
}
}
}
public virtual bool Create(TEntity entity)
{
Debug.WriteLine(String.Format("Create '{0}'", entity.DisplayName), "CollectionChanged");
return true;
}
public virtual IEnumerable<TEntity> Read(Expression<Func<TEntity, bool>> filter)
{
return this.EntitySet.Where(filter.Compile());
}
public virtual IEnumerable<TEntity> ReadAll()
{
return this.Read(x => true);
//return this.EntitySet;
}
public virtual bool Update(TEntity entity)
{
Debug.WriteLine(String.Format("Update '{0}'", entity.DisplayName), "ItemEndEdit");
return true;
}
public virtual bool Delete(TEntity entity)
{
Debug.WriteLine(String.Format("Delete '{0}'", entity.DisplayName), "CollectionChanged");
return true;
}
public virtual IEnumerable<TColumn> GetColumn<TColumn>(string columnName)
{
var lookupTable = this.Read(x => x != null);
List<TColumn> column = new List<TColumn>();
foreach (TEntity record in lookupTable)
{
column.Add(record.GetPropValue<TColumn>(columnName));
}
var result = column.Distinct();
foreach (TColumn element in result)
{
yield return element;
}
}
public abstract int Commit();
public abstract DbTransaction BeginTransaction();
public abstract void Dispose();
}
}

From MichaelLPerry's blog: Common mistakes while using ObservableCollection
ObservableCollection is imperative. Linq is declarative. The two
cannot be used together without extra help.
Imperative code explicitly acts upon something. When using an
ObservableCollection, you explicitly call Add, Remove, and other
methods to change the collection. You have to decide exactly when and
how to take these actions.
Declarative code implicitly generates something. When using linq, you
declare what a collection will look like, how it will be filtered,
mapped, and transformed. You don’t explicitly modify the collection.
These two paradigms don’t mix. Once you use linq on an
ObservableCollection, it is no longer observable. There are
open-source projects like Bindable Linq that bridge the gap. But
without that extra help, people are often surprised when things don’t
work.

The reurn value of EntitySet.Where method won't be the original NotifyingCollection<TEntity> anymore.

Related

Call to NotifyProportyChanged when adding items to List doesn't work, why?

I'm trying to understand why calling the function (code below...) of NotifyProportyChanged from AddNoteToList to update the view whenever item added to list isn't working.
It works great when I'm doing an assignment on the list, but if I'm trying to add items and then call manually the NotifyProportyChanged it doesn't.
I know I should use ObservableCollection to solve the problem, but I would like to know why this implementation I wrote is not doing the job.
public class MainWindowVM : INotifyPropertyChanged
{
public Model.MainWindowModel Model { get; set; }
public List<DataProtocol.Note> _notesListVM;
public List<DataProtocol.Note> NotesListVM
{
get
{
return _notesListVM;
}
set
{
_notesListVM = value;
NotifyProportyChanged("NotesListVM");
}
}
//dp:
public event PropertyChangedEventHandler PropertyChanged;
public void NotifyProportyChanged(string propName)
{
if (this.PropertyChanged != null)
this.PropertyChanged(this, new PropertyChangedEventArgs(propName));
}
//Command:
public RelayCommand AddNoteCommand { get; set; }
public void AddNoteToList(object parm)
{
string value = parm.ToString();
NotesListVM.Add(new DataProtocol.Note(value));
NotifyProportyChanged("NotesListVM");
}
public MainWindowVM()
{
Model = new PL.Model.MainWindowModel();
NotesListVM = Model.NotesList;
AddNoteCommand = new RelayCommand(AddNoteToList);
}
}
Even though you are raising PropertyChanged, the object instance NotesListVM hasn't actually changed, only its content has. WPF is optimized enough to realize this and do nothing.
If you really wanted to do it your way, you'd need create and assign a new list each time.
As you say, use ObservableCollection instead, which will fire CollectionChanged.
ItemsControl.ItemsSource is a dependency property, and will only register a change when you actually set the value to a different collection instance - sending a PropertyChanged event isn't sufficient.
As you noted, using an ObservableCollection is the correct way to have your bound U.I. controls detect that items have been added / removed from your list of items.

Implementing NotifyPropertyChanged without magic strings [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
typesafe NotifyPropertyChanged using linq expressions
I'm working on a large team application which is suffering from heavy use of magic strings in the form of NotifyPropertyChanged("PropertyName"), - the standard implementation when consulting Microsoft. We're also suffering from a great number of misnamed properties (working with an object model for a computation module that has hundreds of stored calculated properties) - all of which are bound to the UI.
My team experiences many bugs related to property name changes leading to incorrect magic strings and breaking bindings. I wish to solve the problem by implementing property changed notifications without using magic strings. The only solutions I've found for .Net 3.5 involve lambda expressions. (for example: Implementing INotifyPropertyChanged - does a better way exist?)
My manager is extremely worried about the performance cost of switching from
set { ... OnPropertyChanged("PropertyName"); }
to
set { ... OnPropertyChanged(() => PropertyName); }
where the name is extracted from
protected virtual void OnPropertyChanged<T>(Expression<Func<T>> selectorExpression)
{
MemberExpression body = selectorExpression.Body as MemberExpression;
if (body == null) throw new ArgumentException("The body must be a member expression");
OnPropertyChanged(body.Member.Name);
}
Consider an application like a spreadsheet where when a parameter changes, approximately a hundred values are recalculated and updated on the UI in real-time. Is making this change so expensive that it will impact the responsiveness of the UI? I can't even justify testing this change right now because it would take about 2 days worth of updating property setters in various projects and classes.
I did a thorough test of NotifyPropertyChanged to establish the impact of switching to the lambda expressions.
Here were my test results:
As you can see, using the lambda expression is roughly 5 times slower than the plain hard-coded string property change implementation, but users shouldn't fret, because even then it's capable of pumping out a hundred thousand property changes per second on my not so special work computer. As such, the benefit gained from no longer having to hard-code strings and being able to have one-line setters that take care of all your business far outweighs the performance cost to me.
Test 1 used the standard setter implementation, with a check to see that the property had actually changed:
public UInt64 TestValue1
{
get { return testValue1; }
set
{
if (value != testValue1)
{
testValue1 = value;
InvokePropertyChanged("TestValue1");
}
}
}
Test 2 was very similar, with the addition of a feature allowing the event to track the old value and the new value. Because this features was going to be implicit in my new base setter method, I wanted to see how much of the new overhead was due to that feature:
public UInt64 TestValue2
{
get { return testValue2; }
set
{
if (value != testValue2)
{
UInt64 temp = testValue2;
testValue2 = value;
InvokePropertyChanged("TestValue2", temp, testValue2);
}
}
}
Test 3 was where the rubber met the road, and I get to show off this new beautiful syntax for performing all observable property actions in one line:
public UInt64 TestValue3
{
get { return testValue3; }
set { SetNotifyingProperty(() => TestValue3, ref testValue3, value); }
}
Implementation
In my BindingObjectBase class, which all ViewModels end up inheriting, lies the implementation driving the new feature. I've stripped out the error handling so the meat of the function is clear:
protected void SetNotifyingProperty<T>(Expression<Func<T>> expression, ref T field, T value)
{
if (field == null || !field.Equals(value))
{
T oldValue = field;
field = value;
OnPropertyChanged(this, new PropertyChangedExtendedEventArgs<T>(GetPropertyName(expression), oldValue, value));
}
}
protected string GetPropertyName<T>(Expression<Func<T>> expression)
{
MemberExpression memberExpression = (MemberExpression)expression.Body;
return memberExpression.Member.Name;
}
All three methods meet at the OnPropertyChanged routine, which is still the standard:
public virtual void OnPropertyChanged(object sender, PropertyChangedEventArgs e)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
handler(sender, e);
}
Bonus
If anyone's curious, the PropertyChangedExtendedEventArgs is something I just came up with to extend the standard PropertyChangedEventArgs, so an instance of the extension can always be in place of the base. It leverages knowledge of the old value when a property is changed using SetNotifyingProperty, and makes this information available to the handler.
public class PropertyChangedExtendedEventArgs<T> : PropertyChangedEventArgs
{
public virtual T OldValue { get; private set; }
public virtual T NewValue { get; private set; }
public PropertyChangedExtendedEventArgs(string propertyName, T oldValue, T newValue)
: base(propertyName)
{
OldValue = oldValue;
NewValue = newValue;
}
}
Personally I like to use Microsoft PRISM's NotificationObject for this reason, and I would guess that their code is reasonably optimized since it's created by Microsoft.
It allows me to use code such as RaisePropertyChanged(() => this.Value);, in addition to keeping the "Magic Strings" so you don't break any existing code.
If I look at their code with Reflector, their implementation can be recreated with the code below
public class ViewModelBase : INotifyPropertyChanged
{
// Fields
private PropertyChangedEventHandler propertyChanged;
// Events
public event PropertyChangedEventHandler PropertyChanged
{
add
{
PropertyChangedEventHandler handler2;
PropertyChangedEventHandler propertyChanged = this.propertyChanged;
do
{
handler2 = propertyChanged;
PropertyChangedEventHandler handler3 = (PropertyChangedEventHandler)Delegate.Combine(handler2, value);
propertyChanged = Interlocked.CompareExchange<PropertyChangedEventHandler>(ref this.propertyChanged, handler3, handler2);
}
while (propertyChanged != handler2);
}
remove
{
PropertyChangedEventHandler handler2;
PropertyChangedEventHandler propertyChanged = this.propertyChanged;
do
{
handler2 = propertyChanged;
PropertyChangedEventHandler handler3 = (PropertyChangedEventHandler)Delegate.Remove(handler2, value);
propertyChanged = Interlocked.CompareExchange<PropertyChangedEventHandler>(ref this.propertyChanged, handler3, handler2);
}
while (propertyChanged != handler2);
}
}
protected void RaisePropertyChanged(params string[] propertyNames)
{
if (propertyNames == null)
{
throw new ArgumentNullException("propertyNames");
}
foreach (string str in propertyNames)
{
this.RaisePropertyChanged(str);
}
}
protected void RaisePropertyChanged<T>(Expression<Func<T>> propertyExpression)
{
string propertyName = PropertySupport.ExtractPropertyName<T>(propertyExpression);
this.RaisePropertyChanged(propertyName);
}
protected virtual void RaisePropertyChanged(string propertyName)
{
PropertyChangedEventHandler propertyChanged = this.propertyChanged;
if (propertyChanged != null)
{
propertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
public static class PropertySupport
{
// Methods
public static string ExtractPropertyName<T>(Expression<Func<T>> propertyExpression)
{
if (propertyExpression == null)
{
throw new ArgumentNullException("propertyExpression");
}
MemberExpression body = propertyExpression.Body as MemberExpression;
if (body == null)
{
throw new ArgumentException("propertyExpression");
}
PropertyInfo member = body.Member as PropertyInfo;
if (member == null)
{
throw new ArgumentException("propertyExpression");
}
if (member.GetGetMethod(true).IsStatic)
{
throw new ArgumentException("propertyExpression");
}
return body.Member.Name;
}
}
If you're concerned that the lambda-expression-tree solution might be too slow, then profile it and find out. I suspect the time spent cracking open the expression tree would be quite a bit smaller than the amount of time the UI will spend refreshing in response.
If you find that it is too slow, and you need to use literal strings to meet your performance criteria, then here's one approach I've seen:
Create a base class that implements INotifyPropertyChanged, and give it a RaisePropertyChanged method. That method checks whether the event is null, creates the PropertyChangedEventArgs, and fires the event -- all the usual stuff.
But the method also contains some extra diagnostics -- it does some Reflection to make sure that the class really does have a property with that name. If the property doesn't exist, it throws an exception. If the property does exist, then it memoizes that result (e.g. by adding the property name to a static HashSet<string>), so it doesn't have to do the Reflection check again.
And there you go: your automated tests will start failing as soon as you rename a property but fail to update the magic string. (I'm assuming you have automated tests for your ViewModels, since that's the main reason to use MVVM.)
If you don't want to fail quite as noisily in production, you could put the extra diagnostic code inside #if DEBUG.
Actually we discussed this aswell for our projects and talked alot about the pros and cons. In the end, we decided to keep the regular method but used a field for it.
public class MyModel
{
public const string ValueProperty = "Value";
public int Value
{
get{return mValue;}
set{mValue = value; RaisePropertyChanged(ValueProperty);
}
}
This helps when refactoring, keeps our performance and is especially helpful when we use PropertyChangedEventManager, where we would need the hardcoded strings again.
public bool ReceiveWeakEvent(Type managerType, object sender, System.EventArgs e)
{
if(managerType == typeof(PropertyChangedEventManager))
{
var args = e as PropertyChangedEventArgs;
if(sender == model)
{
if (args.PropertyName == MyModel.ValueProperty)
{
}
return true;
}
}
}
One simple solution is to simply pre-process all files before compilation, detect the OnPropertyChanged calls that are defined in set { ... } blocks, determine the property name and fix the name parameter accordingly.
You could do this using an ad-hoc tool (that would be my recommendation), or use a real C# (or VB.NET) parser (like those which can be found here: Parser for C#).
I think it's reasonable way to do it. Of course, it's not very elegant nor smart, but it has zero runtime impact, and follows Microsoft rules.
If you want to save some compile time, you could have both ways using compilation directives, like this:
set
{
#if DEBUG // smart and fast compile way
OnPropertyChanged(() => PropertyName);
#else // dumb but efficient way
OnPropertyChanged("MyProp"); // this will be fixed by buid process
#endif
}

Silverlight 4 LoadOperation returns null

LoadOperation on the client side returns null? How can I fix it? Is my code correct? Is it a best practice?
Serverside (Domain service:
public IQueryable<State> GetStates()
{
return this.ObjectContext.States.Include("Country") ;
}
//-----------------------------------------------------------------------
Clientside
LoadOperation<State> loadOp;
public IEnumerable<State> Entities()
{
DSCommon _context = new DSCommon();
loadOp = _context.Load(_context.GetStatesQuery());
loadOp.Completed += complete;
loadOp.Completed += new EventHandler(LoadOp_Completed);
return loadOp.Entities;
}
EventHandler complete;
void LoadOp_Completed(object sender, EventArgs e)
{
foreach (var item in loadOp.Entities)
{
/************* item.Country is Null ********************/
}
}
Your question is not very clear as first you say that LoadOperation return null whereas in your code, you state that item.Country is null.
However, I believe that I see the problem.
In you Domain Service you call the Include("Country") method on the States EntityCollection. However, on client side, the State.Country Entity is still null? I had the same issue some time ago. It seems that RIA Services (or WCF) does not return those entities, unless you apply the [Include] attribute on the Entity you want to return like so in a metadata class
[MetadataType(typeof(State.StateMetadata))]
public partial class State
{
internal sealed class StateMetadata
{
private StateMetadata()
{
}
[Include]
public EntityCollection<Country> Country;
}
}
Someone will probably be able to give an explanation on why it works this way. I just know that I had to do it this way around :-)

.NET delegate equality?

I think this is the question, anyway. I am using a RelayCommand, which decorates an ICommand with two delegates. One is Predicate for the _canExecute and the other is Action for the _execute method.
---Background motivation --
The motivation has to do with unit testing ViewModels for a WPF presentation. A frequent pattern is that I have one ViewModel that has an ObservableCollection, and I want a unit test to prove the data in that collection is what I expect given some source data (which also needs to be converted into a collection of ViewModels). Even though the data in both collections looks the same in the debugger, it looks like the test fails due to an equality failure on the ViewModel's RelayCommand. Here's an example of the failing unit test:
[Test]
public void Creation_ProjectActivities_MatchFacade()
{
var all = (from activity in _facade.ProjectActivities
orderby activity.BusinessId
select new ActivityViewModel(activity, _facade.SubjectTimeSheet)).ToList();
var models = new ObservableCollection<ActivityViewModel>(all);
CollectionAssert.AreEqual(_vm.ProjectActivities, models);
}
--- Back to delegate equality ----
Here is the code for the RelayCommand - it's basically a direct rip-off of Josh Smith's idea, with an implementation for equality that I added in an attempt to solve this issue:
public class RelayCommand : ICommand, IRelayCommand
{
readonly Action<object> _execute;
readonly Predicate<object> _canExecute;
/// <summary>Creates a new command that can always execute.</summary>
public RelayCommand(Action<object> execute) : this(execute, null) { }
/// <summary>Creates a new command which executes depending on the logic in the passed predicate.</summary>
public RelayCommand(Action<object> execute, Predicate<object> canExecute) {
Check.RequireNotNull<Predicate<object>>(execute, "execute");
_execute = execute;
_canExecute = canExecute;
}
[DebuggerStepThrough]
public bool CanExecute(object parameter) { return _canExecute == null ? true : _canExecute(parameter); }
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public void Execute(object parameter) { _execute(parameter); }
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != typeof(RelayCommand)) return false;
return Equals((RelayCommand)obj);
}
public bool Equals(RelayCommand other)
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return Equals(other._execute, _execute) && Equals(other._canExecute, _canExecute);
}
public override int GetHashCode()
{
unchecked
{
return ((_execute != null ? _execute.GetHashCode() : 0) * 397) ^ (_canExecute != null ? _canExecute.GetHashCode() : 0);
}
}
}
In a unit test where I've effectively set the _execute delegate to the same method (_canExecute is null in both cases), the unit test fails at this line:
return Equals(other._execute, _execute) && Equals(other._canExecute, _canExecute)
Debugger output:
?_execute
{Method = {Void <get_CloseCommand>b__0(System.Object)}}
base {System.MulticastDelegate}: {Method = {Void CloseCommand>b__0(System.Object)}}
?other._execute
{Method = {Void <get_CloseCommand>b__0(System.Object)}}
base {System.MulticastDelegate}: {Method = {Void CloseCommand>b__0(System.Object)}}
Can anyone explain what I am missing and what the fix is?
---- EDITED REMARKS ----
As Mehrdad pointed out, the get_CloseCommand from the debug session looks a bit weird at first. It really is just a property get, but it does raise the point as to why the equality of the delegate is problematic if I need to do tricks to make it work.
Some of the point of MVVM is to expose whatever might be useful in a presentation as properties, so you can use WPF binding. The particular class I was testing has a WorkspaceViewModel in it's heirarchy, which is just a ViewModel that already has a close command property. Here is the code:
public abstract class WorkspaceViewModel : ViewModelBase
{
/// <summary>Returns the command that, when invoked, attempts to remove this workspace from the user interface.</summary>
public ICommand CloseCommand
{
get
{
if (_closeCommand == null)
_closeCommand = new RelayCommand(param => OnRequestClose());
return _closeCommand;
}
}
RelayCommand _closeCommand;
/// <summary>Raised when this workspace should be removed from the UI.</summary>
public event EventHandler RequestClose;
void OnRequestClose()
{
var handler = RequestClose;
if (handler != null)
handler(this, EventArgs.Empty);
}
public bool Equals(WorkspaceViewModel other) {
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return Equals(other._closeCommand, _closeCommand) && base.Equals(other);
}
public override int GetHashCode() {
unchecked {
{
return (base.GetHashCode() * 397) ^ (_closeCommand != null ? _closeCommand.GetHashCode() : 0);
}
}
}
}
You can see that the close command is a RelayCommand, and that I monkeyed with equals to make the unit test work.
#Merhdad
Here is the unit test that only works when I use Trickster's delegate.Method in the equality comparison.
[TestFixture]
public class WorkspaceViewModelTests
{
private WorkspaceViewModel vm1;
private WorkspaceViewModel vm2;
private class TestableModel : WorkspaceViewModel
{
}
[SetUp]
public void SetUp() {
vm1 = new TestableModel();
vm1.RequestClose += OnWhatever;
vm2 = new TestableModel();
vm2.RequestClose += OnWhatever;
}
private void OnWhatever(object sender, EventArgs e) { throw new NotImplementedException(); }
[Test]
public void Equality() {
Assert.That(vm1.CloseCommand.Equals(vm2.CloseCommand));
Assert.That(vm1.Equals(vm2));
}
}
----- LATEST EDITS TO USE MERHDAD"S IDEA
debugger out put
?valueOfThisObject
{Smack.Wpf.ViewModel.RelayCommand}
base {SharpArch.Core.DomainModel.ValueObject}: {Smack.Wpf.ViewModel.RelayCommand}
_canExecute: null
_execute: {Method = {Void _executeClose(System.Object)}}
?valueToCompareTo
{Smack.Wpf.ViewModel.RelayCommand}
base {SharpArch.Core.DomainModel.ValueObject}: {Smack.Wpf.ViewModel.RelayCommand}
_canExecute: null
_execute: {Method = {Void _executeClose(System.Object)}}
?valueOfThisObject.Equals(valueToCompareTo)
false
This is the result after changing the code to:
public ICommand CloseCommand
{
get
{
if (_closeCommand == null)
_closeCommand = new RelayCommand(_executeClose);
return _closeCommand;
}
}
RelayCommand _closeCommand;
void _executeClose(object param) {
OnRequestClose();
}
Are you creating the delegate out of anonymous functions or something? These are the exact delegate equality rules according to C# specification (§7.9.8):
Delegate equality operators
Two delegate instances are considered equal as follows:
If either of the delegate instances is null, they are equal if and only if both are null.
If the delegates have different runtime type they are never equal.
If both of the delegate instances have an invocation list (§15.1), those instances are equal if and only if their invocation lists are the same length, and each entry in one’s invocation list is equal (as defined below) to the corresponding entry, in order, in the other’s invocation list.
The following rules govern the equality of invocation list entries:
If two invocation list entries both refer to the same static method then the entries are equal.
If two invocation list entries both refer to the same non-static method on the same target object (as defined by the reference equality operators) then the entries are equal.
Invocation list entries produced from evaluation of semantically identical anonymous-function-expressions with the same (possibly empty) set of captured outer variable instances are permitted (but not required) to be equal.
So, in your case, it's possible that the delegate instances are referring to the same method in two different objects, or referring to two anonymous methods.
UPDATE: Indeed, the problem is that you are not passing the same method reference when you are calling new RelayCommand(param => OnCloseCommand()). After all, the lambda expression specified here is actually an anonymous method (you are not passing a method reference to OnCloseCommand; you are passing a reference to an anonymous method which takes a single parameter and calls OnCloseCommand). As mentioned in the last line of the specification quotation above, it's not necessary that comparing those two delegates return true.
Side Note: The getter of the CloseCommand property would be simply called get_CloseCommand and not <get_CloseCommand>b__0. This is the compiler generated method name for the anonymous method inside get_CloseCommand method (the CloseCommand getter). This further proves the point I mentioned above.
I don't know anything now about other lines but what if
CollectionAssert.AreEqual(_vm.ProjectActivities, models);
fails just because ReferenceEquality is used?
You have overridden the comparison for RelayCommand but not for ObservableCollection.
And it looks like in case of Delegates Reference equality is used too.
Try to compare by Delegate.Method instead.

WinForms Interop, Drag & Drop from WinForms -> WPF

I'm trying to drag data from the Winforms portion of my application on a WPF controls that's contained inside an "ElementHost". And it crashes when I try doing so.
Trying the same thing but from Winforms to Winforms works fine. (See example code below)
I need help on making this work... have any clues what I'm doing wrong?
Thanks!
Example:
In the sample code below, I'm just trying to drag a custom MyContainerClass object created when initating the drag on the label control on a 1) System.Windows.Forms.TextBox (Winforms) and 2) System.Windows.TextBox (WPF, added to an ElementHost).
Case 1) works fine but case 2) is crashing when trying to retrieve the drop data using GetData(). GetDataPresent("WindowsFormsApplication1.MyContainerClass") returns "true" so In theory, I should be able to retrive my drop data of that type like in Winforms.
Here is the stack trace of the crash:
"Error HRESULT E_FAIL has been returned from a call to a COM component" with the following stack trace:
at System.Runtime.InteropServices.Marshal.ThrowExceptionForHRInternal(Int32 errorCode, IntPtr errorInfo)
at System.Windows.Forms.DataObject.GetDataIntoOleStructs(FORMATETC& formatetc, STGMEDIUM& medium)
at System.Windows.Forms.DataObject.System.Runtime.InteropServices.ComTypes.IDataObject.GetDataHere(FORMATETC& formatetc, STGMEDIUM& medium)
at System.Windows.Forms.DataObject.System.Runtime.InteropServices.ComTypes.IDataObject.GetData(FORMATETC& formatetc, STGMEDIUM& medium)
at System.Windows.DataObject.OleConverter.GetDataInner(FORMATETC& formatetc, STGMEDIUM& medium)
at System.Windows.DataObject.OleConverter.GetDataFromOleHGLOBAL(String format, DVASPECT aspect, Int32 index)
at System.Windows.DataObject.OleConverter.GetDataFromBoundOleDataObject(String format, DVASPECT aspect, Int32 index)
at System.Windows.DataObject.OleConverter.GetData(String format, Boolean autoConvert, DVASPECT aspect, Int32 index)
at System.Windows.DataObject.OleConverter.GetData(String format, Boolean autoConvert)
at System.Windows.DataObject.GetData(String format, Boolean autoConvert)
at System.Windows.DataObject.GetData(String format)
at WindowsFormsApplication1.Form1.textBox_PreviewDragEnter(Object sender, DragEventArgs e) in WindowsFormsApplication1\WindowsFormsApplication1\Form1.cs:line 48
Here is some code:
// -- Add an ElementHost to your form --
// -- Add a label to your form --
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
System.Windows.Controls.TextBox textBox = new System.Windows.Controls.TextBox();
textBox.Text = "WPF TextBox";
textBox.AllowDrop = true;
elementHost2.Child = textBox;
textBox.PreviewDragEnter += new System.Windows.DragEventHandler(textBox_PreviewDragEnter);
System.Windows.Forms.TextBox wfTextBox = new System.Windows.Forms.TextBox();
wfTextBox.Text = "Winforms TextBox";
wfTextBox.AllowDrop = true;
wfTextBox.DragEnter += new DragEventHandler(wfTextBox_DragEnter);
Controls.Add(wfTextBox);
}
void wfTextBox_DragEnter(object sender, DragEventArgs e)
{
bool dataPresent = e.Data.GetDataPresent("WindowsFormsApplication1.MyContainerClass");
// NO CRASH here!
object data = e.Data.GetData("WindowsFormsApplication1.MyContainerClass");
}
void textBox_PreviewDragEnter(object sender, System.Windows.DragEventArgs e)
{
bool dataPresent = e.Data.GetDataPresent("WindowsFormsApplication1.MyContainerClass");
// Crash appens here!!
// {"Error HRESULT E_FAIL has been returned from a call to a COM component."}
object data = e.Data.GetData("WindowsFormsApplication1.MyContainerClass");
}
private void label1_MouseDown(object sender, MouseEventArgs e)
{
label1.DoDragDrop(new MyContainerClass(label1.Text), DragDropEffects.Copy);
}
}
public class MyContainerClass
{
public object Data { get; set; }
public MyContainerClass(object data)
{
Data = data;
}
}
#Pedery & jmayor: Thanks for the suggestions guys! (see my findings below)
After quite a few experimentation, trials and errors, and a bit of "Reflector'ing", I managed to figure out exactly why I was receiving the cryptic error message "Error HRESULT E_FAIL has been returned from a call to a COM component".
It was due to the fact that when dragging data WPF <-> Winforms in a same app, that data has to be Serializable!
I've checked how difficult it would be to transform all of our classes to "Serializable" and I would have a been a real pain for a couple of reasons... one, we would need to practically make all of classes serializable and two, some of these classes have references to Controls! And Controls aren't serializable. So a major refactoring would have been needed.
So... since we wanted to pass any object of any class to drag from/to WPF inside the same application, I decided to create a wrapper class, with the Serializable attribute and implementing ISerializable. I would have 1 contructor with 1 parameter of type "object" which would be the actual drag data. That wrapper, when serializing/de-serializing, would serialize not the object itself... but rather the IntPtr to the object (which we can do since we only want that functionnality inside our 1 instance only application.) See code sample below:
[Serializable]
public class DataContainer : ISerializable
{
public object Data { get; set; }
public DataContainer(object data)
{
Data = data;
}
// Deserialization constructor
protected DataContainer(SerializationInfo info, StreamingContext context)
{
IntPtr address = (IntPtr)info.GetValue("dataAddress", typeof(IntPtr));
GCHandle handle = GCHandle.FromIntPtr(address);
Data = handle.Target;
handle.Free();
}
#region ISerializable Members
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
GCHandle handle = GCHandle.Alloc(Data);
IntPtr address = GCHandle.ToIntPtr(handle);
info.AddValue("dataAddress", address);
}
#endregion
}
To keep the IDataObject functionnality, I created the following DataObject wrapper:
public class DataObject : IDataObject
{
System.Collections.Hashtable _Data = new System.Collections.Hashtable();
public DataObject() { }
public DataObject(object data)
{
SetData(data);
}
public DataObject(string format, object data)
{
SetData(format, data);
}
#region IDataObject Members
public object GetData(Type format)
{
return _Data[format.FullName];
}
public bool GetDataPresent(Type format)
{
return _Data.ContainsKey(format.FullName);
}
public string[] GetFormats()
{
string[] strArray = new string[_Data.Keys.Count];
_Data.Keys.CopyTo(strArray, 0);
return strArray;
}
public string[] GetFormats(bool autoConvert)
{
return GetFormats();
}
private void SetData(object data, string format)
{
object obj = new DataContainer(data);
if (string.IsNullOrEmpty(format))
{
// Create a dummy DataObject object to retrieve all possible formats.
// Ex.: For a System.String type, GetFormats returns 3 formats:
// "System.String", "UnicodeText" and "Text"
System.Windows.Forms.DataObject dataObject = new System.Windows.Forms.DataObject(data);
foreach (string fmt in dataObject.GetFormats())
{
_Data[fmt] = obj;
}
}
else
{
_Data[format] = obj;
}
}
public void SetData(object data)
{
SetData(data, null);
}
#endregion
}
And we are using the above classes like this:
myControl.DoDragDrop(new MyNamespace.DataObject(myNonSerializableObject));
// in the drop event for example
e.Data.GetData(typeof(myNonSerializableClass));
I know I know... it's not very pretty... but it's doing what we wanted. We also created a dragdrop helper class which masks the DataObject creation and has templated GetData functions to retrieve the data without any cast... a bit like:
myNonSerializableClass newObj = DragDropHelper.GetData<myNonSerializableClass>(e.Data);
So thanks again for the replies! You guys gave me good ideas where to look at for possible solutions!
-Oli
I had a "similar" issue some time ago so I can at least tell you what I found out.
It seems .Net is resorting to OLE remoting when drag/drop operations are performed in but the simplest of cases. For some reason GetDataPresent will in these cases be successful and GetData will fail. This is furthermore mystified by the fact that there are several versions of the IDataObject in the .Net framework.
Windows Forms defaults to System.Windows.Forms.IDataObject. However, in your case you could try to give System.Runtime.InteropServices.ComTypes.IDataObject a shot instead. You can also check out my discussion here.
Hope this helps.
Seems wonderfull at first sight. I tried it but got some errors on implementations.
I began to correct some errors when I decided to look for something a little bit more simplier, that do not have pointers (humm I don't like that, particularly with carbage collection, but I have no idea if it could have real impact) and that do not use Interop.
I come up with that. It works for me and I hope it will work for anybody else. It is only intended to be used for local drag drop (inside the same app).
How to use to drag:
DragDrop.DoDragDrop(listBoxOfAvailableScopes, new DragDropLocal(GetSelectedSimulResultScopes()),
DragDropEffects.Copy);
How to use to drop (get):
DragDropLocal dragDropLocal = (DragDropLocal)e.Data.GetData(typeof(DragDropLocal));
SimulResultScopes simulResultScopes = (SimulResultScopes)dragDropLocal.GetObject();
Code:
namespace Util
{
[Serializable]
public class DragDropLocal
{
private static readonly Dictionary<Guid, object> _dictOfDragDropLocalKeyToDragDropSource = new Dictionary<Guid, object>();
private Guid _guid = Guid.NewGuid();
public DragDropLocal(object objToDrag)
{
_dictOfDragDropLocalKeyToDragDropSource.Add(_guid, objToDrag);
}
public object GetObject()
{
object obj;
_dictOfDragDropLocalKeyToDragDropSource.TryGetValue(_guid, out obj);
return obj;
}
~DragDropLocal()
{
_dictOfDragDropLocalKeyToDragDropSource.Remove(_guid);
}
}
}
Maybe the events are in the opposite way. The PreviewDragEnter should be related with the WPFTextBox. Also watch out the DragEventArgs class. There is one in System.Windows.Form ( Windows Form version) and the one under System.Windows( for WPF version).

Resources