Problem Summary
I am trying to create an offline tiled map for a WPF application that uses telerik. The user does not need to zoom in very far. I am having trouble finding a source of tiles that can be implemented with telerik.
What I've tried
I am using RadMap from telerik for WPF. They have an option for implementing tiles from a custom tile provider. I have been trying to follow the solutions given in this forum and this forum. They recommend downloading tiles from Easy OpenStreetMap Downloader, but it the file format does not match the code. It appears in the code, the tiles should be grouped in folders according to zoom level, then in a folder according to x coordinate. However, it looks to me like openstreetmaps downloader groups them by y coordinate only. I either need to get openstreetmaps downloader to save the tiles in this format, or to find another provider that will.
Code
Here is the telerik code that I am trying to base my solution off of:
/// <summary>
/// Tile source which read map tiles from the file system.
/// </summary>
public class FileSystemTileSource : TiledMapSource
{
private string tilePathFormat;
/// <summary>
/// Initializes a new instance of the FileSystemTileSource class.
/// </summary>
/// <param name="tilePathFormat">Format string to access tiles in file system.</param>
public FileSystemTileSource(string tilePathFormat)
: base(1, 20, 256, 256)
{
this.tilePathFormat = tilePathFormat;
}
/// <summary>
/// Initialize provider.
/// </summary>
public override void Initialize()
{
// Raise provider intialized event.
this.RaiseIntializeCompleted();
}
/// <summary>
/// Gets the image URI.
/// </summary>
/// <param name="tileLevel">Tile level.</param>
/// <param name="tilePositionX">Tile X.</param>
/// <param name="tilePositionY">Tile Y.</param>
/// <returns>URI of image.</returns>
protected override Uri GetTile(int tileLevel, int tilePositionX, int tilePositionY)
{
int zoomLevel = ConvertTileToZoomLevel(tileLevel);
string tileFileName = this.tilePathFormat.Replace("{zoom}", zoomLevel.ToString(CultureInfo.InvariantCulture));
tileFileName = tileFileName.Replace("{x}", tilePositionX.ToString(CultureInfo.InvariantCulture));
tileFileName = tileFileName.Replace("{y}", tilePositionY.ToString(CultureInfo.InvariantCulture));
if (File.Exists(tileFileName))
{
return new Uri(tileFileName);
}
else
{
return null;
}
}
}
/// <summary>
/// Map provider which read map tiles from the file system.
/// </summary>
public class FileSystemProvider : TiledProvider
{
/// <summary>
/// Initializes a new instance of the MyMapProvider class.
/// </summary>
/// <param name="tilePathFormat">Format string to access tiles in file system.</param>
public FileSystemProvider(string tilePathFormat)
: base()
{
FileSystemTileSource source = new FileSystemTileSource(tilePathFormat);
this.MapSources.Add(source.UniqueId, source);
}
/// <summary>
/// Returns the SpatialReference for the map provider.
/// </summary>
public override ISpatialReference SpatialReference
{
get
{
return new MercatorProjection();
}
}
}
public MainWindow()
{
InitializeComponent();
this.radMap.Provider = new FileSystemProvider("Path to OpenStreet Images\\{zoom}\\{x}\\os_{x}_{y}_{zoom}.png");
}
In a nutshell:
I have a list with items named Categories. For each of those items in the list Categories I have a xml file:
System.IO.File.Create(Categories[listPicker.SelectedIndex] + ".xml");
The created item is serialized into a xml file with the name of the selected index.
The problem:
The problem is that for each item in categories an xml file needs to be deserialized to a list, because each object of categories must be another list because it also contains items.
But there does not exist a list for deserialization of the xml file:
Deserialization:
Serialize.Deserialize(Variable list name , Categories[1]+".xml");
So how do i dynamically create lists or can you provide a better solution to this problem?
Even if each list has a different name, the structure of the content is the same. Text/Description and Value.
I would create a class for the Item. Something like
public class ComboItem{
public string Value {get; set;}
public string Text {get; set;}
}
Then I would create another class for the List of ComboItem that each XML File would have
public class ComboItemList
{
public ComboItemList()
{
ComboItems = new List<ComboItem>();
}
[XmlArray("ComboItems"), XmlArrayItem("ComboItem")]
public List<ComboItem> ComboItems { get; set; }
}
I have a Serialize/Deserialize Helper. Something like
#region static T DeserializeObject( string xml, Encoding encoding )
/// <summary>
/// Deserialize an Xml String to an [object]
/// </summary>
/// <typeparam name="T">Object Type to Deserialize</typeparam>
/// <param name="xml">Xml String to Deserialize</param>
/// <param name="encoding">System.Text.Encoding Type</param>
/// <returns>Default if Exception, Deserialize object if successful</returns>
/// <example>
/// // UTF-16 Deserialize
/// [object] = SerializationHelper<ObjectType>DeserializeObject( xml, Encoding.Unicode )
/// </example>
/// <example>
/// // UTF-8 Deserialize
/// [object] = SerializationHelper<ObjectType>DeserializeObject( xml, Encoding.UTF8 )
/// </example>
public static T DeserializeObject(string xml, Encoding encoding)
{
if (string.IsNullOrEmpty(xml)) { return default(T); }
try
{
XmlSerializer xmlSerializer = new XmlSerializer(typeof(T));
using (MemoryStream memoryStream = new MemoryStream(encoding.GetBytes(xml)))
{
// No settings need modifying here
XmlReaderSettings xmlReaderSettings = new XmlReaderSettings();
using (XmlReader xmlReader = XmlReader.Create(memoryStream, xmlReaderSettings))
{
return (T)xmlSerializer.Deserialize(xmlReader);
}
}
}
catch
{
return default(T);
}
}
#endregion
/// <summary>
/// Deserialize an Xml String to an [object] with UTF8 as Encoding
/// </summary>
/// <param name="xml">Xml String to Deserialize</param>
/// <returns>Default if Exception, Deserialize object if successful</returns>
/// <example>
/// [object] = SerializationHelper<ObjectType>DeserializeObject( xml )
/// </example>
public static T DeserializeObjectFromFile(string filePath)
{
if (!File.Exists(filePath))
{
throw new FileNotFoundException(string.Format("The file {0}, don't exist.", filePath));
}
StreamReader sr = File.OpenText(filePath);
string xml = sr.ReadToEnd();
return DeserializeObject(xml, Encoding.UTF8);
}
that I would call like this
string filePath01 = "PATH TO FILE 01";
List<ComboItem> List01 = SerializationHelper<ComboItem>.DeserializeObjectFromFile(filePath01);
string filePath02 = "PATH TO FILE 02";
List<ComboItem> List02 = SerializationHelper<ComboItem>.DeserializeObjectFromFile(filePath02);
List01 and List02 would have the contents of File01 and File02. Repeat for every file you have.
With a better architecture, you could make some properties in base class, that could be singleton, and would only load each file, only once, increasing the performance.
I was using Application Settings (as part of Visual Studio) but can't seem to get the other app using the settings from the original app.
Can someone help with storing a few string variables between two apps in .net c#?
EDIT: seems I need to add a reference to my first app from the second app to access the Properties.Default settings - how do I do this?
if you want to share a config between to projects you can just add the file from the other project 'as a link': Right click on the project >> select 'Add existing file' >> navigate to the app.config file >> click the dropdown next to the add button and select add as a link.
or
if you want to share a config between two apps this is the method
I would have a shared assembly, which contains your settings class. You can then serialize/deserialize this class to a common place on the hard drive:
[XmlRoot()]
public class Settings
{
private static Settings instance = new Settings();
private Settings() {}
/// <summary>
/// Access the Singleton instance
/// </summary>
[XmlElement]
public static Settings Instance
{
get
{
return instance;
}
}
/// <summary>
/// Gets or sets the height.
/// </summary>
/// <value>The height.</value>
[XmlAttribute]
public int Height { get; set; }
/// <summary>
/// Main window status (Maximized or not)
/// </summary>
[XmlAttribute]
public FormWindowState WindowState
{
get;
set;
}
/// <summary>
/// Gets or sets a value indicating whether this <see cref="Settings"/> is offline.
/// </summary>
/// <value><c>true</c> if offline; otherwise, <c>false</c>.</value>
[XmlAttribute]
public bool IsSomething
{
get;
set;
}
/// <summary>
/// Save setting into file
/// </summary>
public static void Serialize()
{
// Create the directory
if (!Directory.Exists(AppTmpFolder))
{
Directory.CreateDirectory(AppTmpFolder);
}
using (TextWriter writer = new StreamWriter(SettingsFilePath))
{
XmlSerializer serializer = new XmlSerializer(typeof(Settings));
serializer.Serialize(writer, Settings.Instance);
}
}
/// <summary>
/// Load setting from file
/// </summary>
public static void Deserialize()
{
if (!File.Exists(SettingsFilePath))
{
// Can't find saved settings, using default vales
SetDefaults();
return;
}
try
{
using (XmlReader reader = XmlReader.Create(SettingsFilePath))
{
XmlSerializer serializer = new XmlSerializer(typeof(Settings));
if (serializer.CanDeserialize(reader))
{
Settings.instance = serializer.Deserialize(reader) as Settings;
}
}
}
catch (System.Exception)
{
// Failed to load some data, leave the settings to default
SetDefaults();
}
}
}
Your xml file will then look like this:
<?xml version="1.0" encoding="utf-8"?>
<Settings xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" Height="738" WindowState="Maximized" IsSomething="false" >
</Settings>
If you want the same user to use the same settings for both apps OR you want all users to share the same settings, you have a couple of choices besides the standard appsettings:
1) Store the data in the registry. You could either make the settings user specific or global to the machine.
2) Store a structured file, such as an XML file, containing the settings in one of the standard directories: Environment.SpecialFolder.CommonApplicationData for all users or Environment.SpecialFolder.ApplicationData for a single user. This would be the approach I would use.
My app is split up into a configuration tool which writes the configuration and a viewer which just reads and uses settings from the configuration.
What techniques for storing the properties would would be recommended in this scenario? Would XML for the different categories be a good idea?
The apps are developing in C#, on .NET 3.5 and using WinForms.
I would have a shared assembly, which contains your settings class. You can then serialize/deserialize this class to a common place on the hard drive:
[XmlRoot()]
public class Settings
{
private static Settings instance = new Settings();
private Settings() {}
/// <summary>
/// Access the Singleton instance
/// </summary>
[XmlElement]
public static Settings Instance
{
get
{
return instance;
}
}
/// <summary>
/// Gets or sets the height.
/// </summary>
/// <value>The height.</value>
[XmlAttribute]
public int Height { get; set; }
/// <summary>
/// Main window status (Maximized or not)
/// </summary>
[XmlAttribute]
public FormWindowState WindowState
{
get;
set;
}
/// <summary>
/// Gets or sets a value indicating whether this <see cref="Settings"/> is offline.
/// </summary>
/// <value><c>true</c> if offline; otherwise, <c>false</c>.</value>
[XmlAttribute]
public bool IsSomething
{
get;
set;
}
/// <summary>
/// Save setting into file
/// </summary>
public static void Serialize()
{
// Create the directory
if (!Directory.Exists(AppTmpFolder))
{
Directory.CreateDirectory(AppTmpFolder);
}
using (TextWriter writer = new StreamWriter(SettingsFilePath))
{
XmlSerializer serializer = new XmlSerializer(typeof(Settings));
serializer.Serialize(writer, Settings.Instance);
}
}
/// <summary>
/// Load setting from file
/// </summary>
public static void Deserialize()
{
if (!File.Exists(SettingsFilePath))
{
// Can't find saved settings, using default vales
SetDefaults();
return;
}
try
{
using (XmlReader reader = XmlReader.Create(SettingsFilePath))
{
XmlSerializer serializer = new XmlSerializer(typeof(Settings));
if (serializer.CanDeserialize(reader))
{
Settings.instance = serializer.Deserialize(reader) as Settings;
}
}
}
catch (System.Exception)
{
// Failed to load some data, leave the settings to default
SetDefaults();
}
}
}
Your xml file will then look like this:
<?xml version="1.0" encoding="utf-8"?>
<Settings xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" Height="738" WindowState="Maximized" IsSomething="false" >
</Settings>
XML would seem the ideal choice for this.
In WinForms user settings are persisted via XML so you have all the classes and helper methods you need.
What cool functionality and methods do you add to your ASP.net BasePage : System.Web.UI.Page classes?
Examples
Here's something I use for authentication, and I'd like to hear your opinions on this:
protected override void OnPreInit(EventArgs e)
{
base.OnPreInit(e);
// Authentication code omitted... Essentially same as below.
if (_RequiresAuthentication && !(IsAuthorized))
{
RespondForbidden("You do not have permissions to view this page.", UnauthorizedRedirect);
return;
}
}
// This function is overridden in each page subclass and fitted to each page's
// own authorization requirements.
// This also allows cascading authorization checks,
// e.g: User has permission to view page? No - base.IsAuthorized - Is user an admin?
protected virtual bool IsAuthorized
{
get { return true; }
}
My BasePage class contains an instance of this class:
public class StatusCodeResponse {
public StatusCodeResponse(HttpContext context) {
this._context = context;
}
/// <summary>
/// Responds with a specified status code, and if specified - transfers to a page.
/// </summary>
private void RespondStatusCode(HttpContext context, System.Net.HttpStatusCode status, string message, string transfer)
{
if (string.IsNullOrEmpty(transfer))
{
throw new HttpException((int)status, message);
}
context.Response.StatusCode = (int)status;
context.Response.StatusDescription = message;
context.Server.Transfer(transfer);
}
public void RespondForbidden(string message, string transfer)
{
RespondStatusCode(this._context, System.Net.HttpStatusCode.Forbidden, message, transfer);
}
// And a few more like these...
}
As a side note, this could be accomplished using extension methods for the HttpResponse object.
And another method I find quite handy for parsing querystring int arguments:
public bool ParseId(string field, out int result)
{
return (int.TryParse(Request.QueryString[field], out result) && result > 0);
}
Session related stuff, some complex object in the BasePage that maps to a session, and expose it as a property.
Doing stuff like filling a crumble pad object.
But most important: do not make your basepage into some helper class. Don't add stuff like ParseId(), that's just ridiculous.
Also, based on the first post: make stuff like IsAuthorized abstract. This way you don't create giant security holes if someone forgets that there is some virtual method.
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using System.Web;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
namespace MySite
{
/// <summary>
/// Base class with properties for meta tags for content pages
/// http://www.codeproject.com/KB/aspnet/PageTags.aspx
/// http://weblogs.asp.net/scottgu/archive/2005/08/02/421405.aspx
/// </summary>
public partial class BasePage : System.Web.UI.Page
{
private string keywords;
private string description;
/// <SUMMARY>
/// Gets or sets the Meta Keywords tag for the page
/// </SUMMARY>
public string Meta_Keywords
{
get
{
return keywords;
}
set
{
// Strip out any excessive white-space, newlines and linefeeds
keywords = Regex.Replace(value, "\\s+", " ");
}
}
/// <SUMMARY>
/// Gets or sets the Meta Description tag for the page
/// </SUMMARY>
public string Meta_Description
{
get
{
return description;
}
set
{
// Strip out any excessive white-space, newlines and linefeeds
description = Regex.Replace(value, "\\s+", " ");
}
}
// Constructor
// Add an event handler to Init event for the control
// so we can execute code when a server control (page)
// that inherits from this base class is initialized.
public BasePage()
{
Init += new EventHandler(BasePage_Init);
}
// Whenever a page that uses this base class is initialized,
// add meta keywords and descriptions if available
void BasePage_Init(object sender, EventArgs e)
{
if (!String.IsNullOrEmpty(Meta_Keywords))
{
HtmlMeta tag = new HtmlMeta();
tag.Name = "keywords";
tag.Content = Meta_Keywords;
Header.Controls.Add(tag);
}
if (!String.IsNullOrEmpty(Meta_Description))
{
HtmlMeta tag = new HtmlMeta();
tag.Name = "description";
tag.Content = Meta_Description;
Header.Controls.Add(tag);
}
}
}
}
Along with the metadata already mentioned (mostly obsolete in ASP.NET 4.0 with the new Page.MetaDescription and Page.MetaKeywords properties), I've also had methods to add other header links to my page such as specific ones for adding page specific CSS, or things like cannonical links, RSS links, etc:
/// <overloads>
/// Adds a CSS link to the page. Useful when you don't have access to the
/// HeadContent ContentPlaceHolder. This method has 4 overloads.
/// </overloads>
/// <summary>
/// Adds a CSS link.
/// </summary>
/// <param name="pathToCss">The path to CSS file.</param>
public void AddCss(string pathToCss) {
AddCss(pathToCss, string.Empty);
}
/// <summary>
/// Adds a CSS link in a specific position.
/// </summary>
/// <param name="pathToCss">The path to CSS.</param>
/// <param name="position">The postion.</param>
public void AddCss(string pathToCss, int? position) {
AddCss(pathToCss, string.Empty, position);
}
/// <summary>
/// Adds a CSS link to the page with a specific media type.
/// </summary>
/// <param name="pathToCss">The path to CSS file.</param>
/// <param name="media">The media type this stylesheet relates to.</param>
public void AddCss(string pathToCss, string media) {
AddHeaderLink(pathToCss, "text/css", "Stylesheet", media, null);
}
/// <summary>
/// Adds a CSS link to the page with a specific media type in a specific
/// position.
/// </summary>
/// <param name="pathToCss">The path to CSS.</param>
/// <param name="media">The media.</param>
/// <param name="position">The postion.</param>
public void AddCss(string pathToCss, string media, int? position) {
AddHeaderLink(pathToCss, "text/css", "Stylesheet", media, position);
}
/// <overloads>
/// Adds a general header link. Useful when you don't have access to the
/// HeadContent ContentPlaceHolder. This method has 3 overloads.
/// </overloads>
/// <summary>
/// Adds a general header link.
/// </summary>
/// <param name="href">The path to the resource.</param>
/// <param name="type">The type of the resource.</param>
public void AddHeaderLink(string href, string type) {
AddHeaderLink(href, type, string.Empty, string.Empty, null);
}
/// <summary>
/// Adds a general header link.
/// </summary>
/// <param name="href">The path to the resource.</param>
/// <param name="type">The type of the resource.</param>
/// <param name="rel">The relation of the resource to the page.</param>
public void AddHeaderLink(string href, string type, string rel) {
AddHeaderLink(href, type, rel, string.Empty, null);
}
/// <summary>
/// Adds a general header link.
/// </summary>
/// <param name="href">The path to the resource.</param>
/// <param name="type">The type of the resource.</param>
/// <param name="rel">The relation of the resource to the page.</param>
/// <param name="media">The media target of the link.</param>
public void AddHeaderLink(string href, string type, string rel, string media)
{
AddHeaderLink(href, type, rel, media, null);
}
/// <summary>
/// Adds a general header link.
/// </summary>
/// <param name="href">The path to the resource.</param>
/// <param name="type">The type of the resource.</param>
/// <param name="rel">The relation of the resource to the page.</param>
/// <param name="media">The media target of the link.</param>
/// <param name="position">The postion in the control order - leave as null
/// to append to the end.</param>
public void AddHeaderLink(string href, string type, string rel, string media,
int? position) {
var link = new HtmlLink { Href = href };
if (0 != type.Length) {
link.Attributes.Add(HtmlTextWriterAttribute.Type.ToString().ToLower(),
type);
}
if (0 != rel.Length) {
link.Attributes.Add(HtmlTextWriterAttribute.Rel.ToString().ToLower(),
rel);
}
if (0 != media.Length) {
link.Attributes.Add("media", media);
}
if (null == position || -1 == position) {
Page.Header.Controls.Add(link);
}
else
{
Page.Header.Controls.AddAt((int)position, link);
}
}
Culture initialization by overriding InitializeCulture() method (set culture and ui culture from cookie or DB).
Some of my applications are brandable, then here I do some "branding" stuff too.
I use this methot and thanks for yours,
/// <summary>
/// Displays the alert.
/// </summary>
/// <param name="message">The message to display.</param>
protected virtual void DisplayAlert(string message)
{
ClientScript.RegisterStartupScript(
GetType(),
Guid.NewGuid().ToString(),
string.Format("alert('{0}');", message.Replace("'", #"\'")),
true
);
}
/// <summary>
/// Finds the control recursive.
/// </summary>
/// <param name="id">The id.</param>
/// <returns>control</returns>
protected virtual Control FindControlRecursive(string id)
{
return FindControlRecursive(id, this);
}
/// <summary>
/// Finds the control recursive.
/// </summary>
/// <param name="id">The id.</param>
/// <param name="parent">The parent.</param>
/// <returns>control</returns>
protected virtual Control FindControlRecursive(string id, Control parent)
{
if (string.Compare(parent.ID, id, true) == 0)
return parent;
foreach (Control child in parent.Controls)
{
Control match = FindControlRecursive(id, child);
if (match != null)
return match;
}
return null;
}
Putting authorization code in a base page is generally not a good idea. The problem is, what happens if you forget to derive a page that needs authorization from the base page? You will have a security hole.
It's much better to use an HttpModule, so that you can intercept requests for all pages, and make sure users are authorized even before the HttpHandler has a chance to run.
Also, as others have said, and in keeping with OO principles, it's better to only have methods in your base page that actually relate to the Page itself. If they don't reference "this," they should probably be in a helper class -- or perhaps be extension methods.
I inherit from System.Web.UI.Page when I need certain properties and every page. This is good for aweb application that implements a login. In the membership pages I use my own base class to get access to Properties like UserID, UserName etc. These properties wrap Session Variables
Here are some examples (sans code) that I use a custom base class for:
Adding a page filter (e.g. replace "{theme}" with "~/App_Theme/[currentTheme]"),
Adding a Property and handling for Auto Titling pages based upon Site Map,
Registering specialized logging (could probably be redone via different means),
Adding methods for generalized input(Form/Querystring) validation, with blanket redirector: AddRequiredInput("WidgetID", PageInputType.QueryString, typeof(string)),
Site Map Helpers, allowing for things like changing a static "Edit Class" into something context related like "Edit Fall '10 Science 101"
ViewState Helpers, allowing me to register variable on the page to a name and have it automatically populate that variable from the viewstate or a default, and save the value back out to the viewstate at the end of the request.
Custom 404 Redirector, where I can pass an exception or message (or both) and it will go to a page I have predefined to nicely display and log it.
I personally like #5 the most because a) updating the SiteMap is ugly and I prefer not to have clutter the page, making it more readable, b) It makes the SiteMap much more user friendly.
,
Please refer Getting page specific info in ASP.Net Base Page
public abstract string AppSettingsRolesName { get; }
List<string> authorizedRoles = new List<string>((ConfigurationManager.AppSettings[AppSettingsRolesName]).Split(','))
if (!authorizedRoles.Contains(userRole))
{
Response.Redirect("UnauthorizedPage.aspx");
}
In derived Page
public override string AppSettingsRolesName
{
get { return "LogsScreenRoles"; }
}