Episerver -Validate content reference for image type - episerver

I have a content reference of type UIHint of image that accepts all the image types including .ico.
I need to validate this field so that the user can only upload file of type .ico
Right now even with the regex to only accept.ico file,the validation fails.
Could someone point out what is wrong with this.
I have validated the regex that should only accept.ico file but the validation fails
[Display(GroupName = Global.GroupNames.SiteSettings, Name = "Favicon", Description = "", Order = 20)]
[UIHint(UIHint.Image)]
[RegularExpression("[^\\s]+(.*?)\\.(ico)$", ErrorMessage = "Only .ico extension allowed")]
public virtual ContentReference Favicon { get; set; }
Kindly guide me in the right direction

Since .ico files probably aren't intended to be rendered on the site like other images (?) I'd create a separate content type called IconImage for the .ico file extension and then use an AllowedTypes attribute on your ContentReference property, specifying IconImage as the only allowed type.
If you already have a lot of icon files uploaded, i.e. mapped to an existing content type shared with other types of images, I'd probably create a separate validator (class implementing IValidate<T>) for applicable content type(s) to validate the ContentReference property.

Related

How do I create different sets of settings at run time?

My WPF application has a bunch of settings the user can adjust, I am using the built-in application settings (Properties.Settings... and a .settings file) to do this and it all works fine. Now, the application is supposed to allow the user to define different presets of settings for different purposes (different samples to be exact, it's a measurement system software) so they don't need to go over every setting again when they switch.
So, I would need to be able to create copies of the application settings at runtime and save them all separately in their own file, then restore them when the application starts up. I can create new settings files at design time but that's outside of the user's control and not what I am looking for. I also can create new Settings instances in code but when I save them it just overwrites the same user.config file the default instance used and the Save() method takes no arguments to save it somewhere else.
Any ideas?
You would have to create a separate class for your preset settings. Then you can save this as a list in Settings.
So lets say you have a preset class that holds your settings values:
public class Preset
{
public int MaxPower { get; set; }
public int AllowedRotations { get; set; }
}
You could in one place get all of these settings like so:
var presets = JsonConvert.DeserializeObject<List<Preset>>(Properties.Settings.Default.Presets);
And you would save the settings like so:
List<Preset> presets = null;
if (Properties.Settings.Default.Presets == null)
presets = new List<Preset>();
else
presets = JsonConvert.DeserializeObject<List<Preset>>(Properties.Settings.Default.Presets);
presets.Add(new Preset() { AllowedRotations = 1000, MaxPower = 200});
Properties.Settings.Default["Presets"] = JsonConvert.SerializeObject(presets);
Properties.Settings.Default.Save();
I guess you can also have some kind of unique ID for these objects so you can differentiate one preset from the other.
NOTE: I am using Json converter here and saving the list of objects as JSON.

Localization in MEF: export attribute does not support a resource (WPF - C#)

I have an application with a plugin architecture using MEF. For every exported part there is an attribute with the part's name, and I want to have the names translated, because I use these strings to display the available parts in ListBoxes (or the like).
So, I tried to set the 'Name = Strings.SomeText" in the [Export] annotation, but I get the following error:
"An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type"
Is there a solution to this? I find the use of the Metadata very useful (I do lazy loading) and I would not want to redesign everything just to get a few texts translated.
Any ideas? Thanks.
Unfortunately you can't directly provide the translated text to the attributes because an attribute can only contain data that is known at compile time. So you will need to provide some compile time constant value that you can later use to look up the translated test.
One solution would be to pass the resource name to the attribute. Then when you want to display the translated text you grab the resource name, look up the text in the resources and display the result.
For instance your attribute could look something like:
[Export(Name = "SomeText")]
public class MyExport
{
}
Then when you want to display the string you load the resources from the assembly that defines the export and you extract the actual text from the loaded resources. For instance like this (as borrowed from another answer):
var assembly = typeof(MyExport).Assembly;
// Resource file.. namespace.ClassName
var rm = new ResourceManager("MyAssembly.Strings", assembly);
// exportName contains the text provided to the Name property
// of the Export attribute
var text = rm.GetString(exportName);
The one obvious drawback about this solution is that you lose the type-safety that you get from using the Strings.SomeText property.
--------- EDIT ---------
In order to make it a little easier to get the translated text you could create a derivative of the ExportAttribute which takes enough information to extract the translated text. For example the custom ExportAttribute could look like this
public sealed class NamedExportAttribute : ExportAttribute
{
public NamedExportAttribute()
: base()
{
}
public string ResourceName
{
get;
set;
}
public Type ResourceType
{
get;
set;
}
public string ResourceText()
{
var rm = new ResourceManager(ResourceType);
return rm.GetString(ResourceName);
}
}
Using this attribute you can apply it like this
[NamedExport(
ResourceName = "SomeText",
ResourceType = typeof(MyNamespace.Properties.Resources))]
public sealed class MyClass
{
}
Finally when you need to get the translated text you can do this
var attribute = typeof(MyClass).GetCustomAttribute<NamedExportAttribute>();
var text = attribute.ResourceText();
Another option is to use the DisplayAttribute

Silverlight App object Does not exist' Error

name 'App' does not exist in the current context.
How that possible?
Have to note my initialization code is different than MainPage() type, as I converted SketchFlow app into production Silverlight. They instruct you to do init code via System.Windows.Controls.Frame():
private void Application_Startup(object sender, StartupEventArgs e)
{
this.RootVisual = new System.Windows.Controls.Frame() { Source = new Uri("/MyAppScreen.xaml", UriKind.Relative) };
}
public static string ValueFromHome =
"A Value on Home page";
the goal was to set up public var inside App object so I can access it from various screens down the road
Accessing Resource data requires calling App object I believe as in below, is that correct? so this won't help me
string color = App.Current.Resources["customColor"].ToString();
If you are just storing strings, look into using Resource files. Then they can be translated if that ever becomes necessary.
EDIT (to explain the resource file usage): To access the resource, first create a .resx file in your project (let's say you name it MainResource.resx), change the access modifier drop down to public, add your string with Name: ValueFromHome and Value: "A Value on Home page".
Then you can get the value by adding a using to the namespace of the resource if needed and calling it directly like so:
string value = MainResource.ValueFromHome;
I'd be wary of static variables hanging around. Maybe you could use a MainViewModel to store that value. If you really need a static variable create a new static class in your project and put your ValueFromHome property in that class. The App probably isn't available since it is a Silverlight construct and not made to be available to all areas.

Providing the WPF designer with an image at DesignTime

This is a restatement of my question, the revision history contains the original mess.
What it boils down to is "How do I get the application's directory from my WPF application, at design time?"
Which duplicates the question here so if you happen to be passing by please vote to close, thanks.
Do you need the image to be "Content - Copy if newer"? If you switch it to "Resource" you can use the following path to reference the file:
"/MyImage.JPG"
or a longer version
"pack://application:,,,/MyImage.JPG"
given that the image is in the root of the project, otherwise just change the URI to
"/Some/Path/MyImage.JPG"
UPDATE 1:
For me, the longer pack uri syntax works with an image marked as "Content - Copy if newer" as well. However, the shorter syntax does not work. I.e:
This works:
"pack://application:,,,/MyImage.JPG"
This does NOT work:
"/MyImage.JPG"
I my example I added the image to the root of the project, and marked it as "Content". I then bound the design time data context to a view model with a property returning the longer pack URI above. Doing that results in the Content image being shown correctly at design time.
UPDATE 2:
If you want to load a bitmap source from a pack uri, you can do so by using another overload of the BitmapFrame.Create which takes an URI as the first parameter.
If I understand your problem correctly you get the string with the pack uri as the first item in the object array that is passed to your converter. From this string you want to load a BitmapSource.
Since the string contains a pack URI, you can create an actual URI from the string and then use that URI to load the BitmapSource:
var imagePath = values[0] as string;
// ...
try
{
var packUri = new Uri(imagePath);
BitmapSource bitmap = BitmapFrame.Create(packUri, BitmapCreateOptions.None, BitmapCacheOption.OnLoad);
{
// ...
}
}
}
Just return the exact path of the image from your entity in ImagePath property, such as ..
"C:\MyImage.JPG"
..
OR
..
"C:\MyApp\bin\Debug\MyImage.JPG"
Then your binding (i.e. <Image Source="{Binding ImagePath}" />) in .xaml will start working..
I solved it by leveraging the clevers found in this stackoverflow answer.
public class DMyViewModel : PhotoViewModelBase
{
public override string ImagePath
{
get
{
string applicationDirectory =
(from assembly in AppDomain.CurrentDomain.GetAssemblies()
where assembly.CodeBase.EndsWith(".exe")
select System.IO.Path.GetDirectoryName(assembly.CodeBase.Replace("file:///", ""))
).FirstOrDefault();
return applicationDirectory + "\\MyImage.JPG";
}
}
}

Error Application cast in WPF

i have 2 projects in my solution (main is A.WPF and secondary is B.WPF)
when i'm trying to access variables inside my App.xaml.cs in B.WPF:
filename = ((App)Application.Current).ErrorLogFileName;
i get the following error:
Unable to cast object of type 'A.App' to type 'B.App'.
i also tried the following:
filename = ((B.App)Application.Current).ErrorLogFileName;
but still the same error...
the definition in B.App is:
private string _errorLogFileName = "error log.xml";
public string ErrorLogFileName
{
get { return _errorLogFileName; }
}
please assist...
Looks like you need to do:
filename = ((A.App)Application.Current).ErrorLogFileName;
The error is saying the type is A.App, yet in both cases you are trying to cast to B.App.
There can only be one current application also.
Application.Current refers to the current application. The only way to be allowed to cast the current App to another App-type is when the other App-type is a base class of the current App-type.
Are A.App and B.App siblings or is B.App a base class of A.App?
If you don't want B to have a reference to A (or can't as you want A to reference B and that would cause a circular reference), then you need a common type defined in a third assembly that both A and B reference. In our implementation we tend to have a ConfigurationData type that is in a separate project referenced by both Wpf projects, e.g.
public static class ConfigurationData
{
private static string _errorLogFileName = "error log.xml";
public string ErrorLogFileName
{
get { return _errorLogFileName; }
}
}
Another approach would be to define an Interface for your ErrorLogFileName property in a 3rd assembly that both A and B reference, and then implement that interface on your Wpf Application class - A and B would then both be able to cast to that type. If you wanted your A project to set the values on that at runtime, you could make the ErrorLogFileName a read-write property instead and initialize it in your application startup.
I personally prefer using a separate ConfigurationData type from the Wpf app object for this kind of stuff (ErrorLogFileName etc.) as it can then also be used for code that might execute in a unit test and therefore might not be running under a Wpf application - it also avoids having to do casts all over the place (ConfigurationData.ErrorLogFileName instead of ((IAppConfigurationData)Application.Current).ErrorLogFileName.
BTW, if you have an Application object in both assemblies it sounds like you might have both assemblies configured to build as Output type: Windows Application in your project properties. You should only really have one assembly that is configured as the Windows Application and the rest should be Class Library to avoid confusing numbers of Application classes being generated - only the one in the main EXE (and it's related resources) will get created at runtime.

Resources