Skip to content

Instantly share code, notes, and snippets.

@ChaseFlorell
Last active February 9, 2016 23:47
Show Gist options
  • Save ChaseFlorell/7211ffd025f4befcfa9e to your computer and use it in GitHub Desktop.
Save ChaseFlorell/7211ffd025f4befcfa9e to your computer and use it in GitHub Desktop.
Bindable Markdown View for use with MvvmCross (Mvx) on the Android and iOS platforms.

Bindable Markdown View for use with MvvmCross on the Android platform.


Dependencies:

Keywords:
mvvmcross, mvvm cross, mvx, xamarin, android, monodroid, markdown, markdowndeep, binding, bindable, bind

using System;
using Android.Content;
using Android.Util;
using Android.Webkit;
using MarkdownDeep;
namespace FutureState.Droid.Ui.Controls
{
public class BindalbeMarkdownView : WebView
{
private readonly Markdown _markdownDeep;
private string _markdown;
public BindableMarkdownView(Context context, IAttributeSet attrs)
: base(context, attrs)
{
_markdownDeep = new Markdown();
}
public string Markdown
{
get { return _markdown; }
set
{
if (string.IsNullOrEmpty(value)) return;
_markdown = _markdownDeep.Transform(value);
LoadData(_markdown, "text/html", "utf-8");
UpdatedHtmlContent();
}
}
public event EventHandler HtmlContentChanged;
private void UpdatedHtmlContent()
{
var handler = HtmlContentChanged;
if (handler != null)
handler(this, EventArgs.Empty);
}
}
}
using System;
using System.Drawing;
using System.Text;
using MarkdownDeep;
using MonoTouch.Foundation;
using MonoTouch.UIKit;
namespace FutureState.BreathingRoom.Touch.Ui.Controls
{
public class BindableUIMarkdownView : UILabel
{
private readonly Markdown _markdownDeep;
private string _markdown;
private string _style;
public BindableUIMarkdownView()
{
_markdownDeep = new Markdown();
Insets = new UIEdgeInsets(0, 0, 0, 0);
}
public BindableUIMarkdownView(RectangleF frame)
: base(frame)
{
_markdownDeep = new Markdown();
Insets = new UIEdgeInsets(0, 0, 0, 0);
}
[Obsolete("Font wont work because the markdown renders HTML. Please use the Style property.")]
public new UIFont Font { get; set; }
public string Style
{
get
{
return string.IsNullOrWhiteSpace(_style) ? DefaultStyle : _style;
}
set
{
_style = value;
}
}
public UIEdgeInsets Insets { get; set; }
public string Markdown
{
get { return _markdown; }
set
{
if (string.IsNullOrEmpty(value) || _markdown == value) return;
_markdown = _markdownDeep.Transform(value);
var html = new StringBuilder();
html.Append("<html>");
html.Append(string.Format("<style>{0}</style>", Style));
html.Append("<body>");
html.Append(_markdown);
html.Append("</body>");
html.Append("</html>");
var attr = new NSAttributedStringDocumentAttributes { DocumentType = NSDocumentType.HTML };
var nsError = new NSError();
var output = new NSAttributedString(html.ToString(), attr, ref nsError);
AttributedText = output;
HandleHtmlContentChanged();
}
}
public override void DrawText(RectangleF frame)
{
Layer.Bounds = new RectangleF(frame.X, frame.Y, frame.Width, frame.Height + Insets.Top + Insets.Bottom);
base.DrawText(new RectangleF(
frame.X + Insets.Left,
frame.Y + Insets.Top,
frame.Width - Insets.Left - Insets.Right,
frame.Height));
}
public event EventHandler HtmlContentChanged;
private void HandleHtmlContentChanged()
{
var handler = HtmlContentChanged;
if (handler != null)
handler(this, EventArgs.Empty);
}
private const string DefaultStyle = @"
body {
font-family: Helvetica, arial, sans-serif;
font-size: 14px;
line-height: 1.6;
padding-top: 10px;
padding-bottom: 10px;
background-color: white;
padding: 30px;
margin: 10px;
color: #333;
}
body > *:first-child {
margin-top: 0 !important;
}
body > *:last-child {
margin-bottom: 0 !important;
}
a {
color: #4183C4;
text-decoration: none;
}
a.absent {
color: #cc0000;
}
a.anchor {
display: block;
padding-left: 30px;
margin-left: -30px;
cursor: pointer;
position: absolute;
top: 0;
left: 0;
bottom: 0;
}
h1, h2, h3, h4, h5, h6 {
margin: 20px 0 10px;
padding: 0;
font-weight: bold;
-webkit-font-smoothing: antialiased;
cursor: text;
position: relative;
}
h2:first-child, h1:first-child, h1:first-child + h2, h3:first-child, h4:first-child, h5:first-child, h6:first-child {
margin-top: 0;
padding-top: 0;
}
h1:hover a.anchor, h2:hover a.anchor, h3:hover a.anchor, h4:hover a.anchor, h5:hover a.anchor, h6:hover a.anchor {
text-decoration: none;
}
h1 tt, h1 code {
font-size: inherit;
}
h2 tt, h2 code {
font-size: inherit;
}
h3 tt, h3 code {
font-size: inherit;
}
h4 tt, h4 code {
font-size: inherit;
}
h5 tt, h5 code {
font-size: inherit;
}
h6 tt, h6 code {
font-size: inherit;
}
h1 {
font-size: 28px;
color: black;
}
h2 {
font-size: 24px;
border-bottom: 1px solid #cccccc;
color: black;
}
h3 {
font-size: 18px;
}
h4 {
font-size: 16px;
}
h5 {
font-size: 14px;
}
h6 {
color: #777777;
font-size: 14px;
}
p, blockquote, ul, ol, dl, li, table, pre {
margin: 15px 0;
}
hr {
border: 0 none;
color: #222222;
height: 4px;
padding: 0;
}
body > h2:first-child {
margin-top: 0;
padding-top: 0;
}
body > h1:first-child {
margin-top: 0;
padding-top: 0;
}
body > h1:first-child + h2 {
margin-top: 0;
padding-top: 0;
}
body > h3:first-child, body > h4:first-child, body > h5:first-child, body > h6:first-child {
margin-top: 0;
padding-top: 0;
}
a:first-child h1, a:first-child h2, a:first-child h3, a:first-child h4, a:first-child h5, a:first-child h6 {
margin-top: 0;
padding-top: 0;
}
h1 p, h2 p, h3 p, h4 p, h5 p, h6 p {
margin-top: 0;
}
li p.first {
display: inline-block;
}
ul, ol {
padding-left: 30px;
}
ul :first-child, ol :first-child {
margin-top: 0;
}
ul :last-child, ol :last-child {
margin-bottom: 0;
}
dl {
padding: 0;
}
dl dt {
font-size: 14px;
font-weight: bold;
font-style: italic;
padding: 0;
margin: 15px 0 5px;
}
dl dt:first-child {
padding: 0;
}
dl dt > :first-child {
margin-top: 0;
}
dl dt > :last-child {
margin-bottom: 0;
}
dl dd {
margin: 0 0 15px;
padding: 0 15px;
}
dl dd > :first-child {
margin-top: 0;
}
dl dd > :last-child {
margin-bottom: 0;
}
blockquote {
border-left: 4px solid #dddddd;
padding: 15px;
margin: 15px;
color: #777777;
}
blockquote > :first-child {
margin-top: 0;
}
blockquote > :last-child {
margin-bottom: 0;
}
table {
padding: 0;
}
table tr {
border-top: 1px solid #cccccc;
background-color: white;
margin: 0;
padding: 0;
}
table tr:nth-child(2n) {
background-color: #f8f8f8;
}
table tr th {
font-weight: bold;
border: 1px solid #cccccc;
text-align: left;
margin: 0;
padding: 6px 13px;
}
table tr td {
border: 1px solid #cccccc;
text-align: left;
margin: 0;
padding: 6px 13px;
}
table tr th :first-child, table tr td :first-child {
margin-top: 0;
}
table tr th :last-child, table tr td :last-child {
margin-bottom: 0;
}
img {
max-width: 100%;
}
span.frame {
display: block;
overflow: hidden;
}
span.frame > span {
border: 1px solid #dddddd;
display: block;
float: left;
overflow: hidden;
margin: 13px 0 0;
padding: 7px;
width: auto;
}
span.frame span img {
display: block;
float: left;
}
span.frame span span {
clear: both;
color: #333333;
display: block;
padding: 5px 0 0;
}
span.align-center {
display: block;
overflow: hidden;
clear: both;
}
span.align-center > span {
display: block;
overflow: hidden;
margin: 13px auto 0;
text-align: center;
}
span.align-center span img {
margin: 0 auto;
text-align: center;
}
span.align-right {
display: block;
overflow: hidden;
clear: both;
}
span.align-right > span {
display: block;
overflow: hidden;
margin: 13px 0 0;
text-align: right;
}
span.align-right span img {
margin: 0;
text-align: right;
}
span.float-left {
display: block;
margin-right: 13px;
overflow: hidden;
float: left;
}
span.float-left span {
margin: 13px 0 0;
}
span.float-right {
display: block;
margin-left: 13px;
overflow: hidden;
float: right;
}
span.float-right > span {
display: block;
overflow: hidden;
margin: 13px auto 0;
text-align: right;
}
code, tt {
margin: 0 2px;
padding: 0 5px;
white-space: nowrap;
border: 1px solid #eaeaea;
background-color: #f8f8f8;
border-radius: 3px;
}
pre code {
margin: 0;
padding: 0;
white-space: pre;
border: none;
background: transparent;
}
.highlight pre {
background-color: #f8f8f8;
border: 1px solid #cccccc;
font-size: 13px;
line-height: 19px;
overflow: auto;
padding: 6px 10px;
border-radius: 3px;
}
pre {
background-color: #f8f8f8;
border: 1px solid #cccccc;
font-size: 13px;
line-height: 19px;
overflow: auto;
padding: 6px 10px;
border-radius: 3px;
}
pre code, pre tt {
background-color: transparent;
border: none;
}";
}
}
<BindalbeMarkdownView
android:id="@+id/MyWebContent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:layout_marginBottom="10dp"
android:padding="10dp"
android:textColor="@color/breathingroom_mediumgray"
local:MvxBind="Markdown MyMarkdownProperty/>
var myMarkdown = new BindableMarkdownView {
TextColor = CustomUIColor.breathingroom_darkgray,
BackgroundColor = UIColor.Clear,
Lines = 0,
Insets = new UIEdgeInsets(0, 5, 10, 5),
};
myMarkdown.Layer.CornerRadius = 3;
myMarkdown.Layer.BorderColor = UIColor.Gray.CGColor;
myMarkdown.Layer.BackgroundColor = UIColor.White.CGColor;
var set = this.CreateBindingSet<SomeView, SomeViewModel>();
set.Bind(myMarkdown).For(p => p.Markdown).To(vm => vm.MyMarkdownProperty);
set.Apply();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment