I have color scheme for my code editor in a settings file in the project. I have a several similar settings files each containing different color scheme.
To make those settings selectable on runtime, I need them to implement ColorScheme interface.
So far so good, code works fine, with only one major annoyance: each time settings are changed, the interface part is removed from Designer file, so the code doesn't find them anymore.
Is there a way to force code generator to add my interface to generated class? Or is it other workaround for this? I tried to make designer file readonly, but then I see lots of annoying VS dialogs.
Without the interface, I can't cast settings class on anything. I could probably read its properties via Reflection, but this approach looks like an ugly hack.
You could go for an "extension" using a partial class for your settings, that include the interface :) (It should be in the same namespace/assembly as your settings file is). Any changes to the settings do not interfere with your self created partial class
public interface IHaveInterface
{
void Hallo();
}
internal partial class Settings : IHaveInterface
{
public void Hallo()
{
Console.WriteLine("Hallo");
}
}
after which i can access the hallo inside the Properties.Settings.Default
Properties.Settings.Default.Hallo();
Related
I'm developing a platformer using C# and monogame as a fun project to improve my skills. I want to add support for settings like audio, video, controls and more but I don't know the best way to do so.
I plan on having a XML file that stores all settings kind of like this:
<Settings>
<Audio>
<masterVolume>100</masterVolume>
<musicVolume>40</musicVolume>
<sfxVolume>90</sfxVolume>
</Audio>
<Video>
<Resolution>
<width>1920</width>
<height>1080</height>
</Resolution>
</Video>
<Controls>
<forward>W</forward>
<back>S</back>
<left>A</left>
<right>D</right>
</Controls>
</Settings>
My plan was to use a Settings class that has static variables for audio, video and controls etc that are divided into separate classes so that I can access them through Settings.Audio.MasterVolume or Settings.Controls.Forward.
I want to load the settings into these classes from the XML using Linq and I want to save the settings to the XML file when they are changed by the user.
I know that singletons can be used as well but as far as I can tell from the research I've done it has too many drawbacks. Is that true?
Is this a good way to do this or is there a better way that allows me to access the settings throughout the project without having everything static?
Thanks in advance!
Your method works. However, you limit the re-usage of your class.
If you would describe MyClass to others, would you say that the method being used to read the configuration parameters is essential for MyClass? In other words: would most code of your class be meaningless if the configuration parameters wouldn't be read from a configuration file, but for instance from a CSV-file, or from the internet, or whatever method?
You'll probably say no: most code of my class could be reused if the configuration parameters were to be provided differently.
So why limit your class to a class that can only work if it reads the configuration parameters from a configuration file?
I guess that you currently have something like:
static class ConfigurationSettings
{
public static int LeftControl => ...
public static int RighControl => ...
}
class MyClass
{
// MyClass uses configuration settings:
public int LeftControl => ConfigurationSettings.LeftControl;
public int RightControl => ConfigurationSettings.RightControl;
...
}
You can't instantiate two objects of MyClass, each with their own set of configuration parameters. You can't create a MyClass object that uses a different method of providing configuration values.
One of the use cases I quite often need this is when unit testing: I want a quick way to be able to change the configuration settings without having to change the configuration file of the unit test project.
An easy way to allow users of your class to provide different methods for setting is to create an interface with the setting and provide a constructor with this interface:
interface IMySettings
{
int LeftControl {get;}
int RightControl {get;}
...
}
class ConfigurationSettings : IMySettings
{
// ConfigurationSettings reads settings from the configuration file
}
class MyClass
{
// default constructor use the configuration file via ConfigurationSettings:
public MyClass() : this (new ConfigurationSettings())
{
}
// extra constructor for those who don't want to use configuration file
public MyClass(IMySettings settings)
{
this.Settings = settings;
}
protected readonly IMySettings settings;
// MyClass uses settings:
public int LeftControl => this.settings.LeftControl;
public int RightControl => this.settings.RightControl;
}
Users who want to use the settings from the configuration file can use the default constructors; uses who want specific settings use the alternative constructor. This alternative constructor is also used if you want two different MyClass objects, each with their own settings.
At first glance it seems that with minimal changes you can still use the configuration file. However, to be able to implement the interface, the class that reads the configuration file (MyClass) can't be static.
However, you were right: there is only one configuration file, hence there should be only one instance of the class that reads from the configuration file: create a singleton.
In my experience, classes that represent a configuration, is one of the often used reasons to use a singleton instead of a static class
In my game projects I always use some static classes (and/or variables) to hold information that is valid through the whole game.
This might come in handy especially for audio settings if you want to be able to change the volume and so on from different points of the game.
This does not necessarily only include user settings. Thinkig of lowering the background music when some character is speaking.
long story short:
I would go for the static approach. But take care not to over exceed it.
In order to disable component designer in classes it is simple to add just [System.ComponentModel.DesignerCategory("")] attribute to it, however it does not work for any classes derived from this class in any generation. E.g:
[System.ComponentModel.DesignerCategory("")]
public class A:ServiceBase { } //Designer is disabled here
public class B:A {} //Designer is enabled here
[System.ComponentModel.DesignerCategory("")]
public class B:A {} //Designer is enabled here too
[System.ComponentModel.DesignerCategory("Code")]
public class B:A {} //Designer is enabled even here
This happens, of course, in any other generations and permutations. E.g.
//Whatever attribute here
public class C:B {} //Designer is enabled here
Does anybody ever tried to get rid of it? Why component model tries to add designer support even if it explicitely disabled in first generation?
Thank you
The reason for such behaviour is cached referenced assemblies. To solve it, remove reference to the assembly contained base server with attribute and add it again. In this case Visual Studio rebuild project and will not define default editor to derrived class.
"Attribute inheritance" at first struck me as odd, as I always thought that attributes weren't inherited; after checking learn.microsoft.com I discovered that that doesn't have to be the case - attributes may have Inherited = true, so thanks to you for helping me broaden my knowledge :-)
Additionally, I also had to remove a bunch of <SubType>Component</SubType> entries from the .csproj file
What I would like to do is have a versatile settings class that I can use in a composite application. As I add features and components and compose the application using MEF & Prism I would like to have a settings window that automatically loads the settings interface of each of the modules into a window (using Prism & MEF)
There are many different ways of dealing with settings, and the one that appeals to me is something along the following:
public class AppData : ApplicationSettingsBase
{
[UserScopedSetting()]
[DefaultSettingValue("true")]
public bool Clipboard
{
get { return ((bool)this["Clipboard"]); }
set { this["Clipboard"] = (bool)value; }
}
}
It allows me to set a default value and I am assuming that if the application does not find the .settings file then it will create one with the defaults. However I would need to write a bunch of custom code for each modules settings section and either create a unique dialog for each module or try to have a settings manager that manually loads them all in.
There are some settings that would have multiple values as well and it does not look like the above example would be able to accomodate that. What if I had a setting that stored a list of something? For example if I had a setting that was ValidBlock, and at the start there are two blocks that could be valid but in the future there may be a need to add more? Can you have a setting that is a list and specify multiple default values for that setting?
So would it be acceptable to create a Isettings interface that somehow used ApplicationSettingsBase so that I can use MEF to find all Isettings implementations in all the modules in a directory and then compose a dialog with tabs for each implementation it found? In the Isettings interface I could have some basic properties such as Name and whatever else would be needed to label and describe the module in the MEF WPF window.
The only other thing I do not like is that there are strings and attributes all over the place. Is there a way to deal with settings in a fluent way? I am thinking along the lines of having a ISettings implementation that you would explicitly code a setup something like the following:
public class AppData : ISettings
{
Setting Clipboard = new Setting();
Clipboard.Scope = SettingScope.User;
Clipboard.SettingType = List<String>;
List<String> DefaultClipboards = new List<String>();
DefaultClipboards.Add("FoxClipboard");
Clipboard.DefaultSetting = DefaultClipboards;
}
I know the above is not exactly syntax correct, and I do not think that the Clipboard.SettingType would hold much water but its to give an idea of what I am thinking. So if something like this can be achieved while maintaining the creation of a settings file in the event one is missing that would be ideal. As well with something like this MEF can find all the ISettings implementations and create a tab for each one, and then add each Setting based on setup of it in the code.
Is this the right track to be on? Is there a framework or project out there that I have missed that handles what I am aiming for? I am thinking there is probably a better way than what I have outlined?
I am sure this question has come up in composite application development but I have not found a framework or an answer that outlines this scenario.
I have been able to create a loose coupled composite application and dynamically wire up my modules using MEF & Prism but I have not been able to find a satisfactory way to deal with settings in a composite way.
I tackled something similar for one of my applications at work. We leaned further towards your second idea, where there is simply a base settings interface "ISettings" that we used for MEF composition.
We created a custom export provider to deal with loading settings, and had a manager to save out the settings using some serializer.
For the UI, we had modules with user facing settings also export a "settings workspace" that we would load into the settings UI. Using reflection, we wrote a method that will make a deep copy of a settings object so that we could do direct mvvm binding to the cloned object (for cancel functionality), as well as take an object and copy it's properties back.
The reflection was to allow for a generic clone/copy without writing code for every settings object.
Also, one thing that we did that I still love to this day for data model binding is the "INotifyPropertyChanged" interface. Our base ISettings object requires it. This allows not only the settings UI to directly bind to settings and listen for changes, but when we hit apply or ok, all of our data model that needs settings registers for the prop changed event, so they all automatically get notified when a setting has changed.
Check out Property Observer if you plan on doing the notify route. This application has been deployed and I still feel like our settings framework is wildly successful.
If you need, I can provide further detail in certain areas.
Hope this helps!
Disclaimer: I have no experience with custom implementations of ApplicationSettingsBase so I can not assist with its actual implementation, nor positively say that this approach will work. However, what I propose might be a path worth exploring if you really want to use ApplicationSettingsBase.
First of all, ISettings can not inherit ApplicationSettingsBase, because interfaces can only inherit other interfaces.
My proposal is to create a custom ApplicationSettingsBase implementation that is parameterized with an instance of ISettings. That way, whenever you recieve an ISettings from your components, you instantiate a new CustomAppSettings (see below) and associate that with your component.
Since ApplicationSettingsBase uses a string-to-object key value pair mapping, I propose an interface that does the same.
public interface ISettings
{
Dictionary<string,object> Values{ get; set; }
public object GetDefaultValue(string key);
// Whatever else you might need
}
public class CustomAppSettings : ApplicationSettingsBase
{
public ISettings Settings { get; set; }
public override object this[string propertyName]
{
get
{
return this.Settings.Values[propertyName];
}
set
{
this.Settings.Values[propertyName] = value;
}
}
// There will be more implementation work for this class I'm sure
}
In addition you would need a serialization mechanism for your ISetting instances.
Edit: Fixed some code syntax errors
I am using Linq-To-SQL and I would like to attach an interface to each of my entities.
I can edit the designer.cs file and accomplish this.
However, when I make a changes to the dbml through the UI it rewrites the whole designer.cs and I lose my changes.
Am I just going to have to deal with it, or is there a way to get around it?
I am doing this in the designer.cs file(the IMatchable is a custom interface of mine):
public partial class Error : INotifyPropertyChanging, INotifyPropertyChanged, IMatchable
{
...
}
Don't edit the designer file; the beauty of partial classes is that you can create a separate file with just
public partial class Error : IMatchable
{ }
(assuming that we are using implicit interface implementaion by virtue of having properties that match the required interface)
Small word of caution though: if you are using VS2008 and you have MyClasses.dbml and MyClasses.designer.cs, do not call this file MyClasses.cs - there is a bug in VS2008 that makes this a nuisance (you have to keep moving the using directives inside the namespace, or the code-generator breaks) - fixed in VS2010 though.
Also, if it was a single interface, that every type in your model implemented, you can cheat by specifying that at the object base-type in the DBML. The designer doesn't show this option, but if you edit the DBML manually it works fine.
During a refactoring, I added a generic type parameter to MyControl, a class derived from UserControl. So my class is now MyControl<T>.
Now I get an error at runtime stating that the embedded resource file MyControl`1.resources cannot be found. A quick look with .NET Reflector shows that the resource file is actually called MyControl.resources, without the `1.
At the start of the MyControl<T>.InitializeComponent method there is this line which is probably the one causing problems:
System.ComponentModel.ComponentResourceManager resources =
new System.ComponentModel.ComponentResourceManager(
typeof(MyControl<>));
How do I force the ComponentResourceManager to use the embedded resource file MyControl.resources? Other ways to resolve this issue are also welcome.
Turns out you can override the resource filename to load by inheriting from ComponentResourceManager like this:
using System;
using System.ComponentModel;
internal class CustomComponentResourceManager : ComponentResourceManager
{
public CustomComponentResourceManager(Type type, string resourceName)
: base(type)
{
this.BaseNameField = resourceName;
}
}
Now I can make sure that the resource manager loads MyControl.resources like this:
System.ComponentModel.ComponentResourceManager resources =
new CustomComponentResourceManager(typeof(MyControl<>), "MyControl");
This seems to work.
edit: the above line is overwritten if you use the designer, because it is in the
generated code region. I avoid the designer and make use of version control tools to revert any unwanted changes, but the solution is not ideal.
In addition to Wim's technique, you can also declare a non-generic base control that has the same name as your generic class, and have your generic control/form derive from that non-generic base class.
This way you can trick both the designer and the compiler into using the resource file from your generic class, and you get permanent designer support once the base class is setup without having to fiddle in the .designer file everytime you rebuild :
// Empty stub class, must be in a different file (added as a new class, not UserControl
// or Form template)
public class MyControl : UserControl
{
}
// Generic class
public class MyControl<T> : MyControl
{
// ...
}
The only requirements are to have exactly the same name for your generic class and its base class, and that the base class must be in another class file, otherwise the designer complains about not finding one of the two classes.
PS. I tested this with forms, but it should work the same with controls.
On my Visual Studio 2008 I have this error:
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MyControl));
Using the generic type 'WindowsFormsApplication1.UserControl1' requires '1' type arguments.
Notice that in my case code was generated without parentheses, <>, after the class name.
It is becoming interesting, see ImageList autogenerates non-compiling code in a Generic User Control.
What they said:
Posted by Microsoft on 7/6/2005 at 2:49 PM
This is an interesting bug. You've hit upon a generic scneario that we do not support in the Windows Forms designer. We will not be able to add support for this in the Whidbey (my note: Visual Studio 2008?) release. We will consider this for a future version. As a workaround, you can use the designer to create a none generic UserControl with a public Type property and then create a generic class that inherits from it and passes T into the base classes Type property.
I suppose this control cannot be designed in the Visual Studio forms designer either.
The simplest and easiest workaround is to make a dummy class for the autogenerated typeof(). You do not need to inherit from it or even expose it to the outside:
// Non-generic name so that autogenerated resource loading code is happy
internal sealed class GridEditorForm
{
}
(In my experience, the time required getting the designer to work around generics was not worth the ideal coolness generics can provide. I won't be using generic windows forms or controls again.)