How can I use Asp.Net Chart control in Asp.Net MVC 3? - asp.net-mvc-3

I know that there is a Chart control comes with the new Helpers library, but it doesn't have the same features as the Asp.Net Charting control. I have to represent a data where on the pie or the bar, I need to have a clickable link on the legend or the label.
I am using Asp.Net MVC 3 Razor and I couldn't tie the Asp.Net Chart control with this feature. I can show the chart but the links are not rendered.
Any suggestions?

You can use ActionResult to render the chart. On the following link is a blog post of Daniel A Hill - Rendering Microsoft .NET 4.0 Charts in ASP.NET MVC
using System;
using System.IO;
using System.Web.Mvc;
using System.Web.UI.DataVisualization.Charting;
namespace Serviscope.Proviso.Web.Code
{
public class ChartActionResult : ActionResult
{
private readonly Chart _chart;
private readonly ChartImageFormat _imageFormat;
public ChartActionResult(Chart chart, ChartImageFormat imageFormat = ChartImageFormat.Png)
{
if ( chart == null ) { throw new ArgumentNullException("chart"); }
_chart = chart;
_imageFormat = imageFormat;
}
public override void ExecuteResult(ControllerContext context)
{
var response = context.HttpContext.Response;
response.Clear();
response.Charset = String.Empty;
response.ContentType = "image/" + _imageFormat;
if ( _imageFormat == ChartImageFormat.Png )
{
// PNG can only write to a seek-able stream
// Thus we have to go through a memory stream, which permits seeking.
using ( var mStream = new MemoryStream() )
{
_chart.SaveImage(mStream, _imageFormat);
mStream.Seek(0, SeekOrigin.Begin);
mStream.CopyTo(response.OutputStream);
}
}
else
{ // If we don't have to provide a seek-able stream, write directly to
// where the data needs to go.
_chart.SaveImage(response.OutputStream, _imageFormat);
}
_chart.Dispose();
}
}
}
and example:
public ActionResult MyChart()
{
// Build Chart
var chart = new Chart()
{
Height = 300,
Width = 400,
BackGradientStyle = GradientStyle.TopBottom,
BackColor = Color.Gray,
BorderSkin = new BorderSkin() { SkinStyle = BorderSkinStyle.Emboss }
};
// Add Chart Area and Set 3-D Settings
chart.ChartAreas.Add(new ChartArea());
chart.ChartAreas[0].Area3DStyle = new ChartArea3DStyle()
{
Enable3D = true,
Perspective = 10,
Inclination = 30,
Rotation = 10
};
// Add Random values
chart.Series.Add(GenerateRandomSeries(10, 10));
chart.Series.Add(GenerateRandomSeries(10, 10));
chart.Series.Add(GenerateRandomSeries(10, 10));
// Return chart object, wrapped in our custom action result
return new ChartActionResult(chart);
}
private static readonly Random RandomPointGenerator = new Random();
private static Series GenerateRandomSeries(int max, int count)
{
var series = new Series();
series.ChartType = SeriesChartType.Line;
for (int x = 0; x < count; x++)
{
series.Points.AddXY(x + 1, RandomPointGenerator.Next(max));
}
return series;
}

You should just create a standard webforms page inside your ASP.NET MVC application.
Scott Hanselman explains how to do that here.

Related

How to create a cross-platform popup dialog in Xamarin?

In our Xamarin mobile app, I need to display a popup dialog that is timer based. Basically, if the user does not click on OK button, the dialog should still go away within ten seconds.
On the net, there are references to creating custom dialogs for Android and for iOS. However, I did not find any reference to creating a cross-platform dialog.
There seems to be a third party nuget package that creates popup dialogs -
http://www.sparkhound.com/learn/blog/creating-a-modal-popup-dialog-in-xamarin-forms, However, I would prefer not to use a third party package. Plus, I don't know if the library supports timer-based dialogs.
Is there any way to create a simple cross-platform dialog? From usage perspective, here is the prototype I am thinking:
static void DisplayAlert(string title, string body, int msec);
Answer
Here's a custom popup that I've created in Xamarin.Forms. It includes some fancy animations and even blurs the background. I've used it successfully in a couple apps that I've built.
You can trigger this custom popup by calling ShowView. It has a timer and will dismiss itself in 10 seconds, or you can dismiss it by calling HideView.
Code
Custom Popup Base Class
using System;
using System.Threading.Tasks;
using Xamarin.Forms;
namespace MyNamespace
{
public abstract class OverlayContentView : ContentView
{
#region Constant Fields
readonly BoxView _backgroundOverlayBoxView;
readonly Frame _overlayFrame;
readonly RelativeLayout _relativeLayout;
#endregion
#region Fields
View _overlayContent;
#endregion
#region Constructors
protected OverlayContentView(bool isChildOfNavigationPage)
{
_backgroundOverlayBoxView = new BoxView
{
BackgroundColor = ColorConstants.WhiteWith75Opacity
};
_backgroundOverlayBoxView.Opacity = 0;
_overlayFrame = new Frame
{
HasShadow = true,
BackgroundColor = Color.White
};
_overlayFrame.Scale = 0;
_relativeLayout = new RelativeLayout();
Func<RelativeLayout, double> getOverlayContentHeight = (p) => OverlayContent.Measure(p.Width, p.Height).Request.Height;
Func<RelativeLayout, double> getOverlayContentWidth = (p) => OverlayContent.Measure(p.Width, p.Height).Request.Width;
_relativeLayout.Children.Add(_backgroundOverlayBoxView,
Constraint.Constant(-10),
Constraint.Constant(0),
Constraint.RelativeToParent(parent => parent.Width + 20),
Constraint.RelativeToParent(parent => parent.Height)
);
_relativeLayout.Children.Add(_overlayFrame,
Constraint.RelativeToParent(parent => parent.Width / 2 - getOverlayContentWidth(parent) / 2 - 25),
Constraint.RelativeToParent(parent =>
{
switch (isChildOfNavigationPage)
{
case true:
return parent.Height / 4 - getOverlayContentHeight(parent) / 2;
default:
return parent.Height / 2 - getOverlayContentHeight(parent) / 2 - 10;
}
}),
Constraint.RelativeToParent(parent => getOverlayContentWidth(parent) + 50),
Constraint.RelativeToParent(parent => getOverlayContentHeight(parent) + 40)
);
}
#endregion
#region Properties
public View OverlayContent
{
get => _overlayContent;
set
{
_overlayContent = value;
_overlayContent.Scale = 0;
_overlayFrame.Content = _overlayContent;
Content = _relativeLayout;
}
}
#endregion
#region Methods
public void ShowView(bool shouldDisappearAfterTimeoutExpires = false, int timeoutInSeconds = 10)
{
const uint overlayContentViewAnimationTime = 300;
const double overlayContentViewMaxSize = 1.05;
const double overlayContentViewNormalSize = 1;
Device.BeginInvokeOnMainThread(async () =>
{
IsVisible = true;
_backgroundOverlayBoxView.Opacity = 1;
await Task.WhenAll(OverlayContent?.ScaleTo(overlayContentViewMaxSize, overlayContentViewAnimationTime, Easing.CubicOut),
_overlayFrame?.ScaleTo(overlayContentViewMaxSize, overlayContentViewAnimationTime, Easing.CubicOut));
await Task.WhenAll(OverlayContent?.ScaleTo(overlayContentViewNormalSize, overlayContentViewAnimationTime, Easing.CubicOut),
_overlayFrame?.ScaleTo(overlayContentViewNormalSize, overlayContentViewAnimationTime, Easing.CubicOut));
if (!shouldDisappearAfterTimeoutExpires)
return;
await Task.Delay(TimeSpan.FromSeconds(timeoutInSeconds));
HideView();
});
}
public void HideView()
{
Device.BeginInvokeOnMainThread(async () =>
{
await this.FadeTo(0);
IsVisible = false;
InputTransparent = true;
Opacity = 1;
_backgroundOverlayBoxView.Opacity = 0;
OverlayContent.Scale = 0;
_overlayFrame.Scale = 0;
});
}
#endregion
}
}
Implementation of Custom Popup
using Xamarin.Forms;
namespace MyNamespace
{
public class WelcomeView : OverlayContentView
{
public WelcomeView() : base(true)
{
const string titleText = "Welcome";
const string bodyText = "Enjoy InvestmentDataSampleApp";
const string okButtonText = "Ok, thanks!";
var titleLabel = new Label
{
FontAttributes = FontAttributes.Bold,
Text = titleText,
HorizontalTextAlignment = TextAlignment.Center
};
var bodyLabel = new Label
{
Text = bodyText,
HorizontalTextAlignment = TextAlignment.Center
};
var okButton = new Button
{
TextColor = Color.White,
FontAttributes = FontAttributes.Bold,
Margin = new Thickness(5),
Text = okButtonText,
BackgroundColor = new Color(0, 0, 0, 0.75),
TextColor = Color.White,
BorderWidthProperty = 1,
BorderColor = new Color(0, 0, 0, 0.75),
};
okButton.Clicked += (sender, e) => this.HideView();
var textAndButtonStack = new StackLayout
{
HorizontalOptions = LayoutOptions.CenterAndExpand,
Spacing = 20,
Children = {
titleLabel,
bodyLabel,
okButton
}
};
OverlayContent = textAndButtonStack;
}
}
}
Sample App
For reference, here's a sample app that has implemented the custom popup:
https://github.com/brminnick/InvestmentDataSampleApp
I would suggest having a look at this post, i answered some time ago: Display a popup with xamarin forms
Even though such a system takes some time to implement, it gives you the advantage to call any dialog from anywhere in your app without having to embed the dialog inside your content page(s).
If you want to have your dialog timed, you could simply call it with
Dialogs.ShowLoading();
Xamarin.Forms.Device.StartTimer(TimeSpan.FromSeconds(5), () => { Dialogs.Hide();
return false;
});

How to load an Image from Assets in Xamarin.Forms on Android?

I am using the following code:
var baseUrl = DependencyService.Get<IBaseUrl> ().Get ();
var backgroundImage = new Image () {
Source = FileImageSource.FromFile (
System.IO.Path.Combine (baseUrl, "Content", "images", "background-2.jpg")
)
};
Where the DependencyServices for iOS and Androids are as below:
// iOS
[assembly: Xamarin.Forms.Dependency (typeof (BaseUrl_iOS))]
namespace TuneProtectApp.iOS
{
public class BaseUrl_iOS : IBaseUrl
{
public BaseUrl_iOS () { }
public string Get ()
{
return NSBundle.MainBundle.BundlePath;
}
}
}
// Android
[assembly: Xamarin.Forms.Dependency (typeof (BaseUrl_Droid))]
namespace TuneProtectApp.Droid
{
public class BaseUrl_Droid : IBaseUrl
{
public BaseUrl_Droid () {}
public string Get ()
{
return "file:///android_asset/";
}
}
}
The backgroundImage loads fine on iOS but not on Android. How to load an Image from Assets in Xamarin.Forms on Android?
In my Xamarin.forms (shared) app I have a registration-page, where the user also have to select an image for his avatar. Based on the sex of the user, I show a male or a female symbol-image as default (the user then can select another, if he want to do).
I have implemented it as follows:
First created a sub-directory \Embedded for all projects (iOS, Android and WP) (directly in the project-root of each project-type).
Then added the two .jpg’s to the new directories in all projects.
In my app I have a global variable (GV.cEmbeddedAblage)
This is filled in startup-code:
string cNameSpace = "";
switch (Device.OS)
{
case TargetPlatform.WinPhone:
cNameSpace = "MatrixGuide.WinPhone";
break;
case TargetPlatform.iOS:
cNameSpace = "MatrixGuide.iOS";
break;
case TargetPlatform.Android:
cNameSpace = "MatrixGuide.Droid";
break;
//
}
GV.cEmbeddedAblage = cNameSpace + ".Embedded.";
Further, I create a global byte-array for the images (example to male):
static Byte[] _SymbolMann;
public static Byte[] ByteSymbolMann
{
get { return _SymbolMann; }
set { _SymbolMann = value; }
}
I then easily can access the images from shared code (on the registration-page) with (e.g.):
Generate the path, load image in byte-array (if not already loaded):
string cFilename = "";
if (GV.ByteSymbolMann == null) // not yet loaded - only load one time
{
cFilename = GV.cEmbeddedAblage + "SymbolMann.jpg";
var assembly = this.GetType().GetTypeInfo().Assembly;
byte[] buffer;
using (Stream s = assembly.GetManifestResourceStream(cFilename))
{
long length = s.Length;
buffer = new byte[length];
s.Read(buffer, 0, (int)length);
GV.ByteSymbolMann = buffer;
}
}
Fill another byte.array (with selected (loaded) male- / female- image):
AvatarErfassung = GV.ByteSymbolMann;
create the image on the page:
var Avatar = new Image { HeightRequest = 70, WidthRequest = 70, HorizontalOptions = LayoutOptions.Start };
Overtake the selected image as Source to the Image:
Avatar.Source = ImageSource.FromStream(() => new MemoryStream(AvatarErfassung));
You should be able to do it similar...

Can one use system icons on tabs in Xamarin Forms?

Is there a way to specify a "system" icon to be displayed on a tab when using Xamarin Forms? I would like to use icons such as Favourites, Bookmark, History etc but I do not want to supply all my own images for the various platforms.
Using Xamarin.iOS one can use this syntax:
tab1.TabBarItem = new UITabBarItem (UITabBarSystemItem.Favorites, 0);
I can however not find how to do this in the cross-platform Xamarin.Forms project.
This is my current code:
var profilePage = new ContentPage {
Title = "Profile",
//This requires my own images to be added to the project whereas
//I wish to use built-in images which are platform specific for
//Favourites, Bookmark, More, etc...
//Icon = "Profile.png",
Content = new StackLayout {
Spacing = 20, Padding = 50,
VerticalOptions = LayoutOptions.Center,
Children = {
new Entry { Placeholder = "Username" },
new Entry { Placeholder = "Password", IsPassword = true },
new Button {
Text = "Login",
TextColor = Color.White,
BackgroundColor = Color.FromHex("77D065") }}}};
var settingsPage = new ContentPage {
Title = "Settings",
Content = new StackLayout {
Spacing = 20, Padding = 50,
VerticalOptions = LayoutOptions.Center,
Children = {
new Entry { Placeholder = "Username" },
new Entry { Placeholder = "Password", IsPassword = true }}}
};
MainPage = new TabbedPage { Children = {profilePage, settingsPage} };
For iOS
you need a custom renderer for your page. In my example, it is CustomTabsPage class. You cannot just use system icons to create a UIImage. We need to use UITabBarItem. The problem is that UITabBarItem doesn't allow changes to either title or image/icon. But, we can copy an image from it.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UIKit;
using ButtonRendererDemo;
using ButtonRendererDemo.iOS;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
[assembly: ExportRenderer(typeof(CustomTabsPage), typeof(CustomTabsPageRenderer))]
namespace ButtonRendererDemo.iOS
{
public class CustomTabsPageRenderer : TabbedRenderer
{
#region Sytem Image with custom title
public override void ViewWillAppear(bool animated)
{
base.ViewWillAppear(animated);
foreach (var item in TabBar.Items)
{
item.Image = GetTabIcon(item.Title);
}
}
private UIImage GetTabIcon(string title)
{
UITabBarItem item = null;
switch (title)
{
case "Profile":
item = new UITabBarItem(UITabBarSystemItem.Search, 0);
break;
case "Settings":
item = new UITabBarItem(UITabBarSystemItem.Bookmarks, 0);
break;
}
var img = (item != null) ? UIImage.FromImage(item.SelectedImage.CGImage, item.SelectedImage.CurrentScale, item.SelectedImage.Orientation) : new UIImage();
return img;
}
#endregion
}
}
For Android
things are easier
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ButtonRendererDemo;
using ButtonRendererDemo.Droid;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
using Xamarin.Forms.Platform.Android.AppCompat;
using Android.Support.Design.Widget;
[assembly: ExportRenderer(typeof(CustomTabsPage), typeof(CustomTabsPageRenderer))]
namespace ButtonRendererDemo.Droid
{
public class CustomTabsPageRenderer : TabbedPageRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<TabbedPage> e)
{
base.OnElementChanged(e);
//var layout = (TabLayout)ViewGroup.GetChildAt(1); //should be enough but just for robustness we use loop below
TabLayout layout = null;
for (int i = 0; i < ChildCount; i++)
{
layout = GetChildAt(i) as TabLayout;
if (layout != null)
break;
}
if (layout != null)
{
for (int tabIndex = 0; tabIndex < layout.TabCount; tabIndex++)
SetTabIcon(layout, tabIndex);
}
}
private void SetTabIcon(TabLayout layout, int tabIndex)
{
var tab = layout.GetTabAt(tabIndex);
switch (tabIndex)
{
case 0:
tab.SetIcon(Resource.Drawable.icon2);//from local resource
break;
case 1:
tab.SetIcon(Resource.Drawable.ic_media_play_dark);//from Android system, depends on version !
break;
}
}
}
}
In order to use icons, you need a platform-specific structure. In Xamarin.Forms, for this to work:
Icon = "youricon.png";
You need:
iOS: put the image in /Resources/youricon.png
Android: put the image in /Resources/drawable/youricon.png
Win Phone: put the image in the Windows Phone application project root.
You should write custom TabbedPage renderer for iOS project:
public class YourTabbedRenderer : TabbedRenderer {
public override void ViewWillAppear(bool animated)
{
base.ViewWillAppear(animated);
var items = TabBar.Items;
for (var i = 0; i < items.Length; i++) {
// set your icons here, you could do some string comparison (check tab title or tab icon resource name)
// items[i].Image =
// items[i].SelectedImage =
}
}
}
http://developer.xamarin.com/guides/cross-platform/xamarin-forms/custom-renderer/

Bind text with links to RichTextBox

I need to bind text which may contain hyperlinks to RichTextBox so it could show text as normal text and links as hyperlinks.
For example I have following text:
Join us on social networks
http://www.facebook.com/
I want that links in a text be hyperlinks so the result in RichTextBox would be like this:
Join us on social networks
http://www.facebook.com/
I implemented what I need
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Text.RegularExpressions;
using System.Windows.Media;
namespace NazarGrynko.UI.Controls
{
public class MyRichTextBox : RichTextBox
{
private const string UrlPattern = #"(http|ftp|https):\/\/[\w\-_]+(\.[\w\-_]+)+([\w\-\.,#?^=%&:/~\+#]*[\w\-\#?^=%&/~\+#])?";
public static readonly DependencyProperty TextProperty =
DependencyProperty.Register("Text", typeof (string), typeof(MyRichTextBox ), new PropertyMetadata(default(string), TextPropertyChanged));
public string Text
{
get { return (string) GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}
private static void TextPropertyChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
{
var richTextBox = (MyRichTextBox)dependencyObject;
var text = (string) dependencyPropertyChangedEventArgs.NewValue;
int textPosition = 0;
var paragraph = new Paragraph();
var urlMatches = Regex.Matches(text, UrlPattern);
foreach (Match urlMatch in urlMatches)
{
int urlOccurrenceIndex = text.IndexOf(urlMatch.Value, textPosition, StringComparison.Ordinal);
if (urlOccurrenceIndex == 0)
{
var hyperlink = new Hyperlink
{
NavigateUri = new Uri(urlMatch.Value),
TargetName = "_blank",
Foreground = Application.Current.Resources["PhoneAccentBrush"] as Brush
};
hyperlink.Inlines.Add(urlMatch.Value);
paragraph.Inlines.Add(hyperlink);
textPosition += urlMatch.Value.Length;
}
else
{
paragraph.Inlines.Add(text.Substring(textPosition, urlOccurrenceIndex - textPosition));
textPosition += urlOccurrenceIndex - textPosition;
var hyperlink = new Hyperlink
{
NavigateUri = new Uri(urlMatch.Value),
TargetName = "_blank",
Foreground = Application.Current.Resources["PhoneAccentBrush"] as Brush
};
hyperlink.Inlines.Add(urlMatch.Value);
paragraph.Inlines.Add(hyperlink);
textPosition += urlMatch.Value.Length;
}
}
if (urlMatches.Count == 0)
{
paragraph.Inlines.Add(text);
}
richTextBox.Blocks.Add(paragraph);
}
}
}
Using example:
<MyRichTextBox Text="{Binding Message}"/>
Parse the Hyperlink, and create following structure (With C#, of course):
<RichTextBlock>
<Run>Hello World!</Run>
<Hyperlink NavigateUri="http://www.stackoverflow.com">http://www.stackoverflow.com</Hyperlink>
Thanks for the solution!
One minor modification I made was right at the end, I replaced the check on the count, with a line that just adds a substring of the full text, this way it does not truncate everything after the last URL, all text is retained.
paragraph.Inlines.Add(text.Substring(textPosition, text.Length - textPosition));
//if (urlMatches.Count == 0)
//{
// paragraph.Inlines.Add(text);
//}

How can I populate more than one Silverlight Image from Bing Maps asynchronous calls?

I have the following code, which works fine if you just want to populate one Image with a response from Bing Maps. But if I try to do two then the variable _currentImage always ends up being "image1" because the calls are asynchronous. How can I pass the image variable along to the ImageryServiceGetMapUriCompleted method?
using System;
using System.Windows.Controls;
using System.Windows.Media.Imaging;
using BasicBingMapsImagerySvc.ImageryService;
namespace BasicBingMapsImagerySvc
{
public partial class MainPage : UserControl
{
private const string BingMapsKey = "my key";
private Image _currentImage;
public MainPage()
{
InitializeComponent();
GetMap(42.573377, -101.032251, image0, MapStyle.AerialWithLabels);
GetMap(42.573377, -101.032251, image1, MapStyle.Road_v1);
}
private void GetMap(double lat, double lon, Image image, MapStyle mapStyle)
{
var mapUriRequest = new MapUriRequest();
// Set credentials using a valid Bing Maps key
mapUriRequest.Credentials = new Credentials();
mapUriRequest.Credentials.ApplicationId = BingMapsKey;
// Set the location of the requested image
mapUriRequest.Center = new Location();
mapUriRequest.Center.Latitude = lat;
mapUriRequest.Center.Longitude = lon;
// Set the map style and zoom level
var mapUriOptions = new MapUriOptions();
mapUriOptions.Style = mapStyle;
mapUriOptions.ZoomLevel = 13;
// Set the size of the requested image to match the size of the image control
mapUriOptions.ImageSize = new SizeOfint();
mapUriOptions.ImageSize.Height = 256;
mapUriOptions.ImageSize.Width = 256;
mapUriRequest.Options = mapUriOptions;
var imageryService = new ImageryServiceClient("BasicHttpBinding_IImageryService");
imageryService.GetMapUriCompleted += ImageryServiceGetMapUriCompleted;
_currentImage = image;
imageryService.GetMapUriAsync(mapUriRequest);
}
private void ImageryServiceGetMapUriCompleted(object sender, GetMapUriCompletedEventArgs e)
{
// The result is an MapUriResponse Object
MapUriResponse mapUriResponse = e.Result;
var bmpImg = new BitmapImage(new Uri(mapUriResponse.Uri));
_currentImage.Source = bmpImg;
}
}
}
You could use a lambda expression / delegate for your event handler, which allows you to 'capture' the reference to the image:
var imageryService = new ImageryServiceClient("BasicHttpBinding_IImageryService");
imageryService.GetMapUriCompleted += (s,e) =>
{
// The result is an MapUriResponse Object
MapUriResponse mapUriResponse = e.Result;
var bmpImg = new BitmapImage(new Uri(mapUriResponse.Uri));
// set the image source
image.Source = bmpImg;
};

Resources