diff --git a/HandyControl/Controls/Attach/BorderElement.cs b/HandyControl/Controls/Attach/BorderElement.cs
index 05db296b..c0352bf9 100644
--- a/HandyControl/Controls/Attach/BorderElement.cs
+++ b/HandyControl/Controls/Attach/BorderElement.cs
@@ -1,4 +1,9 @@
-using System.Windows;
+using System;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using HandyControl.Data;
+using HandyControl.Tools.Converter;
namespace HandyControl.Controls
{
@@ -10,5 +15,41 @@ namespace HandyControl.Controls
public static void SetCornerRadius(DependencyObject element, CornerRadius value) => element.SetValue(CornerRadiusProperty, value);
public static CornerRadius GetCornerRadius(DependencyObject element) => (CornerRadius)element.GetValue(CornerRadiusProperty);
+
+ public static readonly DependencyProperty CircularProperty = DependencyProperty.RegisterAttached(
+ "Circular", typeof(bool), typeof(BorderElement), new PropertyMetadata(ValueBoxes.FalseBox, OnCircularChanged));
+
+ private static void OnCircularChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
+ {
+ if (d is Border border)
+ {
+ if ((bool)e.NewValue)
+ {
+ border.SetBinding(FrameworkElement.MinWidthProperty,
+ new Binding(FrameworkElement.ActualWidthProperty.Name) { Source = border });
+ border.SetBinding(FrameworkElement.MinHeightProperty,
+ new Binding(FrameworkElement.ActualHeightProperty.Name) { Source = border });
+ var binding = new MultiBinding
+ {
+ Converter = new BorderCircularConverter()
+ };
+ binding.Bindings.Add(new Binding(FrameworkElement.ActualWidthProperty.Name) {Source = border});
+ binding.Bindings.Add(new Binding(FrameworkElement.ActualHeightProperty.Name) { Source = border });
+ border.SetBinding(Border.CornerRadiusProperty, binding);
+ }
+ else
+ {
+ BindingOperations.ClearBinding(border, FrameworkElement.MinWidthProperty);
+ BindingOperations.ClearBinding(border, FrameworkElement.MinHeightProperty);
+ BindingOperations.ClearBinding(border, Border.CornerRadiusProperty);
+ }
+ }
+ }
+
+ public static void SetCircular(DependencyObject element, bool value)
+ => element.SetValue(CircularProperty, value);
+
+ public static bool GetCircular(DependencyObject element)
+ => (bool) element.GetValue(CircularProperty);
}
}
\ No newline at end of file
diff --git a/HandyControl/Controls/Attach/VisualElement.cs b/HandyControl/Controls/Attach/VisualElement.cs
index 511922bc..2e748dae 100644
--- a/HandyControl/Controls/Attach/VisualElement.cs
+++ b/HandyControl/Controls/Attach/VisualElement.cs
@@ -12,6 +12,6 @@ namespace HandyControl.Controls
=> element.SetValue(HighlightBrushProperty, value);
public static Brush GetHighlightBrush(DependencyObject element)
- => (Brush) element.GetValue(HighlightBrushProperty);
+ => (Brush) element.GetValue(HighlightBrushProperty);
}
}
\ No newline at end of file
diff --git a/HandyControl/Controls/Base/IGravatarGenerator.cs b/HandyControl/Controls/Base/IGravatarGenerator.cs
new file mode 100644
index 00000000..37ddca34
--- /dev/null
+++ b/HandyControl/Controls/Base/IGravatarGenerator.cs
@@ -0,0 +1,7 @@
+namespace HandyControl.Controls
+{
+ public interface IGravatarGenerator
+ {
+ object GetGravatar(string id);
+ }
+}
\ No newline at end of file
diff --git a/HandyControl/Controls/Other/Badge.cs b/HandyControl/Controls/Other/Badge.cs
new file mode 100644
index 00000000..0eaf688b
--- /dev/null
+++ b/HandyControl/Controls/Other/Badge.cs
@@ -0,0 +1,9 @@
+using System.Windows.Controls;
+
+namespace HandyControl.Controls
+{
+ public class Badge : ContentControl
+ {
+
+ }
+}
\ No newline at end of file
diff --git a/HandyControl/Controls/Other/Dialog.cs b/HandyControl/Controls/Other/Dialog.cs
new file mode 100644
index 00000000..1b6f1bc0
--- /dev/null
+++ b/HandyControl/Controls/Other/Dialog.cs
@@ -0,0 +1,9 @@
+using System.Windows.Controls;
+
+namespace HandyControl.Controls
+{
+ public class Dialog : ContentControl
+ {
+
+ }
+}
\ No newline at end of file
diff --git a/HandyControl/Controls/Other/Gravatar.cs b/HandyControl/Controls/Other/Gravatar.cs
new file mode 100644
index 00000000..1ba9da89
--- /dev/null
+++ b/HandyControl/Controls/Other/Gravatar.cs
@@ -0,0 +1,51 @@
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Media;
+using HandyControl.Tools;
+
+namespace HandyControl.Controls
+{
+ public class Gravatar : ContentControl
+ {
+ public static readonly DependencyProperty GeneratorProperty = DependencyProperty.Register(
+ "Generator", typeof(IGravatarGenerator), typeof(Gravatar), new PropertyMetadata(new GithubGravatarGenerator()));
+
+ public IGravatarGenerator Generator
+ {
+ get => (IGravatarGenerator) GetValue(GeneratorProperty);
+ set => SetValue(GeneratorProperty, value);
+ }
+
+ public static readonly DependencyProperty IdProperty = DependencyProperty.Register(
+ "Id", typeof(string), typeof(Gravatar), new PropertyMetadata(default(string), OnIdChanged));
+
+ private static void OnIdChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
+ {
+ var ctl = (Gravatar) d;
+ if (ctl.Source != null) return;
+ ctl.Content = ctl.Generator.GetGravatar((string)e.NewValue);
+ }
+
+ public string Id
+ {
+ get => (string) GetValue(IdProperty);
+ set => SetValue(IdProperty, value);
+ }
+
+
+ public static readonly DependencyProperty SourceProperty = DependencyProperty.Register(
+ "Source", typeof(ImageSource), typeof(Gravatar), new PropertyMetadata(default(ImageSource), OnSourceChanged));
+
+ private static void OnSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
+ {
+ var ctl = (Gravatar)d;
+ ctl.Background = new ImageBrush((ImageSource)e.NewValue);
+ }
+
+ public ImageSource Source
+ {
+ get => (ImageSource) GetValue(SourceProperty);
+ set => SetValue(SourceProperty, value);
+ }
+ }
+}
\ No newline at end of file
diff --git a/HandyControl/HandyControl.csproj b/HandyControl/HandyControl.csproj
index efbf174e..4f14d102 100644
--- a/HandyControl/HandyControl.csproj
+++ b/HandyControl/HandyControl.csproj
@@ -86,6 +86,7 @@
+
@@ -108,10 +109,13 @@
+
+
+
@@ -174,8 +178,11 @@
+
+
+
@@ -384,6 +391,10 @@
Designer
MSBuild:Compile
+
+ Designer
+ MSBuild:Compile
+
Designer
MSBuild:Compile
@@ -436,6 +447,10 @@
Designer
MSBuild:Compile
+
+ Designer
+ MSBuild:Compile
+
Designer
MSBuild:Compile
diff --git a/HandyControl/Properties/Langs/Lang.en.resx b/HandyControl/Properties/Langs/Lang.en.resx
index b5f9a98b..28b6a0dc 100644
--- a/HandyControl/Properties/Langs/Lang.en.resx
+++ b/HandyControl/Properties/Langs/Lang.en.resx
@@ -1,95 +1,76 @@
+ Microsoft ResX Schema
+
+ Version 1.3
+
+ The primary goals of this format is to allow a simple XML format
+ that is mostly human readable. The generation and parsing of the
+ various data types are done through the TypeConverter classes
+ associated with the data types.
+
+ Example:
+
+ ... ado.net/XML headers & schema ...
+ text/microsoft-resx
+ 1.3
+ System.Resources.ResXResourceReader, System.Windows.Forms, ...
+ System.Resources.ResXResourceWriter, System.Windows.Forms, ...
+ this is my long string
+ Blue
+
+ [base64 mime encoded serialized .NET Framework object]
+
+
+ [base64 mime encoded string representing a byte array form of the .NET Framework object]
+
+
+ There are any number of "resheader" rows that contain simple
+ name/value pairs.
+
+ Each data row contains a name, and value. The row also contains a
+ type or mimetype. Type corresponds to a .NET class that support
+ text/value conversion through the TypeConverter architecture.
+ Classes that don't support this are serialized and stored with the
+ mimetype set.
+
+ The mimetype is used for serialized objects, and tells the
+ ResXResourceReader how to depersist the object. This is currently not
+ extensible. For a given mimetype the value must be set accordingly:
+
+ Note - application/x-microsoft.net.object.binary.base64 is the format
+ that the ResXResourceWriter will generate, however the reader can
+ read any of the formats listed below.
+
+ mimetype: application/x-microsoft.net.object.binary.base64
+ value : The object must be serialized with
+ : System.Serialization.Formatters.Binary.BinaryFormatter
+ : and then encoded with base64 encoding.
+
+ mimetype: application/x-microsoft.net.object.soap.base64
+ value : The object must be serialized with
+ : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+ : and then encoded with base64 encoding.
+
+ mimetype: application/x-microsoft.net.object.bytearray.base64
+ value : The object must be serialized into a byte array
+ : using a System.ComponentModel.TypeConverter
+ : and then encoded with base64 encoding.
+ -->
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
@@ -108,13 +89,13 @@
text/microsoft-resx
- 2.0
+ 1.3
- System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
- System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
Confirm
diff --git a/HandyControl/Themes/Basic/Converters.xaml b/HandyControl/Themes/Basic/Converters.xaml
index 8a4d418f..57809fe9 100644
--- a/HandyControl/Themes/Basic/Converters.xaml
+++ b/HandyControl/Themes/Basic/Converters.xaml
@@ -15,5 +15,7 @@
+
+
\ No newline at end of file
diff --git a/HandyControl/Themes/Styles/Base/GravatarBaseStyle.xaml b/HandyControl/Themes/Styles/Base/GravatarBaseStyle.xaml
new file mode 100644
index 00000000..861062d2
--- /dev/null
+++ b/HandyControl/Themes/Styles/Base/GravatarBaseStyle.xaml
@@ -0,0 +1,22 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/HandyControl/Themes/Styles/Border.xaml b/HandyControl/Themes/Styles/Border.xaml
index 4163cef3..27557b46 100644
--- a/HandyControl/Themes/Styles/Border.xaml
+++ b/HandyControl/Themes/Styles/Border.xaml
@@ -1,6 +1,11 @@
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ xmlns:controls="clr-namespace:HandyControl.Controls">
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/HandyControl/Themes/Styles/Gravatar.xaml b/HandyControl/Themes/Styles/Gravatar.xaml
new file mode 100644
index 00000000..7c400cdb
--- /dev/null
+++ b/HandyControl/Themes/Styles/Gravatar.xaml
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/HandyControl/Themes/Styles/Style.xaml b/HandyControl/Themes/Styles/Style.xaml
index dfc27adc..50479527 100644
--- a/HandyControl/Themes/Styles/Style.xaml
+++ b/HandyControl/Themes/Styles/Style.xaml
@@ -58,6 +58,7 @@
+
\ No newline at end of file
diff --git a/HandyControl/Tools/Converter/BorderCircularConverter.cs b/HandyControl/Tools/Converter/BorderCircularConverter.cs
new file mode 100644
index 00000000..b7170562
--- /dev/null
+++ b/HandyControl/Tools/Converter/BorderCircularConverter.cs
@@ -0,0 +1,31 @@
+using System;
+using System.Globalization;
+using System.Windows;
+using System.Windows.Data;
+
+namespace HandyControl.Tools.Converter
+{
+ public class BorderCircularConverter : IMultiValueConverter
+ {
+ public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
+ {
+ if (values.Length == 2 && values[0] is double width && values[1] is double height)
+ {
+ if (width < double.Epsilon || height < double.Epsilon)
+ {
+ return new CornerRadius();
+ }
+
+ var min = Math.Min(width, height);
+ return new CornerRadius(min/2);
+ }
+
+ return DependencyProperty.UnsetValue;
+ }
+
+ public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
+ {
+ throw new NotSupportedException();
+ }
+ }
+}
\ No newline at end of file
diff --git a/HandyControl/Tools/Converter/BorderClipConverter.cs b/HandyControl/Tools/Converter/BorderClipConverter.cs
new file mode 100644
index 00000000..4b17a7f7
--- /dev/null
+++ b/HandyControl/Tools/Converter/BorderClipConverter.cs
@@ -0,0 +1,36 @@
+//referenced from https://stackoverflow.com/a/5650367/9639378
+
+using System;
+using System.Globalization;
+using System.Windows;
+using System.Windows.Data;
+using System.Windows.Media;
+
+namespace HandyControl.Tools.Converter
+{
+ public class BorderClipConverter : IMultiValueConverter
+ {
+ public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
+ {
+ if (values.Length == 3 && values[0] is double width && values[1] is double height && values[2] is CornerRadius radius)
+ {
+ if (width < double.Epsilon || height < double.Epsilon)
+ {
+ return Geometry.Empty;
+ }
+
+ var clip = new RectangleGeometry(new Rect(0, 0, width, height), radius.TopLeft, radius.TopLeft);
+ clip.Freeze();
+
+ return clip;
+ }
+
+ return DependencyProperty.UnsetValue;
+ }
+
+ public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
+ {
+ throw new NotSupportedException();
+ }
+ }
+}
\ No newline at end of file
diff --git a/HandyControl/Tools/GithubGravatarGenerator.cs b/HandyControl/Tools/GithubGravatarGenerator.cs
new file mode 100644
index 00000000..30d0808c
--- /dev/null
+++ b/HandyControl/Tools/GithubGravatarGenerator.cs
@@ -0,0 +1,119 @@
+using System;
+using System.Globalization;
+using System.Security.Cryptography;
+using System.Text;
+using System.Windows;
+using System.Windows.Media;
+using System.Windows.Shapes;
+using HandyControl.Controls;
+
+namespace HandyControl.Tools
+{
+ public class GithubGravatarGenerator : IGravatarGenerator
+ {
+ private const int RenderDataMaxLength = 15;
+
+ public object GetGravatar(string id)
+ {
+ var hashcode = GetHashCode(id);
+ var renderData = GetRenderData(hashcode);
+ var renderBrush = GetRenderBrush(hashcode);
+ var geometryGroup = new GeometryGroup();
+
+ void AddRec(int i, int j, bool hidden = false)
+ {
+ var rec = new RectangleGeometry(new Rect(new Point(i, j), hidden ? new Size() : new Size(1, 1)));
+ geometryGroup.Children.Add(rec);
+ }
+
+ var index = 0;
+ for (int i = 0; i < 2; i++)
+ {
+ for (int j = 0; j < 5; j++, index++)
+ {
+ AddRec(i, j, renderData[index] == 0);
+ }
+ }
+
+ for (int j = 0; j < 5; j++, index++)
+ {
+ AddRec(2, j, renderData[index] == 0);
+ }
+
+ index -= 10;
+ for (int i = 3; i < 5; i++)
+ {
+ for (int j = 0; j < 5; j++, index++)
+ {
+ AddRec(i, j, renderData[index] == 0);
+ }
+ index -= 10;
+ }
+
+ var path = new Path
+ {
+ Data = geometryGroup,
+ Fill = renderBrush,
+ VerticalAlignment = VerticalAlignment.Top
+ };
+
+ RenderOptions.SetEdgeMode(path, EdgeMode.Aliased);
+
+ return path;
+ }
+
+ private string GetHashCode(string id)
+ {
+ var md5 = MD5.Create();
+ var bytes = Encoding.ASCII.GetBytes(id);
+ var hash = md5.ComputeHash(bytes);
+ var stringBuilder = new StringBuilder();
+ foreach (var item in hash)
+ {
+ stringBuilder.Append(item.ToString("X2"));
+ }
+ return stringBuilder.ToString();
+ }
+
+ private int[] GetRenderData(string hashcode)
+ {
+ var arr = new int[RenderDataMaxLength];
+ for (int i = 0; i < RenderDataMaxLength; i++)
+ {
+ var c = hashcode[i];
+ var v = (int) c;
+ arr[i] = v % 2;
+ }
+
+ return arr;
+ }
+
+ private Brush GetRenderBrush(string hashcode)
+ {
+ var v = (double)int.Parse(hashcode.Substring(hashcode.Length - 7), NumberStyles.HexNumber);
+ var scale = v / 0xfffffff;
+ var color = Hsl2Rgb(scale);
+ return new SolidColorBrush(color);
+ }
+
+ //adapted from https://github.com/stewartlord/identicon.js/blob/4fad7cafec1b7a4d896015e084e861625ef5d64f/identicon.js#L110
+ private Color Hsl2Rgb(double h, double s = 0.7, double b = 0.5)
+ {
+ h *= 6;
+ var arr = new[]
+ {
+ b += s *= b < .5 ? b : 1 - b,
+ b - h % 1 * s * 2,
+ b -= s *= 2,
+ b,
+ b + h % 1 * s,
+ b + s
+ };
+
+ var hValue = (int) Math.Floor(h);
+
+ return Color.FromRgb((byte) (arr[hValue % 6] * 255), (byte) (arr[(hValue | 16) % 6] * 255),
+ (byte) (arr[(hValue | 8) % 6] * 255));
+ }
+ }
+}
\ No newline at end of file
diff --git a/HandyControlDemo/Data/MessageToken.cs b/HandyControlDemo/Data/MessageToken.cs
index e63c9770..529716b5 100644
--- a/HandyControlDemo/Data/MessageToken.cs
+++ b/HandyControlDemo/Data/MessageToken.cs
@@ -84,6 +84,10 @@
public static readonly string GotoTopDemoCtl = nameof(GotoTopDemoCtl);
+ public static readonly string BadgeDemoCtl = nameof(BadgeDemoCtl);
+
+ public static readonly string GravatarDemoCtl = nameof(GravatarDemoCtl);
+
public static readonly string ButtonDemoCtl = nameof(ButtonDemoCtl);
public static readonly string ToggleButtonDemoCtl = nameof(ToggleButtonDemoCtl);
diff --git a/HandyControlDemo/Data/MessageToken.tt b/HandyControlDemo/Data/MessageToken.tt
index 377d9b64..3af06d18 100644
--- a/HandyControlDemo/Data/MessageToken.tt
+++ b/HandyControlDemo/Data/MessageToken.tt
@@ -44,7 +44,9 @@ var controlList = new List
"ProgressButtonDemoCtl",
"TransferDemoCtl",
"ChatBubbleDemoCtl",
- "GotoTopDemoCtl"
+ "GotoTopDemoCtl",
+ "BadgeDemoCtl",
+ "GravatarDemoCtl"
};
var styleList = new List
{
diff --git a/HandyControlDemo/HandyControlDemo.csproj b/HandyControlDemo/HandyControlDemo.csproj
index fb8411db..464bacdc 100644
--- a/HandyControlDemo/HandyControlDemo.csproj
+++ b/HandyControlDemo/HandyControlDemo.csproj
@@ -133,6 +133,9 @@
AnimationPathDemoCtl.xaml
+
+ BadgeDemoCtl.xaml
+
CalendarWithClockDemoCtl.xaml
@@ -178,6 +181,9 @@
GotoTopDemoCtl.xaml
+
+ GravatarDemoCtl.xaml
+
OutlineTextDemoCtl.xaml
@@ -247,6 +253,9 @@
QQGroupView.xaml
+
+ UnderConstruction.xaml
+
BorderDemoCtl.xaml
@@ -435,6 +444,10 @@
Designer
MSBuild:Compile
+
+ Designer
+ MSBuild:Compile
+
Designer
MSBuild:Compile
@@ -495,6 +508,10 @@
Designer
MSBuild:Compile
+
+ Designer
+ MSBuild:Compile
+
Designer
MSBuild:Compile
@@ -587,6 +604,10 @@
Designer
MSBuild:Compile
+
+ Designer
+ MSBuild:Compile
+
Designer
MSBuild:Compile
@@ -753,6 +774,9 @@
TextTemplatingFileGenerator
MessageToken.cs
+
+
+
diff --git a/HandyControlDemo/Properties/Langs/Lang.Designer.cs b/HandyControlDemo/Properties/Langs/Lang.Designer.cs
index 44d750f8..70097234 100644
--- a/HandyControlDemo/Properties/Langs/Lang.Designer.cs
+++ b/HandyControlDemo/Properties/Langs/Lang.Designer.cs
@@ -47,7 +47,7 @@ namespace HandyControlDemo.Properties.Langs {
}
///
- /// 重写当前线程的 CurrentUICulture 属性
+ /// 使用此强类型资源类,为所有资源查找
/// 重写当前线程的 CurrentUICulture 属性。
///
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
@@ -87,6 +87,15 @@ namespace HandyControlDemo.Properties.Langs {
}
}
+ ///
+ /// 查找类似 标记 的本地化字符串。
+ ///
+ public static string Badge {
+ get {
+ return ResourceManager.GetString("Badge", resourceCulture);
+ }
+ }
+
///
/// 查找类似 填写基本信息 的本地化字符串。
///
@@ -258,6 +267,15 @@ namespace HandyControlDemo.Properties.Langs {
}
}
+ ///
+ /// 查找类似 敬请期待 的本地化字符串。
+ ///
+ public static string ComingSoon {
+ get {
+ return ResourceManager.GetString("ComingSoon", resourceCulture);
+ }
+ }
+
///
/// 查找类似 一般 的本地化字符串。
///
@@ -447,6 +465,15 @@ namespace HandyControlDemo.Properties.Langs {
}
}
+ ///
+ /// 查找类似 头像 的本地化字符串。
+ ///
+ public static string Gravatar {
+ get {
+ return ResourceManager.GetString("Gravatar", resourceCulture);
+ }
+ }
+
///
/// 查找类似 分组框 的本地化字符串。
///
diff --git a/HandyControlDemo/Properties/Langs/Lang.en.resx b/HandyControlDemo/Properties/Langs/Lang.en.resx
index 3f57a795..b2b8e53a 100644
--- a/HandyControlDemo/Properties/Langs/Lang.en.resx
+++ b/HandyControlDemo/Properties/Langs/Lang.en.resx
@@ -501,4 +501,13 @@
GotoTop
+
+ Badge
+
+
+ Gravatar
+
+
+ Coming Soon
+
\ No newline at end of file
diff --git a/HandyControlDemo/Properties/Langs/Lang.resx b/HandyControlDemo/Properties/Langs/Lang.resx
index 32ab263a..dfc893e1 100644
--- a/HandyControlDemo/Properties/Langs/Lang.resx
+++ b/HandyControlDemo/Properties/Langs/Lang.resx
@@ -501,4 +501,13 @@
回到顶部
+
+ 标记
+
+
+ 头像
+
+
+ 敬请期待
+
\ No newline at end of file
diff --git a/HandyControlDemo/Resources/Img/LeftMainContent/DotLarge_16x.png b/HandyControlDemo/Resources/Img/LeftMainContent/DotLarge_16x.png
new file mode 100644
index 00000000..c588ac01
Binary files /dev/null and b/HandyControlDemo/Resources/Img/LeftMainContent/DotLarge_16x.png differ
diff --git a/HandyControlDemo/Resources/Img/LeftMainContent/User_16x.png b/HandyControlDemo/Resources/Img/LeftMainContent/User_16x.png
new file mode 100644
index 00000000..391e91e4
Binary files /dev/null and b/HandyControlDemo/Resources/Img/LeftMainContent/User_16x.png differ
diff --git a/HandyControlDemo/Resources/Img/under_construction.gif b/HandyControlDemo/Resources/Img/under_construction.gif
new file mode 100644
index 00000000..b5efd6d8
Binary files /dev/null and b/HandyControlDemo/Resources/Img/under_construction.gif differ
diff --git a/HandyControlDemo/UserControl/Controls/BadgeDemoCtl.xaml b/HandyControlDemo/UserControl/Controls/BadgeDemoCtl.xaml
new file mode 100644
index 00000000..89201f78
--- /dev/null
+++ b/HandyControlDemo/UserControl/Controls/BadgeDemoCtl.xaml
@@ -0,0 +1,6 @@
+
+
+
diff --git a/HandyControlDemo/UserControl/Controls/BadgeDemoCtl.xaml.cs b/HandyControlDemo/UserControl/Controls/BadgeDemoCtl.xaml.cs
new file mode 100644
index 00000000..7c745584
--- /dev/null
+++ b/HandyControlDemo/UserControl/Controls/BadgeDemoCtl.xaml.cs
@@ -0,0 +1,10 @@
+namespace HandyControlDemo.UserControl
+{
+ public partial class BadgeDemoCtl
+ {
+ public BadgeDemoCtl()
+ {
+ InitializeComponent();
+ }
+ }
+}
diff --git a/HandyControlDemo/UserControl/Controls/GifImageDemoCtl.xaml b/HandyControlDemo/UserControl/Controls/GifImageDemoCtl.xaml
index 7efbaaae..46b410b7 100644
--- a/HandyControlDemo/UserControl/Controls/GifImageDemoCtl.xaml
+++ b/HandyControlDemo/UserControl/Controls/GifImageDemoCtl.xaml
@@ -4,10 +4,10 @@
xmlns:controls="clr-namespace:HandyControl.Controls;assembly=HandyControl"
Background="{DynamicResource RegionBrush}">
-
-
+
+
-
-
+
+
diff --git a/HandyControlDemo/UserControl/Controls/GravatarDemoCtl.xaml b/HandyControlDemo/UserControl/Controls/GravatarDemoCtl.xaml
new file mode 100644
index 00000000..25d5f2ea
--- /dev/null
+++ b/HandyControlDemo/UserControl/Controls/GravatarDemoCtl.xaml
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/HandyControlDemo/UserControl/Controls/GravatarDemoCtl.xaml.cs b/HandyControlDemo/UserControl/Controls/GravatarDemoCtl.xaml.cs
new file mode 100644
index 00000000..3a27748e
--- /dev/null
+++ b/HandyControlDemo/UserControl/Controls/GravatarDemoCtl.xaml.cs
@@ -0,0 +1,10 @@
+namespace HandyControlDemo.UserControl
+{
+ public partial class GravatarDemoCtl
+ {
+ public GravatarDemoCtl()
+ {
+ InitializeComponent();
+ }
+ }
+}
diff --git a/HandyControlDemo/UserControl/Main/LeftMainContent.xaml b/HandyControlDemo/UserControl/Main/LeftMainContent.xaml
index 9828b9ef..f83e9744 100644
--- a/HandyControlDemo/UserControl/Main/LeftMainContent.xaml
+++ b/HandyControlDemo/UserControl/Main/LeftMainContent.xaml
@@ -188,12 +188,22 @@
+
+
+
+
+
+
+
+
+
+
-
+
@@ -303,7 +313,7 @@
-
+
diff --git a/HandyControlDemo/UserControl/Main/UnderConstruction.xaml b/HandyControlDemo/UserControl/Main/UnderConstruction.xaml
new file mode 100644
index 00000000..c03acb47
--- /dev/null
+++ b/HandyControlDemo/UserControl/Main/UnderConstruction.xaml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/HandyControlDemo/UserControl/Main/UnderConstruction.xaml.cs b/HandyControlDemo/UserControl/Main/UnderConstruction.xaml.cs
new file mode 100644
index 00000000..510956ef
--- /dev/null
+++ b/HandyControlDemo/UserControl/Main/UnderConstruction.xaml.cs
@@ -0,0 +1,10 @@
+namespace HandyControlDemo.UserControl
+{
+ public partial class UnderConstruction
+ {
+ public UnderConstruction()
+ {
+ InitializeComponent();
+ }
+ }
+}
diff --git a/README.md b/README.md
index 51890494..35673c7e 100644
--- a/README.md
+++ b/README.md
@@ -39,6 +39,10 @@ Step 3:enjoy coding
## Latest examples
+### Gravatar
+
+
+
### ChatBubble

@@ -51,6 +55,8 @@ Step 3:enjoy coding

+## History publication
+
### CoverFlow

@@ -59,8 +65,6 @@ Step 3:enjoy coding

-## History publication
-
### MessageBox

diff --git a/Resources/Gravatar.gif b/Resources/Gravatar.gif
new file mode 100644
index 00000000..efb9e671
Binary files /dev/null and b/Resources/Gravatar.gif differ