How to use class from other files in C# with visual studio? - c#

I am a newbie of C# and MS visual studio, and I want to use the C# class which defined in another file, but can't get it work.
Here is the program.cs(and why can't I rename that file ?)
using System;
namespace TestCSharp2
{
class Program
{
static void Main(string[] args)
{
Class2 class2 = new Class2();
// here the IDE will complain that cant find namespace or balabala..
class2.setValue(10);
Console.WriteLine(class2.getValue().ToString());
Console.ReadKey();
}
}
}
And here is the Class2 that I want to use in file Class2.cs:
namespace TestCSharp2
{
class Class2
{
int i;
public void setValue(int i)
{
this.i = i;
}
public int getValue()
{
return this.i;
}
}
}
Should I #include or something? isn't use namespace enough?
As some guys asked if they are in the same assembly/same project, I presume they were, because here is the procedure how they are created:
A new project using the template of Console C# Project, then the program.cs was created by default.
The Class2.cs was created with [File] -> [New] -> [File] -> [C# class] and saved in the same folder where program.cs lives.
To be honest, I don't know if they are in same assembly / same project, but I guess they were.

According to your explanation you haven't included your Class2.cs in your project. You have just created the required Class file but haven't included that in the project.
The Class2.cs was created with [File] -> [New] -> [File] -> [C# class] and saved in the same folder where program.cs lives.
Do the following to overcome this,
Simply Right click on your project then -> [Add] - > [Existing Item...] : Select Class2.cs and press OK
Problem should be solved now.
Furthermore, when adding new classes use this procedure,
Right click on project -> [Add] -> Select Required Item (ex - A class, Form etc.)

Yeah, I just made the same 'noob' error and found this thread.
I had in fact added the class to the solution and not to the project.
So it looked like this:
Just adding this in the hope to be of help to someone.

It would be more beneficial for us if we could see the actual project structure, as the classes alone do not say that much.
Assuming that both .cs files are in the same project (if they are in different projects inside the same solution, you'd have to add a reference to the project containing Class2.cs), you can click on the Class2 occurrence in your code that is underlined in red and press CTRL + . (period) or click on the blue bar that should be there. The first option appearing will then add the appropriate using statement automatically. If there is no such menu, it may indicate that there is something wrong with the project structure or a reference missing.
You could try making Class2 public, but it sounds like this can't be a problem here, since by default what you did is internal class Class2 and thus Class2 should be accessible if both are living in the same project/assembly. If you are referencing a different assembly or project wherein Class2 is contained, you have to make it public in order to access it, as internal classes can't be accessed from outside their assembly.
As for renaming: You can click Program.cs in the Solution Explorer and press F2 to rename it. It will then open up a dialog window asking you if the class Program itself and all references thereof should be renamed as well, which is usually what you want. Or you could just rename the class Program in the declaration and again open up the menu with the small blue bar (or, again, CTRL+.) and do the same, but it won't automatically rename the actual file accordingly.
Edit after your question edit: I have never used this option you used, but from quick checking I think that it's really not inside the same project then. Do the following when adding new classes to a project: In the Solution Explorer, right click the project you created and select [Add] -> [Class] or [Add] -> [New Item...] and then select 'Class'. This will automatically make the new class part of the project and thus the assembly (the assembly is basically the 'end product' after building the project). For me, there is also the shortcut Alt+Shift+C working to create a new class.

namespace TestCSharp2
{
**public** class Class2
{
int i;
public void setValue(int i)
{
this.i = i;
}
public int getValue()
{
return this.i;
}
}
}
Add the 'Public' declaration before 'class Class2'.

According to your example here it seems that they both reside in the same namespace. I conclude that they are both part of the same project (if you haven't created another project with the same namespace)
and all classes by default are defined as internal to the project they are defined in, if haven't declared otherwise, therefore I guess the problem is that your file is not included in your project.
You can include it by right clicking the file in the solution explorer window => Include in project, if you cannot see the file inside the project files in the solution explorer then click the show the upper menu button of the solution explorer called show all files (just hover your mouse cursor over the button there and you'll see the names of the buttons).
Just for basic knowledge:
If the file resides in a different project\ assembly then it has to be defined,
otherwise it has to be defined at least as internal or public.
In case your class is inheriting from that class that it can be protected as well.

I was having the same problem here. Found out that the problem was with an Advanced Property of the file. There is there an option with the name 'Compilation Action' (may be not with the exact words, I am translating - my VS is in Portuguese).
My Class1.cs file was there as "Content" and I just had to change it to "Compile" to make it work, and have the classes recognized by the others files in the same project.

Just make two projects in two different files then rename the "Program.cs" of one of the two files
and copy it then paste it next to the Program.cs of the other file and that's it.

In your project there will be a file with .csproj extension.
Double click on it to open the project in the Visual Studio. Otherwise, if you make a new class, it won't link with other classes.

When u diclare your , var
you , can use private , declarasion
using System;
private Class class;

Related

No entry sign in visual studio

Does anybody know what this sign means?
You're looking at a Debug Watch or Quick Watch Window similar to this one:
The stop sign is added when the member you're watching is marked as internal. Each access modifier has its own indicator. As you can see from the picture and the code that belongs to it:
static void Main(string[] args)
{
var test = new Test();
// put breakpoint here
}
public class Test : TestBase
{
internal int SomeNumber;
protected int FooNumber;
}
public abstract class TestBase
{
internal int AbstractInternalSomeInt;
public int OtherInt;
private byte SomeByte;
}
Notice that in the class view and in the Solution Explorer the symbol for internal members is different, it shows a heart instead:
I came across this post when searching for "visual studio solution explorer no entry symbol". In my case the symbol was presented when using the file view of solution explorer rather than class view. It turned out this was because my gitignore file had an exclusion to all files "*.userprefs" and I'd added project called "userprefs" - what are the odds!
Easy way to fix - right click the files in solution explorer and choose "Add ignored file to source control". Would be worth checking that this makes the desired change to the .gitignore file
In files view, I think it indicates the file is excluded from the build.
Maybe (as in my case) the file is directly included into something that is part of the build.
Look at properties > Excluded from build

Class cannot find another class in the same namespace

I have a C# WebApp that we are doing for a client. I have two classes in the project, defined (in separate files) as such...
A general utility library:
namespace Client.WebApp {
public static class General {
public static MyDbClass GetDB() {
//<creates and returns MyDbClass here>
}
}
}
A PageBase class:
namespace Client.WebApp {
public class PageBase : System.Web.UI.Page {
protected MyDbClass dbo { get; set; }
public PageBase() {
dbo = General.GetDB();
}
}
}
When I try to compile, I get the error from the dbo = General.GetDB(); line:
The name 'General' does not exist in the current context Client.WebApp.
I have double-checked that the namespace is spelled right in both files.
I have tried adding the top-level namespace Client.WebApp as a using directive in the pagebase file.
I have tried fully qualifying the name as in dbo = Client.WebApp.General.GetDB();
Nothing has helped and it insists that my General class does not exist.
Funny thing is that while the build hits this error and stops, the code-editor does not see this error, and the statement does not get red-under-squiggled.
The project is targeting Framework v.4.5.2, and I am working in VS 2015.
It is a strange error, in my VS2015 if I set a file Build Action to anything other than "Compile", I get an error underline on any type for that file.
Anyway the solution here is to verify that the Build Action is set to "Compile", I'm not sure why adding a new file would have set the build action to anything other than "Compile". I've also tested trying to add new files in multiple ways (select a text file template and just name it something.cs), it still sets it as "Compile". You should verify that your VS2015 instance is updated with the latest updates.
I had the same problem: "type or namespace could not be found". It turned out that class was in a file with the "Build Action" property set to "None", meaning the file was not being compiled. I set it to "C# Compiler", that solved it.
This happens to me sometimes. Closing visual studio and opening it again always fixes it for me.
I think I might have figure it out that if we create a file in a folder which suppose to have content files it set that file's build type content automatically. In my Case I create a file under app_code folder and it is a class file but the build type is set to Content which make it unavailable for any other classes i have.
May be it has any other reasons too.
Try to create a new Class in the Project folder and then move it to the folder, you want it to be.

Invalid Resx file. Could not load type error why?

I'm getting designer error on code:
The Component i'm willing to define a List of properties for:
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows.Forms;
namespace TestProjectForProperty.Test
{
public class MyTreeView : TreeView
{
private List<TypeDescriptorBase> _descriptorsAvailable = new List<TypeDescriptorBase>();
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public List<TypeDescriptorBase> DescriptorsAvailable
{
get { return _descriptorsAvailable; }
set { _descriptorsAvailable = value; }
}
}
}
The Descriptor itself:
using System;
namespace TestProjectForProperty.Test
{
[Serializable]
public class TypeDescriptorBase
{
public string Name { get; set; }
public override string ToString()
{
return Name;
}
}
}
I am getting the following error if i try to use the component for example on a form and add any items on the property sheet or in the component's constructor to the DescriptorsAvailable property
Error 1 Invalid Resx file. Could not load type
System.Collections.Generic.List`1[[TestProjectForProperty.Test.TypeDescriptorBase,
TestProjectForProperty, Version=1.0.0.0, Culture=neutral,
PublicKeyToken=null]], mscorlib, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089 which is used in the .RESX file.
Ensure that the necessary references have been added to your project.
Line 134, position 5. ...\visual studio
2010\Projects\TestProjectForProperty\TestProjectForProperty\Form1.resx 134 5 TestProjectForProperty
In the Resx file there is data field with base64 encoded stuff inside when this error is present.
I have been searching for an answer, but the best i got is to restart everything, it didn't help me, do you guys have any suggestions? I'm using .net 4 client and visual studio 2010
In my experience, this is due to a change of version of a referenced library, or a change of the lib itself, which contains the backing type of a property you have defined in your user control. The solution is to "force" the visual studio designer to re-initialize it's designer code for that type, and not expect to retrieve a "canned" version of it from the .resx file of the control.
1) Delete the offending data section in the .resx file of your control. This will be a section in the xml of the .resx file associated with your user control, which has a node: <data></data> - the name attribute will be set to whatever you've named that object in the properties of whatever you added this type to. The <data>/data> section contains a base64 encoded string that is the encoded form of the name and version of the library the type comes from. This is where the problem ism, because it now contains an encoded version of the library and/or version number you are no longer referencing in order to include the type. Delete the entire <data>/data> section, from opening to closing tag, save the change and close the file. Now the "artifact" is gone.
2) Now find the place in the designer file for your control, where the type is instantiated; this is initialization code generated for you by visual studio, and it is the place that is expecting to load a "canned" definition of the type from the base64 encoded string contained within the .resx file. The line will look something like this:
this.myCtrlFoo.MyPropertyFroo = ((MyNamespaceFoo.MyTypeFoo)(resources.GetObject("myCtrlFoo.MyPropertyFroo")));
...now just replace the resources.GetObjec call with the instantiation of a new instance of the appropriate type like so:
this.myCtrlFoo.MyPropertyFroo = ((MyNamespaceFoo.MyTypeFoo)(new MyNamespaceFoo.MyTypeFoo()));
...now save the change to the file, close it, rebuild, and everything should now build & run OK.
Put the MyTreeView and TypeDescriptorBase classes into another project and reference it from your GUI project will resolve the issues.
I'm not sure why exactly the problem occurs - I guess it has something to do with the way the serializing process is generating the base64 string for the DescriptorsAvailable Property. Maybe somebody else can give us some insight.
I've struggled quite a bit with this; I have three user controls that all expose the same non-designer property, but for some reason, any change to two of the three would instantly cause the next build to fail with this same issue. This is in VS 2015.
I wound up having to add the following two attributes to the property that kept expanding in the resx file, and it hasn't occurred since. It works for me because they're not available in the designer anyway.
[Browsable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
For me, this error occured when I used a custom class as a property for the user control. When I switched from property to traditional get- and set- methods, the error disappeared. I guess this is because properties are already compiled at design-time, so when you build the whole project, a new version of the custom class is compiled which is separate from the one of the control, and the reference is broken.
For me, with the custom class Inventory, all I had to do was to switch from this property-based approach:
public Inventory Resources {get;set;}
to this method-based approach:
private Inventory resources;
public Inventory getResources() { return resources; }
public void setResources(Inventory newResources) { resources = newResources; }
I hope this helps someone, as I've been spending some hours on figuring it out.
In my case I've got the error : "error MSB3103: Invalid Resx file. The specified module could not be found" executed in a light windows container based on mcr.microsoft.com/powershell instead of mcr.microsoft.com/windows:1909 (was working fine on 1909).
The error was on a ressource icon that was compressed with PNG inside.
It can be checked by opening the ressource on visual studio : Project > Properties > Ressources.resx, select icons, double click on the icon, check the end of the title that is either "..,BMP]" or "...,PNG]").
Updating the icon with an uncompressed format solve the "Invalid Resx file" issue.
I stumbled across this question today whilst looking for the solution to a similar issue.
Unfortunately none of the above worked for me, however my issue turned out to be that I had different versions of the .NET Framework for different projects. For example;
Project A - .NET Framework 4.7.2
Project B - .NET Framework 4
Where Project B was referencing Project A. Solution was simply to change the .NET Framework version of Project B to 4.7.2 (in my case) and hey presto the issue was resolved.
A shame Visual Studio doesn't provide a more helpful error message in this case, but something to look out for!

The component does not have a resource identified by the uri

I want to create a Generic DataGrid to use on all my Views/UserControls.
This is my structure:
Class Library called "Core":
Class called "ViewBase":
public class ViewBase : UserControl
{
public ViewBase()
{
}
//Rest of Methods and Properties
}
Class Library called "Controls":
UserControl Called "GridView":
XAML:
<vb:ViewBase x:Class="Controls.GridView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vb="clr-namespace:Core;assembly=Core">
<Grid>
<DataGrid></DataGrid>
</Grid>
</vb:ViewBase>
Code Behind:
using Core;
public partial class GridView : ViewBase
{
public GridView ()
{
InitializeComponent();
}
}
Then is the WPF Aplication called "WPFApp":
Class called "View":
using Controls;
public class View : GridView
{
public View()
{
InitializeComponent();
}
}
My whole idea is to use GridView where i need a DataGrid.
When i run the application i get this error:
"The component 'WpfApp.View' does not have a resource identified by the URI '/Controls;component/GridView.xaml'."
What am i doing wrong?
Is this the correct approach or am i way off?
Frustratingly, I had exactly this error and spent forever trying to work out the cause. For me, it was once working but then I made some very minor changes to the XAML of the derived control, and the compiler started giving that error message.
Short solution, cutting out many hours of trying to figure it out: shut down Visual Studio and re-opened it, recompiled, problem magically went away! (This is VS2012 Pro)
Just added this in case anyone reading is going round in circles trying to find a non-existent problem with their code. Might be worth trying the "IT Crowd solution" first.
This gave me headaches for 3 days! I have a XAML UserControl in a class library and a class (only C#) that derives from the UserControl in my .exe project.
In xaml designer of my MainWindow.xaml and when starting the application, I got the error "component does not have a resource identified by the uri".
The answer of "Juan Carlos Girón" finally lead me to the solution:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Navigation;
using System.Reflection;
using System.IO.Packaging;
using System.Windows.Markup;
namespace ClassLibrary1
{
static class Extension
{
public static void LoadViewFromUri(this UserControl userControl, string baseUri)
{
try
{
var resourceLocater = new Uri(baseUri, UriKind.Relative);
var exprCa = (PackagePart)typeof(Application).GetMethod("GetResourceOrContentPart", BindingFlags.NonPublic | BindingFlags.Static).Invoke(null, new object[] { resourceLocater });
var stream = exprCa.GetStream();
var uri = new Uri((Uri)typeof(BaseUriHelper).GetProperty("PackAppBaseUri", BindingFlags.Static | BindingFlags.NonPublic).GetValue(null, null), resourceLocater);
var parserContext = new ParserContext
{
BaseUri = uri
};
typeof(XamlReader).GetMethod("LoadBaml", BindingFlags.NonPublic | BindingFlags.Static).Invoke(null, new object[] { stream, parserContext, userControl, true });
}
catch (Exception)
{
//log
}
}
}
}
and called that from by UserControl's .cs file:
namespace ClassLibrary1
{
public partial class MyUserControl : UserControl
{
public MyUserControl()
{
//InitializeComponent();
this.LoadViewFromUri("/ClassLibrary1;component/myusercontrol.xaml");
}
}
}
Thanks again to "Juan Carlos Girón"!
The reason you are getting this error is because the way InitializeComponent that is implemented (in VS 2010) will always search in the derived class's assembly.
Here is InitializeComponent:
/// <summary>
/// InitializeComponent
/// </summary>
[System.Diagnostics.DebuggerNonUserCodeAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("PresentationBuildTasks", "4.0.0.0")]
public void InitializeComponent() {
if (_contentLoaded) {
return;
}
_contentLoaded = true;
System.Uri resourceLocater = new System.Uri("/WpfApplication1;component/mainwindow.xaml", System.UriKind.Relative);
#line 1 "..\..\..\MainWindow.xaml"
System.Windows.Application.LoadComponent(this, resourceLocater);
#line default
#line hidden
}
The line where it looks up your XAML resource is System.Windows.Application.LoadComponent(this, resourceLocator). And this most probably fails because equivalent of 'this.GetType().Assembly' is used to determine which assembly to search for the resource identified by the relative Uri. And 'this.GetType()' does get the derived type of the object, not the type of the class where the code is implemented.
PS. Is this a bug? I do not know...
You can try this approach
I created my own InitializeComponent() and I called this way
this.LoadViewFromUri("/NameOfProject;component/mainwindow.xaml");
public static void LoadViewFromUri(this Window window, string baseUri)
{
try
{
var resourceLocater = new Uri(baseUri, UriKind.Relative);
var exprCa = (PackagePart)typeof(Application).GetMethod("GetResourceOrContentPart", BindingFlags.NonPublic | BindingFlags.Static).Invoke(null, new object[] { resourceLocater });
var stream = exprCa.GetStream();
var uri = new Uri((Uri)typeof(BaseUriHelper).GetProperty("PackAppBaseUri", BindingFlags.Static | BindingFlags.NonPublic).GetValue(null, null), resourceLocater);
var parserContext = new ParserContext
{
BaseUri = uri
};
typeof(XamlReader).GetMethod("LoadBaml", BindingFlags.NonPublic | BindingFlags.Static).Invoke(null, new object[] { stream, parserContext, window, true });
}
catch (Exception)
{
//log
}
}
I was doing something very similar with the same result. I had one C# class library that contained a WPF control called UsageControl (xaml with accompanying xaml.cs file). In a separate C# project(i.e. separate dll) I created a C# class CPUUsageControl which inherited from UsageControl, but put its own spin on it. When I tried to use the CpuUsageControl on one of my views I got the same error you did.
What I did to fix that was in my seperate assembly, instead of creating a class that inherited from the base control, i created a new WPF Control that contained the base control. I then put all of the logic that was contained in the CpuUsage class into the WpfCpuUsageControl's code behind. I was able to use this object is all of my other controls just fine.
For your Control "GridView" i would create a new WPF user control, call it GridView and make it contain a "ViewBase" as the content of the Grid control.Inside of the ViewBase's content put in your DataGrid, like this:
<UserControl....>
<Grid>
<ViewBase name="vBase">
<DataGrid name="dGrid" />
</ViewBase>
</Grid>
</UserControl>
It is also not apparent to me that you need ViewBase to inherit from UserControl directly. If all you want are for your controls to have certain properties and method why not just make a BaseControl class (that does not inherit from anyone but object) and have future controls inherit from it. Perhaps an abstract base class or interface is what you're after.
For MVVM WPF projects, I typically have a BaseViewModel which implements INotifyPropertyChanged for me so I don't have to do that same code everywhere.
Best of luck, I know this problem was a huge pain to figure out. The exception message and google are most unhelpful!
Same problem here.
Short version:
Copy Local has to be set to False!
Long version:
We developed a WPF solution (MVVM, 20 projects) and implemented a plug-in system. Our /bin/Debug directory contains the executable, some dll files and a plugin directory that contains the plugins.
There is one project "DialogLib" (Class library, kind of dialog) that defines a window (the view), the ViewModel, Model and some interfaces. One of the plugins used one of the interfaces of DialogLib. The window itself is opened by the main application.
To use the interface of the 'DialogLib' library in the plugin we had to add a project reference of DialogLib to the plugins project references. When the application was started, the plugins were loaded. If the user then selects a menu item, the window should open. At this point the error "... component does not have a resource identified by the URI ..." occured when the windows code behind tried to execute its InitializeComponent().
Where's the problem?
The problem is, that, when we built the solution VS has created the DialogLib.dll correctly and copied it to /bin/Debug/. This is because the main application file wants to open the window. But DialogLib.dll was also copied to /bin/Debug/plugins because one of the plugins referenced it to use one of the interfaces defined in DialogLib.dll. So what?
When the plugin is loaded at runtime it uses the interface defined in /bin/Debug/plugins/DialogLib.dll. and the main application file tries to open the window defined in /bin/Debug/DialogLib.dll. Although the files are identical, VS runs into trouble. Setting the value of Copy Local of the DialogLib reference properties of the plugins references avoids copying DialogLib.dll to /bin/Debug/plugins and thus solves the problem.
We had a similar same problem (but different error) in another project where we wanted to use a type TypeA, that was defined in a dll file, in a plugin and in the main application. Copy Local was set to true which caused a copy of the dll file to be located in ../bin/Debug/plugins and in ../bin/Debug/. It turned out that, even though it was the same dll file, the TypeA in the main app file and TypeA in the plugin were treated as different types respectively as types which could not be exchanged.
Delete obj folder
Delete bin folder
Rebuild solution
Worked for me!
Also if you are loading assemblies using Assembly.LoadFile, check out AppDomain.CurrentDomain.GetAssemblies() for duplicate assemblies in the current AppDomain. Because in auto-generated code of WPF UserControl, the component will be loaded using its relative URI. And since there are duplicate assemblies in the current AppDomain, application doesn't know which one to use.
I resolved this by placing
myusercontrol = Activator.CreateInstance<myusercontrol>();
in the constructor of the window containing the usercontrol before the InitializeComponent(); line
I received the same error when using Visual Studio 2013.
The component does not have a resource identified by the uri
Tried:
Cleaning and rebuilding the solution - did not work.
Closing and opening Visual Studio - did not work.
Solution:
Went into the projects bin directory and cleared out all files.
Ran the project again and worked fine.
Open the Package Manager Console which will open in the root directory of your Solution and run the following powershell command:
Get-ChildItem -inc bin,obj -recurse | Remove-Item -recurse -force -EA SilentlyContinue
#Willem, this seems perfectly OK to me. In fact I tried this and it worked in my case. I used ListBox instead of DataGrid (but that shouldnt matter).
All my namespaces were in one assembly. So I used a common parent namespace for all e.g.
MyWpfApplication.Controls
MyWpfApplciation.GridView
MyWpfApplciation.ViewBase
Coz all these Controls, GridView, ViewBase are clashing with existing System or System.Windows.Controls based namespace and class declarations. So I made sure I referred correct ones MyWpfApplication.* in my project.
I just ran into this problem as well without any inheritance issues. I was just referencing a DLL that contained a dialog and trying to create and display that dialog.
I have assembly resolver that loads assemblies from a specific folder and it turns out that I had added the reference in VS and had not turned off Copy Local. Long story short: my process had loaded two versions of that same DLL. This seems to confuse WPF (or the runtime). Once I cleared the Copy Local and deleted the extra DLL copies, it worked fine again.
I got this error after renaming a xaml file. Reversing the renaming solved the problem.
Furthermore, I found that a reference to the xaml file name in App.xaml was not updated (the StartupUri), but renaming that to the current name didn't resolve the problem (but maybe it does for you). Basically, I can't rename the xaml file.
Fyi, for me, the component 'complaining' in the error was SplitComboBox.
Happend to me when I had the same project opened in two solutions. Modifying the base-control in one project cause the other project to have this problem. If closing and opening doesn't work, then delete all the folders in "C:\Users...\AppData\Local\Microsoft\VisualStudio\12.0\Designer\ShadowCache"
This can happen also when closing and reopening a window. So it could also have nothing to do with packages and/or dlls.
I solved the problem thanks to the solution posted by PainElemental, which is IMHO underrated:
namespace MyNamespace
{
public partial class MyDialog : Window
{
public MyDialog(ExcelReference sheetReference)
{
this.LoadViewFromUri("/MyApp;component/mynamespace/mydialog.xaml");
}
}
}
LoadViewFromUri is implemented as an extension, as PainElemental wrote.
The craziest is that I also wrote in the same project other windows without encountering any problem.
Thank you PainElemental, you ended my protracted pain!
I started consistently seeing a "the component does not have a resource identified by the uri" error when I clicked a particular menu choice from an installed product that was working on other computers. I tried uninstalling the product, making sure its files really were gone, rebooting, and reinstalling the product. The problem remained. I deleted the contents of my %TEMP% directory, and the problem ceased.
Thanks for all the tips in this thread. I think my own variation of this error was for a slightly different reason again, so I'll post here in case it's of use.
In my situation, the error occurred when invoking window.ShowDialog(). More specifically, my window is defined in a separate class library assembly (let's call it AssemblyA.dll).
I have multiple versions of AssemblyA which are used in various products, some of which are plugins and some aren't. In short, the consequence is that the process might end up loading several different strong-named versions of AssemblyA. So there are duplicate assemblies in the app domain as #VahidN pointed out, but they're strictly differently versioned assemblies which are meant to be there, and merely share the same AssemblyShortName.
WPF's auto-generated code for InitializeComponent() looks like this:
public void InitializeComponent() {
if (_contentLoaded) {
return;
}
_contentLoaded = true;
System.Uri resourceLocater = new System.Uri("/AssemblyA;component/forms/mywindow.xaml", System.UriKind.Relative);
#line 1 "..\..\..\Forms\MyWindow.xaml"
System.Windows.Application.LoadComponent(this, resourceLocater);
#line default
#line hidden
}
It's only referring to the short name of AssemblyA, and not to the specific version or public key token of AssemblyA in which the InitializeComponent() method is running. The consequence is that the code just seems to find the first AssemblyA assembly loaded into the process, searches for the XAML, can't find it (because it's found an older version of the assembly first), and then throws an exception. Or perhaps it finds something but maybe it's pulled a different XAML resource than what it's meant to have, from either an older or newer version of the assembly that happens to also be loaded.
It's not perfect, but I've consulted the Pack URI specification, and worked around this by writing my own extension method that makes sure the assembly is found with the appropriate version and public key token, rather than simply the AssemblyShortName.
In case it's of use for others, here's a simplified version of what I've ended up with.
public static void AssemblySensitive_InitializeComponent(this ContentControl contentControl, string componentString)
{
// Strictly speaking this check from the generated code should also be
// implemented, but it doesn't fit directly into an extension method.
//if (_contentLoaded)
//{
// return;
//}
//_contentLoaded = true;
var asm = System.Reflection.Assembly.GetExecutingAssembly();
var shortName = asm.GetName().Name;
var publicKeyToken = GetPublicKeyTokenFromAssembly(asm);
var version = asm.GetName().Version.ToString();
System.Uri resourceLocater = new System.Uri($"/{shortName};V{version};{publicKeyToken};{componentString}", System.UriKind.Relative);
System.Windows.Application.LoadComponent(contentControl, resourceLocater);
}
/// <summary>
/// Gets a public key token from a provided assembly, and returns it as a string.
/// </summary>
/// <param name="assembly"></param>
/// <returns></returns>
/// <remarks>Adapted from https://stackoverflow.com/questions/3045033/getting-the-publickeytoken-of-net-assemblies</remarks>
private static string GetPublicKeyTokenFromAssembly(System.Reflection.Assembly assembly)
{
var bytes = assembly.GetName().GetPublicKeyToken();
if (bytes == null || bytes.Length == 0)
return "None";
var publicKeyToken = string.Empty;
for (int i = 0; i < bytes.GetLength(0); i++)
publicKeyToken += string.Format("{0:x2}", bytes[i]);
return publicKeyToken;
}
The _contentLoaded bit could probably be done with extension properties, but I need the code for this library to compile in C# 7.3 so I have a much longer workaround which I removed so as not to distract.
Then I call it from the constructor like this:
public MyWindow()
{
// Don't use the auto-generated initialize, because if multiple different versions
// are loaded into the process, it can try to load the resource from the wrong one.
//InitializeComponent();
AssemblySensitive_InitializeComponent("component/forms/mywindow.xaml");
// ... do more constructor stuff ...
}
I spent ages getting frustrated trying to figure out what was going on, so I hope this helps someone else out there.
As others have pointed out in their answers, this will happen if you have a base control class with an associated XAML resource, and then define a class in a separate assembly that inherits from the base control. This happens because of a limitation in WPF.
WPF is open source now, so you can see the source code that we need to work around that is called in IntializeComponent() (though it's a bit difficult to follow). In summary, this method get a stream for the control's XAML resource and then loads it with XamlReader.LoadBaml(). The issue is that the framework code does not load the XAML resource file correctly when the derived class is in a different assembly than the XAML resource file.
To work around this issue we need to load the XAML resource stream correctly and then call XamlReader.LoadBaml() manually. There are a few other answers here already that do exactly this, but here's my take on it. The following extension method is a bit more concise than the other answers, accesses only one private method via reflection, and also guards against multiple calls.
private static MethodInfo? _loadBamlMethod;
public static void InitializeComponent(this ContentControl control, string xamlResourceUri, ref bool contentLoaded)
{
// Ensure the control is only initialized once
if (contentLoaded) return;
contentLoaded = true;
// Use reflection to get the private XamlReader.LoadBaml() method and cache the result
_loadBamlMethod ??= typeof(XamlReader).GetMethod("LoadBaml", BindingFlags.NonPublic | BindingFlags.Static)
?? throw new InvalidOperationException("Could not find XamlReader.LoadBaml() via reflection");
// Load the XAML resource for the control
var stream = Application.GetResourceStream(new Uri(xamlResourceUri, UriKind.Relative)).Stream;
var parserContext = new ParserContext { BaseUri = PackUriHelper.Create(new Uri("application://")) };
_loadBamlMethod.Invoke(null, new object[] { stream, parserContext, control, true });
}
Which can then be used like this. Controls in other assemblies may now inherit from BaseControl and not see this issue.
public partial class BaseControl : UserControl
{
protected BaseControl()
{
// The resource URI here can be coped from the generated partial class
// Note that we are also re-using the _contentLoaded field defined in the generated partial class
this.InitializeComponent("/Senti.Common.PrismModules.Hmi;component/controls/basecontrol.xaml", ref _contentLoaded);
}
}
It should definitely be noted that this workaround (as well as the ones in other answers) work by accessing a private method within the WPF framework, which is obviously not a supported use case. That said, I have developed and tested this approach with the .NET 5 version of WPF and not seen any issues. Microsoft has also said that very little development is planned for the WPF framework other than bugfixes etc, so this workaround should be fairly stable.
Quicker than closing all of Visual Studio is just to kill XDescProc.exe in your task manager.
XDescProc is the designer. The moment the process is closed you'll see a Reload the designer link in visual studio. Click that and XDes will be started again and your 'no resource' error should be gone.
Here's the link visual studio shows after you kill the designer process:
I had accidently deleted a user control via a rename/copy action. When I reinstated the project file and the xaml file and .cs from version control this error started happening in the design studio for that control which had mistakenly been deleted/renamed.
That suggested some type of cache on the file in question....so closing Visual Studio, deleting the bin directory and rebuilding worked.
Followed PainElemental's solution (to clarify, for his code the ClassLibrary1 for me was the .dll name without the .dll extension), here's my scenario in case it helps anyone link their specific error messages to the problem:
I use dll's to load and run usercontrols into a main program as their own popup windows. PainElemental's solution was mostly working , but 1 of the 3 classes in my "popup .dll" wouldn't load properly. I would get an exception with 2 inner exceptions, like:
mscorlib InvokeMethod...;
WpfXamlLoader.Load...Provide value on...StaticResourceExtension...;
ResolveBamlType....method or operation is not implemented.
In my case, I confirmed it would load the new URI and work in testing, but when I tried to run it over in my Live environment it would error in LoadViewFromUri().
As I tested further, I narrowed down the issue to not being able to load a separate "library .dll" file I was using which contained a Converter I was using in the .xaml file of the class which was failing, and on further research the issue there was that the Live environment was using a different "library .dll" version than I was using in my test environment, even though the exception message from my "popup .dll" did not make any mention of that.
For reference, I use Copy Local=True and that didn't give me issues. To best debug these kinds of issues, an understanding of the locations where .dll files are searched for by the .exe is helpful. As I understand it, when you are running projects in VS, when Copy Local=True the .dlls get copied to the same folder as the .exe when it is Built. When the .exe is run the standard location it will search for .dlls is the same folder as the .exe. Additional locations that the .exe can look for .dlls can be set in the .exe.config file, in the probing element. In the below example, it can also search in a 'MyDLLs' and the 'MyDLLs\Core' directory relative to the .exe's location. Note that it will not naturally search any subfolders, you have to specify them explicitly. I believe it also searches the GAC, but I currently have minimal knowledge concerning GAC.
<configuration>
...
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<probing privatePath="MyDLLs;MyDLLs\Core;"/>
</assemblyBinding>
</runtime>
</configuration>
Hi the way solve this problem was to rename the xaml usercontrol to all smallcaps on InitializeComponent()...
enter image description here
enter image description here
For me, when trying to launch a window dialog (window.ShowDialog()) in my application during startup, the exception was thrown in the InitializeComponent method in the window's class constructor.
After much head scratching I had discovered that the issue was that an app.publish folder was getting created in the debug directory, which contained the application exe only. Deleting the app.publish folder resolved this exception. See the following article to prevent this folder from getting created:
What creates the directory "app.publish" in visual studio 2013?

Referencing a different project in the same assembly, different namespaces

I have two projects : Menu and Module and they are both in the same namespace foobar.
I am currently referencing the module project from the Menu project to open up certain controls on a tab control in my menu. However I need to launch a new control from one of my controls which is located in the Module project.
When I try referencing the menu project, it does not show up in my intellisense when I try to reference it with a using. Am I doing something wrong logically here?
Here is an example of what it is :
Project Menu
Public Void LaunchWPFControl(string pHeader,string pPath)
{
//Code goes here to launch a WPF control in the browser
}
Project Module
//What I would love to do but doesn't work
Using Menu;
...
...
...
private void dgModule_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
Menu.LaunchWPFControl("Accounts","AccountsControl");
}
If you are talking about seperate projects then what you are trying to do here is a circular reference, this is not allowed. If Project Menu references Project Module, then Project Module cannot reference Project Menu.
If you need a class in Project Module to trigger something in the Menu project you need to look for an alternative way of doing it. One possible technique for achieving this is to create an event in the class in the Module project that the Menu project can subscribe to and perform the required action.
For example in Project Module:
private void dgModule_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
OnMyEvent();
}
private void OnMyEvent()
{
EventHandler localEvent = MyEvent;
if(localEvent != null)
{
localEvent(this, EventArgs.Empty);
}
}
Then in Project Menu you can subscribe to this event and perform your action:
...
...
...
moduleClass.MyEvent += SomeHandler;
...
...
...
private void SomeHandler(Object sender, EventArgs e)
{
Menu.LaunchWPFControl("Accounts","AccountsControl");
}
As Ray Burns mentions (see comments) another way would be to define an interface of the Menu class in some shared location (either there referenced project, or some other shared project) and than you can pass implementations of that interface to the Module project.
Which way is better often depends on the abstraction you are trying to achieve with each project.
If they're both in namespace foobar then you need
using foobar;
instead of using Menu.
It's important that you understand the terminology involved - you're talking about "a different project in the same assembly" - that's nonsensical. Visual Studio creates one assembly per project. You then talk about the projects having the same namespace in the text of your question. You need to understand the difference.
To work out the namespace of a type, open the class containing the type and look for namespace declarations:
namespace MyProject
{
...
}
To work out the assembly of a type, look in the project properties for the project in which it's declared - or if you're using the same solution, just add a reference from the project which wants to use the type to the project which declares the type.
Note that you specify a namespace with a using directive; you need to add a reference to an assembly in solution explorer. They're not doing the same thing. A using directive just says, "Within the code affected by this using directive, I want to be able to use types within this namespace without fully qualifying the names."
Next you've got code like this:
Menu.LaunchWPFControl("Accounts","AccountsControl");
I thought Menu was either a project name or a namespace - but now you're trying to use it as a type name. Which is it?
If this doesn't sort you out, please post full code and a more coherent description of the projects and namespaces involved. Take a step back, work out the types, namespaces and assemblies involved, and then lay it all out clearly.
So Project Menu references Project Module. Then you want Project Module to reference Project Menu so a module can directly call Menu functionality?
This isn't possible, this is a circular reference. If you try to add the Menu reference to the Module project, Visual Studio won't let you.
You need to pull the stuff out of Menu that both Menu and Module want to use into a third project, and have them both reference it. Or combine Menu and Module into one project.

Categories

Resources