The program I'm making is pretty hard to explain since it's for a very specific personal use so I'll use an example to make it easy to understand:
I have a class in the project named Person that stores an image and a name of a person.
All images are stored in the project resources.
How do I save the resource path/name so that I can reuse it on the main program (not the Person class) ?
For exemple if I create a new Person object in the main program:
Person p = new Person("Michael", Project.Properties.Resources.image);
As what type of variable do I save the path in the Person class?
public Person(string name, ??? image)
Note that I will need to reuse this image later,
for exemple:
this.imageBox.Image = p.image;
I tried using the Image and Bitmap objects but it just changed the imageBox to be blank (I think it sets the imageBox.Image to null. Also, I'm pretty sure that using Bitmap will copy the Image's data and use more memorey for no reason)
I also tried using Image.FromFile and inserting the path as a string but it didn't work.
You should not be messing around with paths if you mean to use resources. They are embedded into the assembly and can be reused from there.
The easiest way to access them is by using the generated resources class, Project.Properties.Resources.Picture. The type of the variable will be an Image.
public Person(string name, Image picture)
If you want to, you can even access the resource by extracting it by hand from the assembly, but that seems to much for this case as far as I can tell.
Related
The attribute [CallerFilePath] seems to do what I need to do:
How to find path to .cs file by its type in C#
...but I would like to be able to avoid having to add this new prop to every type that I want to check:
public string SourceFilePath { get; } = Helper.GetCallerFilePath();
What I have tried:
Adding this method at runtime does not seem to be an option.
Using it in a base class does not seem to work either (it returns the
path of the base class).
My guess is that this is somehow feasible, because an exception is able to give you this kind of info (from any given type).
What I really want to do in my particular case is: I have a set of cs files that can be identified via their implemented interface, and I want to know their location in the file structure of the project.
So in this case I don't need to know the file location of any given type, but it would be my preferred approach if that's possible.
I have a bunch of Shape-classes (classic) like Rectangle and Circle in my first module.
In my second module, I have a GUI, made with WPF. I want to show a ListBox of all Shape-classes. The ListBox shall contain the localizable name of the shape, which is saved as a resource string, and an icon, saved as a resource image.
I want my whole code to be as modular as possible, e.g. if I add a new Shape-class, I want to change as few classes as possible.
My first approach would be to make a helper class in my GUI-module, which for each shape holds the Shape's Type, its name as string, and its icon as a Bitmap (or similar). I would then initialize the list at one place, e.g.
var shapeList = new List<ShapeHelperClass>
{
new ShapeHelperClass(typeof(Rectangle), Resources.StringRectangle, Resources.IconRectangle),
new ShapeHelperClass(typeof(Circle), Resources.StringCircle, Resources.IconCircle),
};
and bind this list to the ListBox. Now, if I rename my classes or my resources, nothing will break, and localization should work properly. But, of course, if adding a new Shape-class in the first module, I also need to update this list.
Another approach would be to use reflection to find all my Shape classes, and build the list out of that. However, I would still need some Dictionaries or something similar to map the classes to the Resources. I could find the resources if they follow a pattern, like "Icon" + "Classname". However, if no icon is found, this is only noticed at runtime.
So, my questions are:
Is my first approach a good one, our could it be improved?
How can I make sure that a programmer who adds a new Shape also adds the new Resources and extends the mapping-list? Maybe by Unit-testing?
1.Is my first approach a good one, our could it be improved?
You could create a method in your first module that returns all shapes and call this one in your client application, e.g.:
var shapes = GetShapes();
List<ShapeHelperClass> helpers = new List<ShapeHelperClass>();
foreach(var shape in shapes)
helpers.Add(...);
Then you should never have to modify the client application as a shape is added or removed in the first module.
2.How can I make sure that a programmer who adds a new Shape also adds the new Resources and extends the mapping-list? Maybe by Unit-testing?
Maybe you could write a unit test that uses reflection to find all shape types and asserts that they are included in the list of shapes that is returned from the first module. And likewise for the resources. I can't think of any better automatic way of ensuring this really.
I am currently implementing the Level content type, which is supposed to represent a game level contents (most important, refer to textures stored separately). Input level data contains full path to source texture resources.
Problem: How to determine the resulting content "names" that I can write out into the compiled level content? The textures are supposed to be reused, so baking them into the level content would be a bad idea (waste of space). It is impossible to provide the names during content creation (e.g. within the level editor).
To give an example: Source file Levels/Level01.level refers to Textures/Granite.png and Textures/Dirt.png using their full path names. I would like to infer Textures/Granite and Textures/Dirt from that data at compile time.
The correct solution was to use the (not that well documented) ExternalReference<T> class instead of plain string names.
On the writer's side, the level content object contains ExternalReference<TextureContent> (or even List<ExternalReference<TextureContent>>) instance. When serialized (via ContentWriter), this takes care of adjusting the reference properly.
The reader's side is simplified to a plain ContentReader.ReadObject<> call, e.g.
public sealed class LocationReader : ContentTypeReader<Location>
{
protected override Location Read(ContentReader input, Location existingInstance)
{
List<Texture2D> textures = input.ReadObject<List<Texture2D>>();
}
}
NOTE: Take care to properly override the GetRuntimeType() method in your writer classes; this was the source of oddball ReflectionReader<T> issues for me.
I'm using XNA and attempting to load an image using a string
image = Game.Content.Load<Texture2D>(playerCharacter.image);
the character class is abstract, the PlayerCharacter classes are all derived from it and the image variable is set to something like "PlayerSprites/Char1"
I get a null exception when running this code. The path is correct, but I don't know if a path is the correct way to do this.
Don't use the file path. Use the asset name. Click on the asset in the solution explorer. You'll see a bunch of properties pop up. Look at the one that says "Asset Name". That is literally the string you pass in to the loadcontent method. Hope I helped!
I need a way to insert (or use an already implemented property that could serve as) a unique identifier into a Microsoft.Office.Interop.Excel.ListObject instance.
The problem is that when I'm creating a new ListObject as:
var excelTable = worksheet.ListObjects.Add(ExcelInterop.XlListObjectSourceType.xlSrcExternal, DUMMY_CONNECTIONSTRING, false, true, cellRange);
I cannot rely on the Name property of excelTable to browse for it in the collection since the user could change the value of that property anytime afterwards.
After browsing trough the object properties I found nothing I could use out of the box (like a Tag property for example, which exists in a Microsoft.Office.Tools.Excel.ListObjecttype of object I cannot use at this point due to dependencies) ...and other weird stuff like a DisplayName that appears not only unable to be set directly but also to reflect the exact same value that the Name property has at all times (Why would you want to have 2 properties that reflect the same value at any time?).
I've thought on either creating my own implementation of this class or probably use the Comment property to store a GUID (which I don't know why kinda feels wrong):
excelTable.Comment = Guid.NewGuid().ToString();
Can you suggest of another way to accomplish this task?
Thanks a lot!
It is quite frustrating that there is no "Tag" (or similar) property that you could set on Excel objects. I'm facing the same issues as you. Here are two options that you can use:
alternative text property (for the table it is only visible by right clicking the table, selecting table and alternative text). This is probably a bit cleaner than Comment since the UI for comment is always visible.
you could also generate a wrapper object that contains a direct reference to the ListObject. So one wrapper object for each created ListObject. This works fine until you save / open the workbook again. If you need to be able to identify the table again after reopening the workbook you would still need to write some id to Comment or Alternative text. You could probably do a clean implementation by using events like BeforeSave and AfterSave (add alternative text before save so it saves to disk, then remove it again after save so that the user doesn't see it. When the workbook opens you load up your wrapper objects and remove the alternative text).