5

Some background information:

  • I am using VS 2013
  • I created a Portable Class Library (Targets: .NET 4.5/Silverlight 5/Win Phone 8/Win Store 8)
  • I implemented the ICommand interface in my class named MyCommand.

MyCommand.cs:

public class MyCommand : ICommand
{
    public bool CanExecute(object parameter)
    {
        throw new NotImplementedException();
    }

    public void Execute(object parameter)
    {
        throw new NotImplementedException();
    }

    public event EventHandler CanExecuteChanged;
}

I found that when I attempted to reference use the MyCommand class in a WPF 4.5 application, I get the following error:

The type 'System.Windows.Input.ICommand' is defined in an assembly that is not referenced. You must add a reference to assembly 'System.Windows, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e, Retargetable=Yes'.

I'm not really sure why this is happening, or what I can do to resolve it appropriately. After scouring the internet, I found answers talking about adding a reference to System.Windows.dll 4.0.0.0 in my WPF application. Doing this allows me to compile and run the application, but my IDE complains that:

Interface member 'void System.Windows.Markup.IComponentConnector.Connect(in, object)' is not implemented.

This occurs for my MainWindow.cs class. Is there a better fix than to just deal with this bug so I'm not adding a reference to System.Windows.dll in a WPF application which really doesn't need it? And I say that it doesn't really need it because if I copy/paste the MyCommand class into the Wpf app it works fine. It only has an issue because I am attempting to use it as a portable class library.


UPDATE:

It seems that there is more to this than meets the eye. I created a new Wpf Application and used NuGet to reference the MvvmCross solution (since it has an MvxCommand object). When I do this, I get the same error.

David Kean's answer to a similar question suggests that this should be fixed via VS2012/VS2013 and if not, just reinstall/repair. I fully removed my VS installation and reinstalled it from scratch (VS2013) and still have this issue. So, is this truly a bug or did I do something wrong here?


UPDATE 2:

I attempted to see if I could assign an instance of the MyCommand class to ICommand: ICommand cmd = new MyCommand(); and received the following error:

Cannot implicitly convert type 'PortableClassLibrary1.MyCommand' to 'System.Windows.Input.ICommand'. An explicit conversion exists (are you missing a cast?)

For some reason the PCL does not seem to type forward the System.Windows.dll [2.0.5.0] ICommand to System.dll [4.0.0.0] ICommand for my desktop application... Ugh!


Update 3:

I uploaded my solution so that it is more visible as to what the problem is.


Update 4:

I've opened a Microsoft connect ticket on this issue.


Update 5:

After calming down from being upset about this not working... and others telling me that they don't get the same "interface" error. I realize that the "side-effect" of adding System.Windows.dll was a ReSharper 8.1 error. I guess it's time to complain to ReSharper instead of Microsoft. sigh

Community
  • 1
  • 1
myermian
  • 31,823
  • 24
  • 123
  • 215
  • Are you somehow accidentally referencing System.Windows version 2.0 in your project? Did you add a reference to the wrong .NET assembly when you created your project? – JDB Dec 12 '13 at 20:43
  • @JDB: Wpf applications do not need System.Windows (whether it is 2.0.5.0 or 4.0.0.0). The `ICommand` class lives in the `System.dll` assembly. – myermian Dec 12 '13 at 20:52
  • ICommand was moved to System.dll starting in .NET 3.0 (3.5 maybe?), I think. Before then, it was located in System.Windows. – JDB Dec 12 '13 at 20:56
  • Oh... PresentationCore is what I was thinking of: http://stackoverflow.com/questions/16772998/the-type-system-windows-input-icommand-exists-in-both-presentationcore-dll-a – JDB Dec 12 '13 at 20:59
  • @JDB: Yes. I agree, which is why I don't actually need `System.Windows.dll [2.0.5.0]` for my WPF application, which is why I am not referencing it (even though the compiler is telling me I have to). – myermian Dec 12 '13 at 21:00
  • 1
    Right... you don't need it, but if you were accidentally referencing it in your class library, then your ICommand may be referencing the wrong assembly. Have you tried fully-qualifing it and redeploying? – JDB Dec 12 '13 at 21:25
  • @JDB: I added a quick sample solution so that people can easily see what I am talking about. I didn't do anything fancy... just created a PCL selecting specific targets (.NET 4.5; Silverlight 5; Win Store 8; Win Phone 8), then I attempted to reference my PCL in a WPF app to use my ICommand implementation and it just doesn't want to compile correctly. – myermian Dec 12 '13 at 21:39
  • Right-click ICommand in your class library and select Go To Definition. Which ICommand definition are you looking at? In which assembly? You may need to fully-qualify ICommand to ensure it is using the correct assembly. (I don't have VS 2013, so I can't open your project.) – JDB Dec 12 '13 at 21:41
  • Your zip file is incomplete mate, the WpfApplication is not there... could you include it? – Stefan Z Camilleri Dec 13 '13 at 15:53
  • @StefanZCamilleri: You are correct. I updated my upload. – myermian Dec 13 '13 at 16:50
  • I managed to solve it for you mate, I'll populate it in an answer below. – Stefan Z Camilleri Dec 13 '13 at 19:15

3 Answers3

6

You must add a reference to assembly 'System.Windows, Version=2.0.5.0

The advice is excellent, the message is not that great. Clearly you got baffled by the version number. Right-click your WPF project, Add Reference and tick System.Windows. Which solves your problem.

The missing magic is this line in the System.Windows.dll reference assembly:

  [assembly: TypeForwardedTo(typeof(ICommand))]

Which gets ICommand forward from System.Windows.dll to System.dll

Keep in mind that System.Windows.dll from the c:\program files (x86)\reference assemblies subdirectory is just a reference assembly. It doesn't contain any code or types at all, just [TypeForwardedTo] attributes. It acts as an "adapter", bridging the gap between different .NET framework platforms. The final executable doesn't actually have a dependency on System.Windows.dll at all.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • +1 agree this is the right solution, but if I recall correctly OP indicated he didn't want to add the dll. – chue x Dec 13 '13 at 17:22
  • It is not an option, he must add the **reference assembly**. It is just a reference assembly, it doesn't contain *any* code or types at all. Just [TypeForwardTo] attributes. Think of it as an "adapter". – Hans Passant Dec 13 '13 at 17:25
  • Whether I add a reference to `System.Windows.dll [2.0.5.0]` or `System.Windows.dll [4.0.0.0]`, both produce a negative side-effect: Visual Studio complains that my XAML Windows are not implementing a required interface: `Interface member 'void System.Windows.Markup.IComponentConnector.Connect(in, object)' is not implemented.` – myermian Dec 13 '13 at 19:22
  • @m-y - in my testing I never saw the interface member error (that doesn't mean it doesn't exist). My WPF app is the default one generated from VS. – chue x Dec 13 '13 at 19:36
  • Wow, did you ever ask the wrong question. I only know how to troubleshoot your sample project, it doesn't have a problem with IComponentConnector. – Hans Passant Dec 13 '13 at 19:38
  • I am marking this answer as correct. It turns out that in adding a reference to the assembly I am only adding the reference assembly (not the full assembly). It turns out that after I suspended ReSharper 8.1 the error about an interface needing to be implemented went away. I still don't like the idea of having to add even a reference assembly, but I guess there's nothing I can do about that. Basically, I was an idiot and let a ReSharper bug confound me. :( – myermian Dec 13 '13 at 19:41
  • Sorry guys, this may seem confusing, but this is not correct. There is no 'missing magic'. System.Windows v2.0.5.0 correctly has an ICommand, and therefore putting in a TypeForwardedTo in it would be incorrect. System.Window v4.0.0.0 HAS a TypeForwardedTo, referencing ICommand in System v4.0.0.0.. which is also correct. The problem here is that .NET Portable Subset uses System.Windows v2.0.5.0, so that is where MSBuild will go to look for it... see my answer below. – Stefan Z Camilleri Dec 13 '13 at 19:44
  • Hmm, no, that does not help. PCL reference assemblies have .NETCore version numbers. – Hans Passant Dec 13 '13 at 19:45
  • @m-y i did actually point the ReSharper issue to you in my answer below ;) – Stefan Z Camilleri Dec 13 '13 at 19:46
1

This is not exactly a bug, it is more about what's included in the .NET Portable Subset. MSBuild is correct in complaining.

If you look at the manifest of PortableClassLibrary, you will see that an extern reference to System.Windows is actually made.

.assembly extern retargetable System.Windows
{
  .publickeytoken = (7C EC 85 D7 BE A7 79 8E )                         // |.....y.
  .ver 2:0:5:0
}

And if you check what is actually contained in .NETPortable, you'll find that the included System assembly is v2.0.5.0

You can find it here -> C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETPortable\v4.0\Profile\Profile158\

...as is System.Windows at v2.0.5.0

So technically speaking, MSBuild is correct in asking for System.Windows, since this is not included explicitly in a build for WPF.

Although the TypeForwarding argument is interesting, it would still be moot, since at v2.0.5.0, there was no type forwarding to be done.

Now, if you actually look at System.Windows v4.0.0.0, there IS a TypeForwardedTo rule for ICommand (use reflector)

So the question here is more of a design issue, more than anything. System.Windows conflicts with WPF, yet this is only due to the other implementation of Window.

So to fix this, reference the v2.0.5.0 System.Windows in C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETPortable\v4.0\Profile\Profile158\System.Windows.dll (I would take a copy of it for this project).

Your last step is to resolve the type ambiguity that occurs because of this... you'll get a type ambiguity between System v4.0.0.0 and System.Windows v2.0.5.0 for the use of ICommand

You can solve this by removing System.Windows from the 'global' alias (hit F4 on the reference), and add in a custom alias, ex. SomeAlias

Then just reference it via it's alias.

extern alias SomeAlias;

public partial class MainWindow : Window
{
    private SomeAlias::System.Windows.Input.ICommand _command;
    ...etc...

Voila.. this was really interesting, so I've detailed it a bit more here, where I could include screenshots (and talk about the ReSharper hiccup)

Stefan Z Camilleri
  • 4,016
  • 1
  • 32
  • 42
0

are you referencing System.dll?

ICommand

Supported in: Portable Class Library

No need to reference System.Windows.dll in your PCL, just add it in the WPF project.

Test solution

Dmitry Ledentsov
  • 3,620
  • 18
  • 28
  • I am referencing the `System.dll [4.0.0.0]` assembly. The problem is that Visual Studio insists that if I use the `MyCommand` class that I need to reference `System.Windows.dll [2.0.5.0]` assembly in order to use `ICommand`. – myermian Dec 12 '13 at 20:54
  • Tried to reproduce here - everything works fine in VS 2013, referencing automatically the .Net Portable Subset – Dmitry Ledentsov Dec 12 '13 at 21:02
  • Care to zip up your solution and upload it somewhere? I'd love to compare it to my solution and see what is different. – myermian Dec 12 '13 at 21:04
  • added a test solution – Dmitry Ledentsov Dec 12 '13 at 21:27
  • You're upload only contained one project, a PCL which targeted .NET 4.5; Win Store 8; Win Phone 8. I was attempting to also target Silverlight 5, then use the PCL in a WPF application. – myermian Dec 12 '13 at 21:34
  • Now I see what you mean. I can reproduce it. It might be a bug. Now, [System.Windows](http://msdn.microsoft.com/en-us/library/system.windows(v=vs.110).aspx) is meant for WPF. If you add the reference to System.Windows to your WPF application, you're not endangering the PCL. Added the new solution – Dmitry Ledentsov Dec 13 '13 at 06:22