Skip to content

Instantly share code, notes, and snippets.

@kellyelton
Created August 2, 2017 19:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kellyelton/9f3634e428cfb26d84dc8b2f680d5840 to your computer and use it in GitHub Desktop.
Save kellyelton/9f3634e428cfb26d84dc8b2f680d5840 to your computer and use it in GitHub Desktop.
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Media;
using System.Xml;
using Octgn.DataNew.Entities;
using System.IO;
using System.Windows.Media.Imaging;
using System.Xml.Linq;
namespace Octgn.Controls
{
public class RichTextBlock : TextBlock
{
public static DependencyProperty InlineProperty;
static RichTextBlock()
{
//OverrideMetadata call tells the system that this element wants to provide a style that is different than in base class
DefaultStyleKeyProperty.OverrideMetadata(typeof(RichTextBlock), new FrameworkPropertyMetadata(
typeof(RichTextBlock)));
InlineProperty = DependencyProperty.Register("RichText", typeof(List<Inline>), typeof(RichTextBlock),
new PropertyMetadata(null, new PropertyChangedCallback(OnInlineChanged)));
}
public List<Inline> RichText
{
get { return (List<Inline>)GetValue(InlineProperty); }
set { SetValue(InlineProperty, value); }
}
public static void OnInlineChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
if (e.NewValue == e.OldValue)
return;
RichTextBlock r = sender as RichTextBlock ?? throw new InvalidOperationException($"{nameof(sender)} of type {sender?.GetType().FullName} was not expected.");
List<Inline> i = e.NewValue as List<Inline> ?? throw new InvalidOperationException($"{nameof(e.NewValue)} of type {e.NewValue?.GetType().FullName} was not expected.");;
r.Inlines.Clear();
foreach (Inline inline in i)
{
r.Inlines.Add(inline);
}
}
}
public class StyledTextConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var propval = value as PropertyDefValue;
if (propval == null) throw new ArgumentInvalidException(nameof(value));
if (!(propval.Value is XElement)) throw new InvalidOperationException($"{nameof(PropertyDefValue)}.{nameof(Value)} is the wrong type");
Span span = new Span();
InternalProcess(span, (XElement)propval.Value, parameter as Game);
return span.Inlines.ToList();
}
public object ConvertBack(object value, Type targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
private static void InternalProcess(Span span, XElement xmlNode, Game game)
{
foreach (XNode child in xmlNode.Nodes())
{
if (child is XText text)
{
span.Inlines.Add(new Run(text.Value));
}
else if (child is XElement element)
{
switch (element.Name.ToString().ToUpper())
{
case "B":
case "BOLD":
{
Span boldSpan = new Span();
InternalProcess(boldSpan, element, game);
Bold bold = new Bold(boldSpan);
span.Inlines.Add(bold);
break;
}
case "I":
case "ITALIC":
{
Span italicSpan = new Span();
InternalProcess(italicSpan, element, game);
Italic italic = new Italic(italicSpan);
span.Inlines.Add(italic);
break;
}
case "U":
case "UNDERLINE":
{
Span underlineSpan = new Span();
InternalProcess(underlineSpan, element, game);
Underline underline = new Underline(underlineSpan);
span.Inlines.Add(underline);
break;
}
case "C":
case "COLOR":
{
Span colorSpan = new Span();
InternalProcess(colorSpan, element, game);
try
{
colorSpan.Foreground = new BrushConverter().ConvertFromString(element.Attribute("value").Value) as SolidColorBrush;
}
catch (Exception ex) { //TODO: specify the exception we are actually expecting to get here
/* this was the easiest way to make sure that the color string was valid */
Log.Warn("Error parsing Foreground", ex);
}
span.Inlines.Add(colorSpan);
break;
}
case "S":
case "SYMBOL":
{
var symbolId = element.Attribute("value").Value;
Symbol symbol = game.Symbols.FirstOrDefault(x => x.Id == symbolId);
if (symbol == null) throw new InvalidOperationException($"Could not find symbol {symbolId}");
var image = new Image
{
Margin = new Thickness(0,0,0,-2),
Height = span.FontSize + 2,
Stretch = Stretch.Uniform,
Source = new BitmapImage(new Uri(symbol.Source)),
ToolTip = symbol.Name
};
var symbolSpan = new InlineUIContainer();
symbolSpan.Child = image;
span.Inlines.Add(symbolSpan);
break;
}
}
}
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment