做聊天消息时,需要用到文字和表情混合的TextBlock,经过一番百度。。终于实现了,不容易,今天就来分享下。
先看下效果,输入框和textblock绑定了同一个属性,懂的人自然懂:
注:此文较长,代码难度较大,还请您耐心看
话不多说,下面就看看如何实现:
首先,图片表情资源什么的,网上很多,自行下载即可。
为了管理我们添加的图片资源 ,新建两个类GifFace和SysFaces:
public class GifFace
{
public string Name { get; set; }
public string ImageName { get; set; }
}
public class SysFaces
{
public static GifFace 微笑 = new GifFace() { Name = "微笑", ImageName = "Expression_1@2x.png" };
public static GifFace 撇嘴 = new GifFace() { Name = "撇嘴", ImageName = "Expression_2@2x.png" };
public static GifFace 色色 = new GifFace() { Name = "色色", ImageName = "Expression_3@2x.png" };
public static GifFace 发呆 = new GifFace() { Name = "发呆", ImageName = "Expression_4@2x.png" };
public static GifFace 得意 = new GifFace() { Name = "得意", ImageName = "Expression_5@2x.png" };
public static GifFace 流泪 = new GifFace() { Name = "流泪", ImageName = "Expression_6@2x.png" };
public static GifFace 害羞 = new GifFace() { Name = "害羞", ImageName = "Expression_7@2x.png" };
public static GifFace 闭嘴 = new GifFace() { Name = "闭嘴", ImageName = "Expression_8@2x.png" };
public static GifFace 睡觉 = new GifFace() { Name = "睡觉", ImageName = "Expression_9@2x.png" };
public static GifFace 大哭 = new GifFace() { Name = "大哭", ImageName = "Expression_10@2x.png" };
public static GifFace 尴尬 = new GifFace() { Name = "尴尬", ImageName = "Expression_11@2x.png" };
public static GifFace 发怒 = new GifFace() { Name = "发怒", ImageName = "Expression_12@2x.png" };
public static GifFace 调皮 = new GifFace() { Name = "调皮", ImageName = "Expression_13@2x.png" };
public static GifFace 呲牙 = new GifFace() { Name = "呲牙", ImageName = "Expression_14@2x.png" };
public static GifFace 惊讶 = new GifFace() { Name = "惊讶", ImageName = "Expression_15@2x.png" };
public static GifFace 难过 = new GifFace() { Name = "难过", ImageName = "Expression_16@2x.png" };
public static GifFace 酷酷 = new GifFace() { Name = "酷酷", ImageName = "Expression_17@2x.png" };
public static GifFace 冷汗 = new GifFace() { Name = "冷汗", ImageName = "Expression_18@2x.png" };
public static GifFace 抓狂 = new GifFace() { Name = "抓狂", ImageName = "Expression_19@2x.png" };
public static GifFace 呕吐 = new GifFace() { Name = "呕吐", ImageName = "Expression_20@2x.png" };
public static GifFace 偷笑 = new GifFace() { Name = "偷笑", ImageName = "Expression_21@2x.png" };
public static GifFace 愉快 = new GifFace() { Name = "愉快", ImageName = "Expression_22@2x.png" };
public static GifFace 白眼 = new GifFace() { Name = "白眼", ImageName = "Expression_23@2x.png" };
public static GifFace 傲慢 = new GifFace() { Name = "傲慢", ImageName = "Expression_24@2x.png" };
public static GifFace 饥饿 = new GifFace() { Name = "饥饿", ImageName = "Expression_25@2x.png" };
public static GifFace 困倦 = new GifFace() { Name = "困倦", ImageName = "Expression_26@2x.png" };
public static GifFace 惊恐 = new GifFace() { Name = "惊恐", ImageName = "Expression_27@2x.png" };
public static GifFace 流汗 = new GifFace() { Name = "流汗", ImageName = "Expression_28@2x.png" };
public static GifFace 憨笑 = new GifFace() { Name = "憨笑", ImageName = "Expression_29@2x.png" };
public static GifFace 悠闲 = new GifFace() { Name = "悠闲", ImageName = "Expression_30@2x.png" };
public static GifFace 奋斗 = new GifFace() { Name = "奋斗", ImageName = "Expression_31@2x.png" };
public static GifFace 咒骂 = new GifFace() { Name = "咒骂", ImageName = "Expression_32@2x.png" };
public static GifFace 疑问 = new GifFace() { Name = "疑问", ImageName = "Expression_33@2x.png" };
public static GifFace 嘘嘘 = new GifFace() { Name = "嘘嘘", ImageName = "Expression_34@2x.png" };
public static GifFace 晕倒 = new GifFace() { Name = "晕倒", ImageName = "Expression_35@2x.png" };
public static GifFace 疯了 = new GifFace() { Name = "疯了", ImageName = "Expression_36@2x.png" };
public static GifFace 衰人 = new GifFace() { Name = "衰人", ImageName = "Expression_37@2x.png" };
public static GifFace 骷髅 = new GifFace() { Name = "骷髅", ImageName = "Expression_38@2x.png" };
public static GifFace 敲打 = new GifFace() { Name = "敲打", ImageName = "Expression_39@2x.png" };
public static GifFace 再见 = new GifFace() { Name = "再见", ImageName = "Expression_40@2x.png" };
public static GifFace 擦汗 = new GifFace() { Name = "擦汗", ImageName = "Expression_41@2x.png" };
public static GifFace 抠鼻 = new GifFace() { Name = "抠鼻", ImageName = "Expression_42@2x.png" };
public static GifFace 鼓掌 = new GifFace() { Name = "鼓掌", ImageName = "Expression_43@2x.png" };
public static GifFace 糗了 = new GifFace() { Name = "糗了", ImageName = "Expression_44@2x.png" };
public static GifFace 坏笑 = new GifFace() { Name = "坏笑", ImageName = "Expression_45@2x.png" };
public static GifFace 左哼 = new GifFace() { Name = "左哼", ImageName = "Expression_46@2x.png" };
public static GifFace 右哼 = new GifFace() { Name = "右哼", ImageName = "Expression_47@2x.png" };
public static GifFace 哈欠 = new GifFace() { Name = "哈欠", ImageName = "Expression_48@2x.png" };
public static GifFace 鄙视 = new GifFace() { Name = "鄙视", ImageName = "Expression_49@2x.png" };
public static GifFace 委屈 = new GifFace() { Name = "委屈", ImageName = "Expression_50@2x.png" };
public static GifFace 快哭 = new GifFace() { Name = "快哭", ImageName = "Expression_51@2x.png" };
public static GifFace 阴险 = new GifFace() { Name = "阴险", ImageName = "Expression_52@2x.png" };
public static GifFace 亲亲 = new GifFace() { Name = "亲亲", ImageName = "Expression_53@2x.png" };
public static GifFace 惊吓 = new GifFace() { Name = "惊吓", ImageName = "Expression_54@2x.png" };
public static GifFace 可怜 = new GifFace() { Name = "可怜", ImageName = "Expression_55@2x.png" };
public static GifFace 菜刀 = new GifFace() { Name = "菜刀", ImageName = "Expression_56@2x.png" };
public static GifFace 西瓜 = new GifFace() { Name = "西瓜", ImageName = "Expression_57@2x.png" };
public static GifFace 啤酒 = new GifFace() { Name = "啤酒", ImageName = "Expression_58@2x.png" };
public static GifFace 篮球 = new GifFace() { Name = "篮球", ImageName = "Expression_59@2x.png" };
public static GifFace 乒乓 = new GifFace() { Name = "乒乓", ImageName = "Expression_60@2x.png" };
public static GifFace 咖啡 = new GifFace() { Name = "咖啡", ImageName = "Expression_61@2x.png" };
public static GifFace 米饭 = new GifFace() { Name = "米饭", ImageName = "Expression_62@2x.png" };
public static GifFace 猪头 = new GifFace() { Name = "猪头", ImageName = "Expression_63@2x.png" };
public static GifFace 玫瑰 = new GifFace() { Name = "玫瑰", ImageName = "Expression_64@2x.png" };
public static GifFace 凋谢 = new GifFace() { Name = "凋谢", ImageName = "Expression_65@2x.png" };
public static GifFace 嘴唇 = new GifFace() { Name = "嘴唇", ImageName = "Expression_66@2x.png" };
public static GifFace 爱心 = new GifFace() { Name = "爱心", ImageName = "Expression_67@2x.png" };
public static GifFace 心碎 = new GifFace() { Name = "心碎", ImageName = "Expression_68@2x.png" };
public static GifFace 蛋糕 = new GifFace() { Name = "蛋糕", ImageName = "Expression_69@2x.png" };
public static GifFace 闪电 = new GifFace() { Name = "闪电", ImageName = "Expression_70@2x.png" };
public static GifFace 炸弹 = new GifFace() { Name = "炸弹", ImageName = "Expression_71@2x.png" };
public static GifFace 刀刀 = new GifFace() { Name = "刀刀", ImageName = "Expression_72@2x.png" };
public static GifFace 足球 = new GifFace() { Name = "足球", ImageName = "Expression_73@2x.png" };
public static GifFace 瓢虫 = new GifFace() { Name = "瓢虫", ImageName = "Expression_74@2x.png" };
public static GifFace 便便 = new GifFace() { Name = "便便", ImageName = "Expression_75@2x.png" };
public static GifFace 月亮 = new GifFace() { Name = "月亮", ImageName = "Expression_76@2x.png" };
public static GifFace 太阳 = new GifFace() { Name = "太阳", ImageName = "Expression_77@2x.png" };
public static GifFace 礼物 = new GifFace() { Name = "礼物", ImageName = "Expression_78@2x.png" };
public static GifFace 拥抱 = new GifFace() { Name = "拥抱", ImageName = "Expression_79@2x.png" };
public static GifFace 强强 = new GifFace() { Name = "强强", ImageName = "Expression_80@2x.png" };
public static GifFace 弱弱 = new GifFace() { Name = "弱弱", ImageName = "Expression_81@2x.png" };
public static GifFace 握手 = new GifFace() { Name = "握手", ImageName = "Expression_82@2x.png" };
public static GifFace 胜利 = new GifFace() { Name = "胜利", ImageName = "Expression_83@2x.png" };
public static GifFace 抱拳 = new GifFace() { Name = "抱拳", ImageName = "Expression_84@2x.png" };
public static GifFace 勾引 = new GifFace() { Name = "勾引", ImageName = "Expression_85@2x.png" };
public static GifFace 拳头 = new GifFace() { Name = "拳头", ImageName = "Expression_86@2x.png" };
public static GifFace 差劲 = new GifFace() { Name = "差劲", ImageName = "Expression_87@2x.png" };
public static GifFace 爱你 = new GifFace() { Name = "爱你", ImageName = "Expression_88@2x.png" };
public static GifFace NO = new GifFace() { Name = "NO", ImageName = "Expression_89@2x.png" };
public static GifFace OK = new GifFace() { Name = "OK", ImageName = "Expression_90@2x.png" };
public static GifFace 扫地 = new GifFace() { Name = "扫地", ImageName = "Expression_91@2x.gif" };
public static List<GifFace> Faces { get; set; } = new List<GifFace>()
{
微笑,撇嘴,色色,发呆,得意,流泪,害羞,闭嘴,睡觉,大哭,尴尬,发怒,调皮,呲牙,惊讶,难过,酷酷,冷汗,抓狂,呕吐,偷笑,愉快,
白眼,傲慢,饥饿,困倦,惊恐,流汗,憨笑,悠闲,奋斗,咒骂,疑问,嘘嘘,晕倒,疯了,衰人,骷髅,敲打,再见,擦汗,抠鼻,鼓掌,糗了,
坏笑,左哼,右哼,哈欠,鄙视,委屈,快哭,阴险,亲亲,惊吓,可怜,菜刀,西瓜,啤酒,篮球,乒乓,咖啡,米饭,猪头,玫瑰,凋谢,嘴唇,
爱心,心碎,蛋糕,闪电,炸弹,刀刀,足球,瓢虫,便便,月亮,太阳,礼物,拥抱,强强,弱弱,握手,胜利,抱拳,勾引,拳头,
差劲,爱你,NO,OK,扫地
};
}
新建一个图片子类,实现Gif图片:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Media;
using System.Windows.Threading;
using System.Windows;
using System.Windows.Controls;
namespace WpfDemo
{
public class ImageExpender : Image
{
string imageLocation;
public string ImageLocation
{
get
{
return imageLocation;
}
set
{
if (imageLocation != value)
{
imageLocation = value;
try
{
Load();
}
catch (Exception)
{ }
}
}
}
private String location;
/// <summary>
/// 图像路径
/// </summary>
public String Location
{
get { return location; }
set { location = value; }
}
public System.Drawing.Image Image
{
get { return (System.Drawing.Image)GetValue(ImageProperty); }
set { SetValue(ImageProperty, value); }
}
//使用 DependencyProperty 作为后备存储的图像。这使动画、 样式、 绑定等......
public static readonly DependencyProperty ImageProperty =
DependencyProperty.Register("Image", typeof(System.Drawing.Image), typeof(ImageExpender), new UIPropertyMetadata(null, new PropertyChangedCallback(ImagePropertyChanged)));
private static void ImagePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
ImageExpender imageExpender = d as ImageExpender;
System.Drawing.Image oldImage = e.OldValue as System.Drawing.Image;
System.Drawing.Image newImage = e.NewValue as System.Drawing.Image;
imageExpender.StopAnimate(oldImage);
imageExpender.Animate(newImage);
imageExpender.RefreshImageSource();
}
bool currentlyAnimating = false;
#region Animate
private void Animate(bool animate, System.Drawing.Image image)
{
if (animate != this.currentlyAnimating)
{
if (animate)
{
if (image != null)
{
ImageAnimatiorExpender.Animate(image, new EventHandler(this.OnFrameChanged));
this.currentlyAnimating = animate;
}
}
else
{
if (image != null)
{
ImageAnimatiorExpender.StopAnimate(image, new EventHandler(this.OnFrameChanged));
this.currentlyAnimating = animate;
}
}
}
}
private void StopAnimate(System.Drawing.Image image)
{
Animate(false, image);
}
private void Animate(System.Drawing.Image image)
{
Animate(IsEnabled && Visibility == Visibility.Visible, image);
}
#endregion
private void OnFrameChanged(object o, EventArgs e)
{
this.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new System.Threading.ThreadStart(RefreshImageSource));
}
private void RefreshImageSource()
{
if (this.Image != null && this.Visibility == Visibility.Visible)
{
ImageAnimatiorExpender.UpdateFrames(this.Image);
ImageSource imageSource = ImageAnimatiorExpender.GetImageSource(this.Image);
if (imageSource == null)
{
IntPtr ip = (this.Image as System.Drawing.Bitmap).GetHbitmap();
imageSource = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
ip, IntPtr.Zero, System.Windows.Int32Rect.Empty,
System.Windows.Media.Imaging.BitmapSizeOptions.FromEmptyOptions());
}
this.Source = imageSource;
}
}
#region 辅助方法
private Uri CalculateUri(string path)
{
Uri uri;
try
{
uri = new Uri(path);
}
catch (UriFormatException)
{
// It's a relative pathname, get its full path as a file.
path = Path.GetFullPath(path);
uri = new Uri(path);
}
return uri;
}
public void Load()
{
if (ImageLocation == null || ImageLocation.Length == 0)
{
return;
}
System.Drawing.Image img = null;
try
{
Uri uri = CalculateUri(ImageLocation);
if (uri.IsFile)
{
using (StreamReader reader = new StreamReader(uri.LocalPath))
{
//img = System.Drawing.Image.FromStream(reader.BaseStream);
img = new System.Drawing.Bitmap(uri.LocalPath);
}
}
else
{
using (WebClient wc = new WebClient())
{
using (Stream s = wc.OpenRead(uri.ToString()))
{
img = System.Drawing.Bitmap.FromStream(s);
}
}
}
}
catch
{
}
this.Image = img;
}
#endregion
}
}
新建一个gif动画支持类:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Drawing;
using System.Drawing.Imaging;
using System.Threading;
using System.Windows.Media;
namespace WpfDemo
{
public class ImageAnimatiorExpender
{
static List<ImageInfoExpender> imageInfoList;
static bool anyFrameDirty;
static Thread animationThread;
static ReaderWriterLock rwImgListLock = new ReaderWriterLock();
[ThreadStatic]
static int threadWriterLockWaitCount;
private ImageAnimatiorExpender()
{
}
public static void UpdateFrames(Image image)
{
if (!anyFrameDirty || image == null || imageInfoList == null)
{
return;
}
if (threadWriterLockWaitCount > 0)
{
return;
}
rwImgListLock.AcquireReaderLock(Timeout.Infinite);
try
{
bool foundDirty = false;
bool foundImage = false;
foreach (ImageInfoExpender imageInfo in imageInfoList)
{
if (imageInfo.Image == image)
{
if (imageInfo.FrameDirty)
{
lock (imageInfo.Image)
{
imageInfo.UpdateFrame();
}
}
foundImage = true;
}
if (imageInfo.FrameDirty)
{
foundDirty = true;
}
if (foundDirty && foundImage)
{
break;
}
}
anyFrameDirty = foundDirty;
}
finally
{
rwImgListLock.ReleaseReaderLock();
}
}
public static ImageSource GetImageSource(Image image)
{
ImageSource imageSource = null;
if (imageInfoList != null)
{
foreach (ImageInfoExpender imageInfo in imageInfoList)
{
if (imageInfo.Image == image)
{
imageSource = imageInfo.GetCurrentImageSource();
break;
}
}
}
return imageSource;
}
public static void Animate(Image image, EventHandler onFrameChangedHandler)
{
if (image == null)
{
return;
}
ImageInfoExpender imageInfo = null;
lock (image)
{
imageInfo = new ImageInfoExpender(image);
}
StopAnimate(image, onFrameChangedHandler);
bool readerLockHeld = rwImgListLock.IsReaderLockHeld;
LockCookie lockDowngradeCookie = new LockCookie();
threadWriterLockWaitCount++;
try
{
if (readerLockHeld)
{
lockDowngradeCookie = rwImgListLock.UpgradeToWriterLock(Timeout.Infinite);
}
else
{
rwImgListLock.AcquireWriterLock(Timeout.Infinite);
}
}
finally
{
threadWriterLockWaitCount--;
Debug.Assert(threadWriterLockWaitCount >= 0, "threadWriterLockWaitCount less than zero.");
}
try
{
if (imageInfo.Animated)
{
if (imageInfoList == null)
{
imageInfoList = new List<ImageInfoExpender>();
}
imageInfo.FrameChangedHandler = onFrameChangedHandler;
imageInfoList.Add(imageInfo);
if (animationThread == null)
{
animationThread = new Thread(new ThreadStart(AnimateImages50ms));
animationThread.Name = typeof(ImageAnimator).Name;
animationThread.IsBackground = true;
animationThread.Start();
}
}
}
finally
{
if (readerLockHeld)
{
rwImgListLock.DowngradeFromWriterLock(ref lockDowngradeCookie);
}
else
{
rwImgListLock.ReleaseWriterLock();
}
}
}
public static bool CanAnimate(Image image)
{
if (image == null)
{
return false;
}
lock (image)
{
Guid[] dimensions = image.FrameDimensionsList;
foreach (Guid guid in dimensions)
{
FrameDimension dimension = new FrameDimension(guid);
if (dimension.Equals(FrameDimension.Time))
{
return image.GetFrameCount(FrameDimension.Time) > 1;
}
}
}
return false;
}
public static void StopAnimate(Image image, EventHandler onFrameChangedHandler)
{
if (image == null || imageInfoList == null)
{
return;
}
bool readerLockHeld = rwImgListLock.IsReaderLockHeld;
LockCookie lockDowngradeCookie = new LockCookie();
threadWriterLockWaitCount++;
try
{
if (readerLockHeld)
{
lockDowngradeCookie = rwImgListLock.UpgradeToWriterLock(Timeout.Infinite);
}
else
{
rwImgListLock.AcquireWriterLock(Timeout.Infinite);
}
}
finally
{
threadWriterLockWaitCount--;
Debug.Assert(threadWriterLockWaitCount >= 0, "threadWriterLockWaitCount less than zero.");
}
try
{
for (int i = 0; i < imageInfoList.Count; i++)
{
ImageInfoExpender imageInfo = imageInfoList[i];
if (image == imageInfo.Image)
{
if ((onFrameChangedHandler == imageInfo.FrameChangedHandler) || (onFrameChangedHandler != null && onFrameChangedHandler.Equals(imageInfo.FrameChangedHandler)))
{
imageInfoList.Remove(imageInfo);
}
break;
}
}
}
finally
{
if (readerLockHeld)
{
rwImgListLock.DowngradeFromWriterLock(ref lockDowngradeCookie);
}
else
{
rwImgListLock.ReleaseWriterLock();
}
}
}
[SuppressMessage("Microsoft.Performance", "CA1804:RemoveUnusedLocals")]
static void AnimateImages50ms()
{
Debug.Assert(imageInfoList != null, "Null images list");
while (true)
{
rwImgListLock.AcquireReaderLock(Timeout.Infinite);
try
{
for (int i = 0; i < imageInfoList.Count; i++)
{
ImageInfoExpender imageInfo = imageInfoList[i];
imageInfo.FrameTimer += 5;
if (imageInfo.FrameTimer >= imageInfo.FrameDelay(imageInfo.Frame))
{
imageInfo.FrameTimer = 0;
if (imageInfo.Frame + 1 < imageInfo.FrameCount)
{
imageInfo.Frame++;
}
else
{
imageInfo.Frame = 0;
}
if (imageInfo.FrameDirty)
{
anyFrameDirty = true;
}
}
}
}
finally
{
rwImgListLock.ReleaseReaderLock();
}
Thread.Sleep(50);
}
}
}
}
新建一个ImageInfoExpender类:
using System;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;
using System.Windows.Media;
namespace WpfDemo
{
public class ImageSourceExpender
{
public int DelayTime { set; get; }
public ImageSource Source { set; get; }
public ImageSourceExpender(ImageSource source, int delayTime)
{
this.Source = source;
this.DelayTime = delayTime;
}
}
public class ImageInfoExpender
{
const int PropertyTagFrameDelay = 0x5100;
Image image;
int frame;
int frameCount;
bool frameDirty;
bool animated;
EventHandler onFrameChangedHandler;
int frameTimer;
ImageSourceExpender[] ImageSourceList = null;
public ImageInfoExpender(Image image)
{
this.image = image;
animated = ImageAnimator.CanAnimate(image);
if (animated)
{
frameCount = image.GetFrameCount(FrameDimension.Time);
ImageSourceList = new ImageSourceExpender[frameCount];
PropertyItem frameDelayItem = image.GetPropertyItem(PropertyTagFrameDelay);
if (frameDelayItem != null)
{
byte[] values = frameDelayItem.Value;
Debug.Assert(values.Length == 4 * FrameCount, "PropertyItem has invalid value byte array");
for (int i = 0; i < FrameCount; ++i)
{
int delayTime = values[i * 4] + 256 * values[i * 4 + 1] + 256 * 256 * values[i * 4 + 2] + 256 * 256 * 256 * values[i * 4 + 3];
image.SelectActiveFrame(FrameDimension.Time, i);
System.Drawing.Bitmap bitmap = new System.Drawing.Bitmap(this.Image.Width, this.Image.Height);
System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(bitmap);
g.DrawImage(this.Image, new System.Drawing.Rectangle(0, 0, this.Image.Width, this.Image.Height));
IntPtr ip = bitmap.GetHbitmap();
ImageSource bitmapSource = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
ip, IntPtr.Zero, System.Windows.Int32Rect.Empty,
System.Windows.Media.Imaging.BitmapSizeOptions.FromEmptyOptions());
ImageSourceList[i] = new ImageSourceExpender(bitmapSource, delayTime);
}
}
}
else
{
frameCount = 1;
}
if (ImageSourceList == null)
{
ImageSourceList = new ImageSourceExpender[frameCount];
}
}
public bool Animated
{
get
{
return animated;
}
}
public int Frame
{
get
{
return frame;
}
set
{
if (frame != value)
{
if (value < 0 || value >= FrameCount)
{
throw (new Exception("错误"));
}
if (Animated)
{
frame = value;
frameDirty = true;
OnFrameChanged(EventArgs.Empty);
}
}
}
}
public bool FrameDirty
{
get
{
return frameDirty;
}
}
public EventHandler FrameChangedHandler
{
get
{
return onFrameChangedHandler;
}
set
{
onFrameChangedHandler = value;
}
}
public int FrameCount
{
get
{
return frameCount;
}
}
public int FrameDelay(int frame)
{
return ImageSourceList[frame].DelayTime;
}
internal int FrameTimer
{
get
{
return frameTimer;
}
set
{
frameTimer = value;
}
}
internal Image Image
{
get
{
return image;
}
}
public void UpdateFrame()
{
if (frameDirty)
{
frameDirty = false;
}
return;
}
public ImageSource GetCurrentImageSource()
{
return ImageSourceList[Frame].Source;
}
protected void OnFrameChanged(EventArgs e)
{
if (this.onFrameChangedHandler != null)
{
this.onFrameChangedHandler(image, e);
}
}
}
}
最后
新建一个用户控件 GTextBlock:
<TextBlock x:Class="WpfDemo.GTextBlock"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
/>
后台代码为:
using System;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Media;
namespace WpfDemo
{
public partial class GTextBlock : TextBlock
{
static GTextBlock()
{
TextProperty.OverrideMetadata(typeof(GTextBlock), new FrameworkPropertyMetadata(
(string)TextBlock.TextProperty.GetMetadata(typeof(TextBlock)).DefaultValue,
(o, e) => (o as GTextBlock).OnTextChanged(e.NewValue as string)));
}
private void OnTextChanged(string text)
{
Inlines.Clear();
if (string.IsNullOrEmpty(text))
return;
string[] msgs = Regex.Split(text, @"(\[[^\][]+\])");
foreach (var msg in msgs)
{
if (!string.IsNullOrEmpty(msg))
{
if (msg.StartsWith("[")&& msg.EndsWith("]"))
{
string name = msg.Substring(1, msg.Length - 2);
GifFace face = SysFaces.Faces.Where(f => f.Name == name).FirstOrDefault();
if (face != null)
{
InlineUIContainer iuc = new InlineUIContainer();
var image = GegImageExpender(face);
iuc.Child = image;
Inlines.Add(iuc);
continue;
}
}
Inlines.Add(new Run(msg) { BaselineAlignment=BaselineAlignment.Center});
}
}
}
public ImageExpender GegImageExpender(GifFace face)
{
ImageExpender Img_Exp = new ImageExpender();
Img_Exp.Stretch = Stretch.UniformToFill;
Img_Exp.Visibility = Visibility.Visible;
string facePath = $"{face.ImageName}";
Stream imageStream = Application.GetResourceStream(new Uri("/faces/" + facePath, UriKind.Relative)).Stream;
System.Drawing.Bitmap bitmap = new System.Drawing.Bitmap(imageStream);
Img_Exp.Image = bitmap;
Img_Exp.Location = "/faces/" + facePath;
Img_Exp.Tag = face.Name;
Img_Exp.Width = 50;
Img_Exp.Height = 50;
return Img_Exp;
}
public GTextBlock()
{
InitializeComponent();
}
public new string Text
{
get => m_text_dpd.GetValue(this) as string;
set => m_text_dpd.SetValue(this, value);
}
public static new readonly DependencyProperty TextProperty =
DependencyProperty.Register(nameof(Text), typeof(string), typeof(GTextBlock));
private static readonly DependencyPropertyDescriptor m_text_dpd =
DependencyPropertyDescriptor.FromProperty(TextProperty, typeof(GTextBlock));
}
}
最后 ,新建一个窗口TextBlockDemo使用自定义控件:
<Window x:Class="WpfDemo.TextBlockDemo"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfDemo"
mc:Ignorable="d"
x:Name="window"
Title="ImageBlockDemo" Height="450" Width="800">
<Grid Background="LightBlue">
<StackPanel VerticalAlignment="Center"
HorizontalAlignment="Center" >
<local:GTextBlock Text="{Binding DemoText,ElementName=window}" FontSize="30" HorizontalAlignment="Center"/>
<TextBox Width="400" Height="100" FontSize="30" FontFamily="微软雅黑"
TextWrapping="Wrap"
Text="{Binding DemoText,UpdateSourceTrigger=PropertyChanged,ElementName=window}"/>
</StackPanel>
</Grid>
</Window>
窗体后台代码为:
using System.ComponentModel;
using System.Windows;
namespace WpfDemo
{
public partial class TextBlockDemo : Window, INotifyPropertyChanged
{
public TextBlockDemo()
{
InitializeComponent();
}
public event PropertyChangedEventHandler PropertyChanged;
private string _demoText="[微笑]";
public string DemoText
{
get { return _demoText; }
set
{
_demoText = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(DemoText)));
}
}
}
}
至此,大功告成!
感谢您的观看。下面是效果截图:
如果喜欢,点个赞呗~