34 changed files with 2975 additions and 47 deletions
@ -0,0 +1,42 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Globalization; |
|||
using System.Linq; |
|||
using System.Text; |
|||
using System.Threading.Tasks; |
|||
using System.Windows.Data; |
|||
|
|||
namespace QYMessageCenter.Client.Converters |
|||
{ |
|||
public class AppCodeConverter : IValueConverter |
|||
{ |
|||
private IDictionary<string, string> codeDic; |
|||
|
|||
public AppCodeConverter() |
|||
{ |
|||
codeDic = new Dictionary<string, string>() |
|||
{ |
|||
{ "PJZS", "评价助手" }, |
|||
{ "BBWYC", "步步为盈C端" }, |
|||
{ "BBWYB", "步步为盈B端" }, |
|||
{ "QK", "齐库" }, |
|||
{ "LK", "良库" }, |
|||
{ "SBF", "三板斧" }, |
|||
{ "SN", "司南" }, |
|||
}; |
|||
} |
|||
|
|||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture) |
|||
{ |
|||
var appCode = value?.ToString() ?? string.Empty; |
|||
if (codeDic.TryGetValue(appCode, out var appName)) |
|||
return appName; |
|||
else return "UnKnow App"; |
|||
} |
|||
|
|||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) |
|||
{ |
|||
throw new NotImplementedException(); |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,71 @@ |
|||
using CommunityToolkit.Mvvm.ComponentModel; |
|||
|
|||
namespace QYMessageCenter.Client.Models |
|||
{ |
|||
public class Message : ObservableObject |
|||
{ |
|||
private string appCode; |
|||
private string title; |
|||
private string content; |
|||
|
|||
|
|||
public long Id { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// 消息频道
|
|||
/// </summary>
|
|||
public string Channel { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// 消息所属团队Id
|
|||
/// </summary>
|
|||
public string TeamId { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// 消息所属店铺Id
|
|||
/// </summary>
|
|||
public string ShopId { get; set; } |
|||
|
|||
public DateTime? CreateTime { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// 自定义类型编码
|
|||
/// </summary>
|
|||
public string CustomTypeCode { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// 已读人员
|
|||
/// </summary>
|
|||
public string ReaderId { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// 发送人
|
|||
/// </summary>
|
|||
public string SenderId { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// 接收人(可空)
|
|||
/// </summary>
|
|||
public string RecevierId { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// 是否为Json消息, 解析规则参考CustomTypeCode的约定
|
|||
/// </summary>
|
|||
public bool IsJsonMsg { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// 消息所属应用
|
|||
/// </summary>
|
|||
public string AppCode { get => appCode; set { SetProperty(ref appCode, value); } } |
|||
|
|||
/// <summary>
|
|||
/// 消息标题
|
|||
/// </summary>
|
|||
public string Title { get => title; set { SetProperty(ref title, value); } } |
|||
|
|||
/// <summary>
|
|||
/// 消息内容
|
|||
/// </summary>
|
|||
public string Content { get => content; set { SetProperty(ref content, value); } } |
|||
} |
|||
} |
@ -0,0 +1,25 @@ |
|||
namespace QYMessageCenter.Client.Models.Msg |
|||
{ |
|||
/// <summary>
|
|||
/// 消息_评价助手_上架失败
|
|||
/// </summary>
|
|||
public class Message_PJZS_SHANGJIASHIBAI : Message |
|||
{ |
|||
|
|||
private string activityName; |
|||
|
|||
private string spuLogo; |
|||
|
|||
private string mainProductSpu; |
|||
|
|||
private string errorMsg; |
|||
|
|||
public string ActivityName { get => activityName; set { SetProperty(ref activityName, value); } } |
|||
|
|||
public string SpuLogo { get => spuLogo; set { SetProperty(ref spuLogo, value); } } |
|||
|
|||
public string MainProductSpu { get => mainProductSpu; set { SetProperty(ref mainProductSpu, value); } } |
|||
|
|||
public string ErrorMsg { get => errorMsg; set { SetProperty(ref errorMsg, value); } } |
|||
} |
|||
} |
@ -0,0 +1,64 @@ |
|||
using CommunityToolkit.Mvvm.Messaging; |
|||
using CommunityToolkit.Mvvm.Messaging.Messages; |
|||
using QYMessageCenter.Client.Models; |
|||
|
|||
namespace QYMessageCenter.Client |
|||
{ |
|||
public class PopupManager |
|||
{ |
|||
private List<Message> MessageList { get; set; } |
|||
|
|||
|
|||
private PopupWindow pw; |
|||
|
|||
public PopupManager() |
|||
{ |
|||
MessageList = new List<Message>(); |
|||
WeakReferenceMessenger.Default.Register<MVVMMessage_ShowNext>(this, (o, x) => ShowNext()); |
|||
} |
|||
|
|||
public void Show(Message msg) |
|||
{ |
|||
MessageList.Insert(0, msg); |
|||
Show(); |
|||
} |
|||
|
|||
private void Show() |
|||
{ |
|||
var msg = MessageList[0]; |
|||
if (pw != null) |
|||
{ |
|||
pw.RefreshMsg(msg); |
|||
} |
|||
else |
|||
{ |
|||
pw = new PopupWindow(msg); |
|||
pw.Closed += Pw_Closed; |
|||
pw.Show(); |
|||
} |
|||
} |
|||
|
|||
private void Pw_Closed(object? sender, EventArgs e) |
|||
{ |
|||
pw = null; |
|||
MessageList.Clear(); |
|||
} |
|||
|
|||
public void ShowNext() |
|||
{ |
|||
if (MessageList.Count() > 0) |
|||
MessageList.RemoveAt(0); |
|||
if (MessageList.Count() == 0) |
|||
pw.Close(); |
|||
else |
|||
Show(); |
|||
} |
|||
} |
|||
|
|||
public class MVVMMessage_ShowNext : ValueChangedMessage<object> |
|||
{ |
|||
public MVVMMessage_ShowNext(object value) : base(value) |
|||
{ |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,122 @@ |
|||
<c:BWindow x:Class="QYMessageCenter.Client.PopupWindow" |
|||
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:QYMessageCenter.Client" |
|||
xmlns:c="clr-namespace:SJ.Controls;assembly=SJ.Controls" |
|||
xmlns:templateSelector="clr-namespace:QYMessageCenter.Client.TemplateSelector" |
|||
mc:Ignorable="d" |
|||
Title="PopupWindow" Height="260" Width="350" |
|||
MinButtonVisibility="Collapsed" |
|||
MaxButtonVisibility="Collapsed" |
|||
CloseButtonVisibility="Collapsed" |
|||
Style="{StaticResource bwstyle}"> |
|||
<Window.Resources> |
|||
<SolidColorBrush x:Key="Border.Brush" Color="#D7D7D7"/> |
|||
<SolidColorBrush x:Key="Border.Background" Color="#8080FF"/> |
|||
<SolidColorBrush x:Key="Text.Link.Color" Color="#02A7F0"/> |
|||
<SolidColorBrush x:Key="Text.Property.Color" Color="Gray"/> |
|||
<Style x:Key="middleTextBlock" TargetType="TextBlock"> |
|||
<Setter Property="HorizontalAlignment" Value="Center"/> |
|||
<Setter Property="VerticalAlignment" Value="Center"/> |
|||
</Style> |
|||
<Style x:Key="LinkButton" TargetType="{x:Type c:BButton}"> |
|||
<Setter Property="BorderThickness" Value="0"/> |
|||
<Setter Property="Background" Value="Transparent"/> |
|||
<Setter Property="Foreground" Value="{StaticResource Text.Link.Color}"/> |
|||
</Style> |
|||
|
|||
<DataTemplate x:Key="Template_PJZS_SHANGJIASHIBAI"> |
|||
<Grid> |
|||
<Grid.RowDefinitions> |
|||
<RowDefinition Height="40"/> |
|||
<RowDefinition Height="80"/> |
|||
<RowDefinition/> |
|||
</Grid.RowDefinitions> |
|||
<TextBlock Text="{Binding AppCode,Converter={StaticResource appCodeCtr}}" |
|||
VerticalAlignment="Center" Margin="10,0,0,0" FontSize="14"/> |
|||
<Grid Grid.Row="1"> |
|||
<Grid.RowDefinitions> |
|||
<RowDefinition Height="25"/> |
|||
<RowDefinition/> |
|||
</Grid.RowDefinitions> |
|||
<Grid.ColumnDefinitions> |
|||
<ColumnDefinition Width="90"/> |
|||
<ColumnDefinition/> |
|||
</Grid.ColumnDefinitions> |
|||
<c:BAsyncImage UrlSource="{Binding SpuLogo}" DecodePixelWidth="70" Width="70" |
|||
Grid.RowSpan="2" |
|||
VerticalAlignment="Top"/> |
|||
<TextBlock Grid.Column="1"> |
|||
<Run Text="活动名称:" Foreground="{StaticResource Text.Property.Color}"/> |
|||
<Run Text="{Binding ActivityName}"/> |
|||
</TextBlock> |
|||
<TextBlock Grid.Column="1" Grid.Row="1" VerticalAlignment="Top"> |
|||
<Run Text="SPU:" Foreground="{StaticResource Text.Property.Color}"/> |
|||
<Run Text="{Binding MainProductSpu}"/> |
|||
</TextBlock> |
|||
</Grid> |
|||
<TextBlock Text="{Binding ErrorMsg}" |
|||
TextWrapping="Wrap" |
|||
Grid.Row="2" |
|||
Margin="10,0"/> |
|||
</Grid> |
|||
</DataTemplate> |
|||
|
|||
<DataTemplate x:Key="Template_Normal"> |
|||
<Grid> |
|||
<Grid.RowDefinitions> |
|||
<RowDefinition Height="40"/> |
|||
<RowDefinition/> |
|||
</Grid.RowDefinitions> |
|||
<TextBlock Text="{Binding AppCode,Converter={StaticResource appCodeCtr}}" |
|||
VerticalAlignment="Center" Margin="10,0,0,0" FontSize="14"/> |
|||
<TextBlock Text="{Binding Content}" Grid.Row="1" Margin="10,0" TextWrapping="Wrap"/> |
|||
</Grid> |
|||
</DataTemplate> |
|||
|
|||
|
|||
|
|||
<templateSelector:MessageTemplateSelector x:Key="mtSelector" |
|||
Template_Normal="{StaticResource Template_Normal}" |
|||
Template_PJZS_SHANGJIASHIBAI="{StaticResource Template_PJZS_SHANGJIASHIBAI}"/> |
|||
</Window.Resources> |
|||
<Grid> |
|||
<Grid.RowDefinitions> |
|||
<RowDefinition Height="35"/> |
|||
<RowDefinition/> |
|||
<RowDefinition Height="30"/> |
|||
</Grid.RowDefinitions> |
|||
|
|||
<Border BorderBrush="{StaticResource Border.Brush}" |
|||
Background="{StaticResource Border.Background}"/> |
|||
|
|||
<TextBlock Text="{Binding Msg.Title}" VerticalAlignment="Center" HorizontalAlignment="Left" Margin="10,0,0,0" |
|||
Foreground="White" FontSize="14"/> |
|||
|
|||
<c:BButton HorizontalAlignment="Right" Margin="0,0,10,0" BorderThickness="0" |
|||
x:Name="btn_Close" Click="btn_Close_Click"> |
|||
<Path x:Name="p" Stretch="Uniform" SnapsToDevicePixels="True" UseLayoutRounding="True" |
|||
Data="M814.060 781.227q-67.241-67.241-269.773-269.773 67.241-67.241 269.773-269.773 5.671-6.481 5.671-12.962 0 0-0.81-0.81 0-6.481-4.861-9.722-4.861-4.051-11.342-4.861-0.81 0-0.81 0-5.671 0-11.342 4.861-89.924 89.924-269.773 269.773-67.241-67.241-269.773-269.773-4.861-4.861-12.962-4.861-7.291 0.81-10.532 4.861-5.671 5.671-5.671 11.342 0 6.481 5.671 12.152 89.924 89.924 269.773 269.773-67.241 67.241-269.773 269.773-11.342 11.342 0 23.494 12.152 11.342 23.494 0 89.924-89.924 269.773-269.773 67.241 67.241 269.773 269.773 5.671 5.671 11.342 5.671 5.671 0 12.152-5.671 4.861-5.671 4.861-12.962 0-6.481-4.861-10.532z" |
|||
Width="14" Height="14" Stroke="White"/> |
|||
</c:BButton> |
|||
|
|||
|
|||
<c:BButton Style="{StaticResource LinkButton}" |
|||
Content="查看详情" |
|||
Grid.Row="2" |
|||
Margin="10,0,0,0" |
|||
HorizontalAlignment="Left"/> |
|||
|
|||
<c:BButton x:Name="btn_showNext" Style="{StaticResource LinkButton}" |
|||
Content="下一条" |
|||
Grid.Row="2" |
|||
Margin="0,0,10,0" |
|||
HorizontalAlignment="Right" |
|||
Click="btn_showNext_Click"/> |
|||
|
|||
<ContentControl Content="{Binding Msg,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" ContentTemplateSelector="{StaticResource mtSelector}" |
|||
Grid.Row="1"/> |
|||
</Grid> |
|||
</c:BWindow> |
@ -0,0 +1,47 @@ |
|||
using CommunityToolkit.Mvvm.Messaging; |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using QYMessageCenter.Client.Models; |
|||
using SJ.Controls; |
|||
using System.Windows; |
|||
|
|||
namespace QYMessageCenter.Client |
|||
{ |
|||
/// <summary>
|
|||
/// PopupWindow.xaml 的交互逻辑
|
|||
/// </summary>
|
|||
public partial class PopupWindow : BWindow |
|||
{ |
|||
private Message msg; |
|||
public Message Msg { get => msg; set { Set(ref msg, value); } } |
|||
|
|||
public PopupWindow(Message msg) |
|||
{ |
|||
InitializeComponent(); |
|||
this.Msg = msg; |
|||
this.DataContext = this; |
|||
this.Loaded += PopupWindow_Loaded; |
|||
} |
|||
|
|||
private void PopupWindow_Loaded(object sender, RoutedEventArgs e) |
|||
{ |
|||
//弹窗显示在右下角
|
|||
this.Left = SystemParameters.WorkArea.Width - this.Width; |
|||
this.Top = SystemParameters.WorkArea.Height - this.Height; |
|||
} |
|||
|
|||
public void RefreshMsg(Message msg) |
|||
{ |
|||
this.Msg = msg; |
|||
} |
|||
|
|||
private void btn_showNext_Click(object sender, RoutedEventArgs e) |
|||
{ |
|||
WeakReferenceMessenger.Default.Send(new MVVMMessage_ShowNext(null)); |
|||
} |
|||
|
|||
private void btn_Close_Click(object sender, RoutedEventArgs e) |
|||
{ |
|||
WeakReferenceMessenger.Default.Send(new MVVMMessage_ShowNext(null)); |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,19 @@ |
|||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" |
|||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
|||
xmlns:c="clr-namespace:SJ.Controls;assembly=SJ.Controls"> |
|||
<SolidColorBrush x:Key="WindowButtonColor" Color="Black"/> |
|||
<SolidColorBrush x:Key="Text.Link.Color" Color="#02A7F0"/> |
|||
|
|||
<Style x:Key="LinkButton" TargetType="{x:Type c:BButton}"> |
|||
<Setter Property="BorderThickness" Value="0"/> |
|||
<Setter Property="Background" Value="Transparent"/> |
|||
<Setter Property="Foreground" Value="{StaticResource Text.Link.Color}"/> |
|||
</Style> |
|||
|
|||
<Style x:Key="bwstyle" TargetType="c:BWindow"> |
|||
<Setter Property="MaxButtonColor" Value="{StaticResource WindowButtonColor}"/> |
|||
<Setter Property="MinButtonColor" Value="{StaticResource WindowButtonColor}"/> |
|||
<Setter Property="CloseButtonColor" Value="{StaticResource WindowButtonColor}"/> |
|||
<Setter Property="RightButtonGroupMargin" Value="0,5,5,0"/> |
|||
</Style> |
|||
</ResourceDictionary> |
@ -0,0 +1,30 @@ |
|||
using QYMessageCenter.Client.Models; |
|||
using System.Windows; |
|||
using System.Windows.Controls; |
|||
|
|||
namespace QYMessageCenter.Client.TemplateSelector |
|||
{ |
|||
public class MessageTemplateSelector : DataTemplateSelector |
|||
{ |
|||
public DataTemplate Template_Normal { get; set; } |
|||
|
|||
public DataTemplate Template_PJZS_SHANGJIASHIBAI { get; set; } |
|||
|
|||
public override DataTemplate SelectTemplate(object item, DependencyObject container) |
|||
{ |
|||
if (item == null) |
|||
return null; |
|||
|
|||
var msg = item as Message; |
|||
if (msg.AppCode == "PJZS") |
|||
{ |
|||
if (msg.CustomTypeCode == "SHANGJIASHIBAI") |
|||
{ |
|||
return Template_PJZS_SHANGJIASHIBAI; |
|||
} |
|||
} |
|||
|
|||
return Template_Normal; |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,10 @@ |
|||
using System.Windows; |
|||
|
|||
[assembly: ThemeInfo( |
|||
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
|
|||
//(used if a resource is not found in the page,
|
|||
// or application resource dictionaries)
|
|||
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
|
|||
//(used if a resource is not found in the page,
|
|||
// app, or any theme specific resource dictionaries)
|
|||
)] |
@ -0,0 +1,705 @@ |
|||
using System; |
|||
using System.Collections.Concurrent; |
|||
using System.Collections.Generic; |
|||
using System.Net.Http; |
|||
using System.Runtime.CompilerServices; |
|||
using System.Runtime.InteropServices; |
|||
using System.Text.RegularExpressions; |
|||
using System.Threading; |
|||
using System.Threading.Tasks; |
|||
using System.Threading.Tasks.Schedulers; |
|||
using System.Windows; |
|||
using System.Windows.Controls; |
|||
using System.Windows.Interop; |
|||
using System.Windows.Media; |
|||
using System.Windows.Media.Imaging; |
|||
using System.Windows.Resources; |
|||
using dw = System.Drawing; |
|||
|
|||
namespace SJ.Controls |
|||
{ |
|||
public class BAsyncImage : Control |
|||
{ |
|||
#region DependencyProperty
|
|||
public static readonly DependencyProperty DecodePixelWidthProperty = DependencyProperty.Register("DecodePixelWidth", |
|||
typeof(double), typeof(BAsyncImage), new PropertyMetadata(0.0)); |
|||
|
|||
public static readonly DependencyProperty LoadingTextProperty = |
|||
DependencyProperty.Register("LoadingText", typeof(string), typeof(BAsyncImage), new PropertyMetadata("Loading...")); |
|||
|
|||
public static readonly DependencyProperty IsLoadingProperty = |
|||
DependencyProperty.Register("IsLoading", typeof(bool), typeof(BAsyncImage), new PropertyMetadata(false)); |
|||
|
|||
public static readonly DependencyProperty ImageSourceProperty = DependencyProperty.Register("ImageSource", typeof(ImageSource), typeof(BAsyncImage)); |
|||
|
|||
public static readonly DependencyProperty DefaultUrlSourceProperty = DependencyProperty.Register("DefaultUrlSource", typeof(string), typeof(BAsyncImage), new PropertyMetadata("")); |
|||
|
|||
public static readonly DependencyProperty UrlSourceProperty = |
|||
DependencyProperty.Register("UrlSource", typeof(string), typeof(BAsyncImage), new PropertyMetadata(string.Empty, new PropertyChangedCallback((s, e) => |
|||
{ |
|||
var asyncImg = s as BAsyncImage; |
|||
if (asyncImg.LoadEventFlag) |
|||
{ |
|||
asyncImg.Load(); |
|||
} |
|||
}))); |
|||
|
|||
public static readonly DependencyProperty FailUrlSourceProperty = |
|||
DependencyProperty.Register("FailUrlSource", typeof(string), typeof(BAsyncImage), new PropertyMetadata(string.Empty)); |
|||
|
|||
public static readonly DependencyProperty IsCacheProperty = DependencyProperty.Register("IsCache", typeof(bool), typeof(BAsyncImage), new PropertyMetadata(true)); |
|||
|
|||
public static readonly DependencyProperty StretchProperty = DependencyProperty.Register("Stretch", typeof(Stretch), typeof(BAsyncImage), new PropertyMetadata(Stretch.Uniform)); |
|||
|
|||
public static readonly DependencyProperty CacheGroupProperty = DependencyProperty.Register("CacheGroup", typeof(string), typeof(BAsyncImage), new PropertyMetadata("QLAsyncImage_Default")); |
|||
#endregion
|
|||
|
|||
#region Property
|
|||
private static readonly HttpClient httpClient = new HttpClient(); |
|||
|
|||
public double StaticImageActualPixelWidth { get; set; } = 0; |
|||
|
|||
public double StaticImageActualPixelHeight { get; set; } = 0; |
|||
|
|||
public const string LocalRegex = @"^([C-J]):\\([^:&]+\\)*([^:&]+).(jpg|jpeg|png|gif)$"; |
|||
public const string HttpRegex = @"^((https|http):\/\/)?([^\\*+@]+)$"; |
|||
|
|||
private Image _image; |
|||
private dw.Bitmap gifBitmap; |
|||
private bool LoadEventFlag = false; |
|||
private static ConcurrentDictionary<string, ImageSource> ImageCacheList; |
|||
private static ConcurrentDictionary<string, byte[]> GifImageCacheList; |
|||
|
|||
private static LimitedConcurrencyLevelTaskScheduler httpTaskScheduler; |
|||
|
|||
public double DecodePixelWidth |
|||
{ |
|||
get { return (double)GetValue(DecodePixelWidthProperty); } |
|||
set { SetValue(DecodePixelWidthProperty, value); } |
|||
} |
|||
public string LoadingText |
|||
{ |
|||
get { return GetValue(LoadingTextProperty) as string; } |
|||
set { SetValue(LoadingTextProperty, value); } |
|||
} |
|||
|
|||
public bool IsLoading |
|||
{ |
|||
get { return (bool)GetValue(IsLoadingProperty); } |
|||
set { SetValue(IsLoadingProperty, value); } |
|||
} |
|||
|
|||
public string UrlSource |
|||
{ |
|||
get { return GetValue(UrlSourceProperty) as string; } |
|||
set { SetValue(UrlSourceProperty, value); } |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 仅限Resourcesl路径
|
|||
/// </summary>
|
|||
public string FailUrlSource |
|||
{ |
|||
get { return GetValue(FailUrlSourceProperty) as string; } |
|||
set { SetValue(FailUrlSourceProperty, value); } |
|||
} |
|||
|
|||
public ImageSource ImageSource |
|||
{ |
|||
get { return GetValue(ImageSourceProperty) as ImageSource; } |
|||
set { SetValue(ImageSourceProperty, value); } |
|||
} |
|||
|
|||
public bool IsCache |
|||
{ |
|||
get { return (bool)GetValue(IsCacheProperty); } |
|||
set { SetValue(IsCacheProperty, value); } |
|||
} |
|||
|
|||
public Stretch Stretch |
|||
{ |
|||
get { return (Stretch)GetValue(StretchProperty); } |
|||
set { SetValue(StretchProperty, value); } |
|||
} |
|||
|
|||
public string CacheGroup |
|||
{ |
|||
get { return GetValue(CacheGroupProperty) as string; } |
|||
set { SetValue(CacheGroupProperty, value); } |
|||
} |
|||
|
|||
#endregion
|
|||
|
|||
#region RouteEvent
|
|||
public delegate void QLAsyncImageLoadCompleteHandler(object sender, QLAsyncImageLoadCompleteEventArgs e); |
|||
|
|||
public static readonly RoutedEvent OnLoadCompleteEvent = EventManager.RegisterRoutedEvent("OnLoadComplete", RoutingStrategy.Bubble, typeof(QLAsyncImageLoadCompleteHandler), typeof(BAsyncImage)); |
|||
|
|||
public event QLAsyncImageLoadCompleteHandler OnLoadComplete |
|||
{ |
|||
add { AddHandler(OnLoadCompleteEvent, value); } |
|||
remove { RemoveHandler(OnLoadCompleteEvent, value); } |
|||
} |
|||
#endregion
|
|||
|
|||
#region Method
|
|||
static BAsyncImage() |
|||
{ |
|||
DefaultStyleKeyProperty.OverrideMetadata(typeof(BAsyncImage), new FrameworkPropertyMetadata(typeof(BAsyncImage))); |
|||
ImageCacheList = new ConcurrentDictionary<string, ImageSource>(); |
|||
GifImageCacheList = new ConcurrentDictionary<string, byte[]>(); |
|||
httpTaskScheduler = new LimitedConcurrencyLevelTaskScheduler(10); |
|||
} |
|||
|
|||
public BAsyncImage() |
|||
{ |
|||
Loaded += QLAsyncImage_Loaded; |
|||
Unloaded += QLAsyncImage_Unloaded; |
|||
} |
|||
|
|||
private void QLAsyncImage_Unloaded(object sender, RoutedEventArgs e) |
|||
{ |
|||
Reset(); |
|||
LoadEventFlag = false; |
|||
} |
|||
|
|||
private void QLAsyncImage_Loaded(object sender, RoutedEventArgs e) |
|||
{ |
|||
Init(); |
|||
} |
|||
|
|||
public override void OnApplyTemplate() |
|||
{ |
|||
Init(); |
|||
} |
|||
|
|||
private void Init([CallerMemberName] string eventName = "") |
|||
{ |
|||
if (LoadEventFlag) |
|||
return; |
|||
|
|||
_image = GetTemplateChild("image") as Image; |
|||
|
|||
if (_image == null) |
|||
return; |
|||
|
|||
LoadEventFlag = true; |
|||
Load(); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Delete local bitmap resource
|
|||
/// Reference: http://msdn.microsoft.com/en-us/library/dd183539(VS.85).aspx
|
|||
/// </summary>
|
|||
[DllImport("gdi32.dll", CharSet = CharSet.Auto, SetLastError = true)] |
|||
[return: MarshalAs(UnmanagedType.Bool)] |
|||
static extern bool DeleteObject(IntPtr hObject); |
|||
|
|||
/// <summary>
|
|||
/// 重置图像
|
|||
/// </summary>
|
|||
private void Reset() |
|||
{ |
|||
//停止播放Gif动画
|
|||
if (gifBitmap != null) |
|||
StopGif(); |
|||
SetSource(null); |
|||
} |
|||
|
|||
private void Load() |
|||
{ |
|||
if (_image == null) |
|||
return; |
|||
|
|||
Reset(); |
|||
|
|||
if (!string.IsNullOrEmpty(UrlSource)) |
|||
{ |
|||
var url = UrlSource; |
|||
var failUrl = FailUrlSource; |
|||
var pixelWidth = (int)DecodePixelWidth; |
|||
var isCache = IsCache; |
|||
var cacheKey = string.Format("{0}_{1}", CacheGroup, url); |
|||
IsLoading = !ImageCacheList.ContainsKey(cacheKey) && !GifImageCacheList.ContainsKey(cacheKey); |
|||
|
|||
#region 读取缓存
|
|||
if (ImageCacheList.ContainsKey(cacheKey)) |
|||
{ |
|||
var source = ImageCacheList[cacheKey]; |
|||
SetSource(source); |
|||
SetStaticImageActualPixelSize(source.Width, source.Height); |
|||
LoadComplete(string.Empty, url); |
|||
return; |
|||
} |
|||
else if (GifImageCacheList.ContainsKey(cacheKey)) |
|||
{ |
|||
PlayGif(GifImageCacheList[cacheKey]); |
|||
LoadComplete(string.Empty, url); |
|||
return; |
|||
} |
|||
#endregion
|
|||
|
|||
this.Load(url, failUrl, cacheKey, isCache, pixelWidth); |
|||
} |
|||
} |
|||
|
|||
private void Load(string url, string failUrl, string cacheKey, bool isCache, int pixelWidth) |
|||
{ |
|||
var errorMessage = string.Empty; |
|||
|
|||
//解析路径类型
|
|||
var pathType = ValidatePathType(url); |
|||
if (pathType == PathType.Invalid) |
|||
{ |
|||
LoadFail(failUrl); |
|||
LoadComplete(errorMessage, url); |
|||
return; |
|||
} |
|||
|
|||
if (pathType == PathType.Http) |
|||
{ |
|||
////先加载默认图
|
|||
//if (!string.IsNullOrEmpty(defaultUrl))
|
|||
// LoadLocal(defaultUrl, failUrl, PathType.Resources, defaultUrl, true, 0, excuteComplete: false); //默认图不触发加载完毕事件
|
|||
LoadHttp(url, failUrl, cacheKey, isCache, pixelWidth); |
|||
} |
|||
else |
|||
LoadLocal(url, failUrl, pathType, cacheKey, isCache, pixelWidth); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 加载失败图像
|
|||
/// </summary>
|
|||
/// <param name="failUrl"></param>
|
|||
private void LoadFail(string failUrl) |
|||
{ |
|||
byte[] imgBytes = null; |
|||
string errorMessage = string.Empty; |
|||
var pathType = ValidatePathType(failUrl); |
|||
if (pathType == PathType.Invalid) |
|||
{ |
|||
Console.ForegroundColor = ConsoleColor.Red; |
|||
Console.WriteLine($"LoadFail 无效的路径 {failUrl}"); |
|||
Console.ResetColor(); |
|||
return; |
|||
} |
|||
if (pathType == PathType.Local) |
|||
imgBytes = LoadBytesFromLocal(failUrl, out errorMessage); |
|||
else if (pathType == PathType.Resources) |
|||
imgBytes = LoadBytesFromApplicationResource(failUrl, out errorMessage); |
|||
|
|||
|
|||
if (string.IsNullOrEmpty(errorMessage) && imgBytes != null) |
|||
AnalysisBytes(imgBytes, failUrl, true, 0, out errorMessage); |
|||
|
|||
if (string.IsNullOrEmpty(errorMessage)) |
|||
return; |
|||
|
|||
Console.ForegroundColor = ConsoleColor.Red; |
|||
Console.WriteLine($"LoadFail {errorMessage} {failUrl}"); |
|||
Console.ResetColor(); |
|||
} |
|||
|
|||
private void LoadLocal(string url, string failUrl, PathType pathType, string cacheKey, bool isCache, int pixelWidth, bool excuteComplete = true) |
|||
{ |
|||
byte[] imgBytes = null; |
|||
var errorMessage = string.Empty; |
|||
if (pathType == PathType.Local) |
|||
imgBytes = LoadBytesFromLocal(url, out errorMessage); |
|||
else if (pathType == PathType.Resources) |
|||
imgBytes = LoadBytesFromApplicationResource(url, out errorMessage); |
|||
|
|||
if (string.IsNullOrEmpty(errorMessage) && imgBytes != null) |
|||
AnalysisBytes(imgBytes, cacheKey, isCache, pixelWidth, out errorMessage); |
|||
|
|||
if (!string.IsNullOrEmpty(errorMessage)) |
|||
{ |
|||
LoadFail(failUrl); |
|||
Console.ForegroundColor = ConsoleColor.Red; |
|||
} |
|||
Console.WriteLine($"LoadLocal {errorMessage} {url}"); |
|||
Console.ResetColor(); |
|||
if (excuteComplete) |
|||
LoadComplete(errorMessage, url); |
|||
return; |
|||
} |
|||
|
|||
private void LoadHttp(string url, string failUrl, string cacheKey, bool isCache, int pixelWidth) |
|||
{ |
|||
Task.Factory.StartNew(() => |
|||
{ |
|||
//Thread.Sleep(2000);
|
|||
Console.WriteLine($"LoadHttp Start {url}"); |
|||
var errorMessage = string.Empty; |
|||
var imgBytes = LoadBytesFromHttp(url, out errorMessage); |
|||
|
|||
if (string.IsNullOrEmpty(errorMessage) && imgBytes != null) |
|||
AnalysisBytes(imgBytes, cacheKey, isCache, pixelWidth, out errorMessage); |
|||
|
|||
if (!string.IsNullOrEmpty(errorMessage)) |
|||
{ |
|||
LoadFail(failUrl); |
|||
Console.ForegroundColor = ConsoleColor.Red; |
|||
} |
|||
Console.WriteLine($"LoadHttp Completed {errorMessage} {url}"); |
|||
Console.ResetColor(); |
|||
LoadComplete(errorMessage, url); |
|||
return; |
|||
}, CancellationToken.None, TaskCreationOptions.None, httpTaskScheduler); |
|||
} |
|||
|
|||
private void AnalysisBytes(byte[] imgBytes, string cacheKey, bool isCache, int pixelWidth, out string errorMessage) |
|||
{ |
|||
errorMessage = string.Empty; |
|||
|
|||
#region 读取文件类型
|
|||
var imgType = GetImageType(imgBytes); |
|||
if (imgType == ImageType.Invalid) |
|||
{ |
|||
imgBytes = null; |
|||
errorMessage = "Invalid ImageFile"; |
|||
return; |
|||
} |
|||
#endregion
|
|||
|
|||
#region 加载图像
|
|||
if (imgType != ImageType.Gif) |
|||
{ |
|||
//加载静态图像
|
|||
var imgSource = LoadStaticImage(cacheKey, imgBytes, pixelWidth, isCache, out errorMessage); |
|||
if (imgSource == null) |
|||
return; |
|||
SetStaticImageActualPixelSize(imgSource.Width, imgSource.Height); |
|||
SetSource(imgSource); |
|||
} |
|||
else |
|||
{ |
|||
var frameCount = 0; |
|||
using (var memoryStream = new System.IO.MemoryStream(imgBytes)) |
|||
{ |
|||
//读取gif帧数
|
|||
var decoder = BitmapDecoder.Create(memoryStream, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.OnLoad); |
|||
frameCount = decoder.Frames.Count; |
|||
decoder = null; |
|||
} |
|||
if (frameCount > 1) |
|||
{ |
|||
CacheGifBytes(cacheKey, imgBytes, isCache); |
|||
PlayGif(imgBytes); |
|||
} |
|||
else |
|||
{ |
|||
//gif只有1帧,视为静态图处理
|
|||
var imgSource = LoadStaticImage(cacheKey, imgBytes, pixelWidth, isCache, out errorMessage); |
|||
if (imgSource == null) |
|||
return; |
|||
SetStaticImageActualPixelSize(imgSource.Width, imgSource.Height); |
|||
SetSource(imgSource); |
|||
} |
|||
} |
|||
#endregion
|
|||
} |
|||
|
|||
|
|||
/// <summary>
|
|||
/// 加载静态图像
|
|||
/// </summary>
|
|||
/// <param name="cacheKey"></param>
|
|||
/// <param name="imgBytes"></param>
|
|||
/// <param name="pixelWidth"></param>
|
|||
/// <param name="isCache"></param>
|
|||
/// <returns></returns>
|
|||
private ImageSource LoadStaticImage(string cacheKey, byte[] imgBytes, int pixelWidth, bool isCache, out string errorMessage) |
|||
{ |
|||
errorMessage = string.Empty; |
|||
if (ImageCacheList.ContainsKey(cacheKey)) |
|||
return ImageCacheList[cacheKey]; |
|||
var bit = new BitmapImage() { CacheOption = BitmapCacheOption.OnLoad }; |
|||
try |
|||
{ |
|||
bit.BeginInit(); |
|||
if (pixelWidth != 0) |
|||
{ |
|||
bit.DecodePixelWidth = pixelWidth; |
|||
} |
|||
bit.StreamSource = new System.IO.MemoryStream(imgBytes); |
|||
bit.EndInit(); |
|||
bit.Freeze(); |
|||
if (isCache && !ImageCacheList.ContainsKey(cacheKey)) |
|||
ImageCacheList.TryAdd(cacheKey, bit); |
|||
} |
|||
catch (Exception ex) |
|||
{ |
|||
errorMessage = $"LoadStaticImage Error {ex.Message}"; |
|||
bit = null; |
|||
} |
|||
return bit; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 加载Gif图像动画
|
|||
/// </summary>
|
|||
/// <param name="cacheKey"></param>
|
|||
/// <param name="imgBytes"></param>
|
|||
/// <param name="pixelWidth"></param>
|
|||
/// <param name="isCache"></param>
|
|||
/// <returns></returns>
|
|||
private void CacheGifBytes(string cacheKey, byte[] imgBytes, bool isCache) |
|||
{ |
|||
if (isCache && !GifImageCacheList.ContainsKey(cacheKey)) |
|||
GifImageCacheList.TryAdd(cacheKey, imgBytes); |
|||
} |
|||
|
|||
private byte[] LoadBytesFromHttp(string url, out string errorMessage) |
|||
{ |
|||
errorMessage = string.Empty; |
|||
try |
|||
{ |
|||
return httpClient.GetByteArrayAsync(url).Result; |
|||
} |
|||
catch (Exception ex) |
|||
{ |
|||
errorMessage = $"Dowdload Error {ex.Message}"; |
|||
} |
|||
return null; |
|||
} |
|||
|
|||
private byte[] LoadBytesFromLocal(string path, out string errorMessage) |
|||
{ |
|||
errorMessage = string.Empty; |
|||
if (!System.IO.File.Exists(path)) |
|||
{ |
|||
errorMessage = "File No Exists"; |
|||
return null; |
|||
} |
|||
try |
|||
{ |
|||
return System.IO.File.ReadAllBytes(path); |
|||
} |
|||
catch (Exception ex) |
|||
{ |
|||
errorMessage = $"Load Local Error {ex.Message}"; |
|||
return null; |
|||
} |
|||
} |
|||
|
|||
private byte[] LoadBytesFromApplicationResource(string path, out string errorMessage) |
|||
{ |
|||
errorMessage = string.Empty; |
|||
try |
|||
{ |
|||
StreamResourceInfo streamInfo = Application.GetResourceStream(new Uri(path, UriKind.RelativeOrAbsolute)); |
|||
if (streamInfo.Stream.CanRead) |
|||
{ |
|||
using (streamInfo.Stream) |
|||
{ |
|||
var bytes = new byte[streamInfo.Stream.Length]; |
|||
streamInfo.Stream.Read(bytes, 0, bytes.Length); |
|||
return bytes; |
|||
} |
|||
} |
|||
} |
|||
catch (Exception ex) |
|||
{ |
|||
errorMessage = $"Load Resource Error {ex.Message}"; |
|||
return null; |
|||
} |
|||
return null; |
|||
} |
|||
|
|||
private void SetSource(ImageSource source) |
|||
{ |
|||
Dispatcher.BeginInvoke((Action)delegate |
|||
{ |
|||
if (_image != null) |
|||
_image.Source = source; |
|||
}); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 更新图像实际像素
|
|||
/// </summary>
|
|||
/// <param name="pixelWidth"></param>
|
|||
private void SetStaticImageActualPixelSize(double pixelWidth, double pixelHeight) |
|||
{ |
|||
Dispatcher.Invoke(() => |
|||
{ |
|||
StaticImageActualPixelWidth = pixelWidth; |
|||
StaticImageActualPixelHeight = pixelHeight; |
|||
}); |
|||
} |
|||
|
|||
private void PlayGif(byte[] imgBytes) |
|||
{ |
|||
gifBitmap = new dw.Bitmap(new System.IO.MemoryStream(imgBytes)); |
|||
if (dw.ImageAnimator.CanAnimate(gifBitmap)) |
|||
{ |
|||
SetStaticImageActualPixelSize(gifBitmap.Width, gifBitmap.Height); |
|||
dw.ImageAnimator.Animate(gifBitmap, OnGifFrameChanged); |
|||
} |
|||
else |
|||
{ |
|||
gifBitmap.Dispose(); |
|||
} |
|||
} |
|||
|
|||
private void StopGif() |
|||
{ |
|||
dw.ImageAnimator.StopAnimate(gifBitmap, OnGifFrameChanged); |
|||
gifBitmap.Dispose(); |
|||
} |
|||
|
|||
private void OnGifFrameChanged(object sender, EventArgs e) |
|||
{ |
|||
dw.ImageAnimator.UpdateFrames(); |
|||
var currentFrameImageSource = GetBitmapSource(); |
|||
if (currentFrameImageSource != null) |
|||
currentFrameImageSource.Freeze(); |
|||
SetSource(currentFrameImageSource); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 加载完成
|
|||
/// </summary>
|
|||
/// <param name="errorMessage"></param>
|
|||
/// <param name="url"></param>
|
|||
private void LoadComplete(string errorMessage, string url) |
|||
{ |
|||
this.Dispatcher.BeginInvoke((Action)delegate |
|||
{ |
|||
IsLoading = false; |
|||
var args = new QLAsyncImageLoadCompleteEventArgs(OnLoadCompleteEvent, this) |
|||
{ |
|||
IsSuccess = string.IsNullOrEmpty(errorMessage), |
|||
UrlSource = url, |
|||
ErrorMessage = errorMessage, |
|||
StaticImageActualPixelWidth = StaticImageActualPixelWidth, |
|||
StaticImageActualPixelHeight = StaticImageActualPixelHeight |
|||
}; |
|||
this.RaiseEvent(args); |
|||
}); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 从System.Drawing.Bitmap中获得当前帧图像的BitmapSource
|
|||
/// </summary>
|
|||
/// <returns></returns>
|
|||
private ImageSource GetBitmapSource() |
|||
{ |
|||
IntPtr handle = IntPtr.Zero; |
|||
try |
|||
{ |
|||
handle = gifBitmap.GetHbitmap(); |
|||
return Imaging.CreateBitmapSourceFromHBitmap(handle, IntPtr.Zero, System.Windows.Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions()); |
|||
} |
|||
catch |
|||
{ |
|||
return null; |
|||
} |
|||
finally |
|||
{ |
|||
if (handle != IntPtr.Zero) |
|||
{ |
|||
DeleteObject(handle); |
|||
} |
|||
} |
|||
} |
|||
|
|||
public void Refresh() |
|||
{ |
|||
Load(); |
|||
} |
|||
|
|||
private PathType ValidatePathType(string path) |
|||
{ |
|||
if (path.StartsWith("pack://")) |
|||
return PathType.Resources; |
|||
else if (Regex.IsMatch(path, BAsyncImage.LocalRegex, RegexOptions.IgnoreCase)) |
|||
return PathType.Local; |
|||
else if (Regex.IsMatch(path, BAsyncImage.HttpRegex, RegexOptions.IgnoreCase)) |
|||
return PathType.Http; |
|||
else |
|||
return PathType.Invalid; |
|||
} |
|||
|
|||
private ImageType GetImageType(byte[] bytes) |
|||
{ |
|||
var type = ImageType.Invalid; |
|||
try |
|||
{ |
|||
var fileHead = Convert.ToInt32($"{bytes[0]}{bytes[1]}"); |
|||
if (!Enum.IsDefined(typeof(ImageType), fileHead)) |
|||
{ |
|||
type = ImageType.Invalid; |
|||
} |
|||
else |
|||
{ |
|||
type = (ImageType)fileHead; |
|||
} |
|||
} |
|||
catch (Exception ex) |
|||
{ |
|||
type = ImageType.Invalid; |
|||
Console.WriteLine($"获取图片类型失败 {ex.Message}"); |
|||
} |
|||
return type; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 清楚缓存
|
|||
/// </summary>
|
|||
/// <param name="cacheKey">缓存Key,格式: CacheGroup_UrlSource</param>
|
|||
public static void ClearCache(string cacheKey = "") |
|||
{ |
|||
if (string.IsNullOrEmpty(cacheKey)) |
|||
{ |
|||
ImageCacheList.Clear(); |
|||
GifImageCacheList.Clear(); |
|||
return; |
|||
} |
|||
|
|||
ImageCacheList.Remove(cacheKey, out _); |
|||
GifImageCacheList.Remove(cacheKey, out _); |
|||
} |
|||
|
|||
public static ImageSource GetImageCache(string cacheKey) |
|||
{ |
|||
if (ImageCacheList.ContainsKey(cacheKey)) |
|||
return ImageCacheList[cacheKey]; |
|||
return null; |
|||
} |
|||
#endregion
|
|||
} |
|||
|
|||
|
|||
public enum PathType |
|||
{ |
|||
Invalid = 0, Local = 1, Http = 2, Resources = 3 |
|||
} |
|||
|
|||
public enum ImageType |
|||
{ |
|||
Invalid = 0, Gif = 7173, Jpg = 255216, Png = 13780, Bmp = 6677 |
|||
} |
|||
|
|||
public class QLAsyncImageLoadCompleteEventArgs : RoutedEventArgs |
|||
{ |
|||
public QLAsyncImageLoadCompleteEventArgs(RoutedEvent routedEvent, object source) : base(routedEvent, source) { } |
|||
|
|||
public bool IsSuccess { get; set; } |
|||
|
|||
public string UrlSource { get; set; } |
|||
|
|||
public string ErrorMessage { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// 当加载静态图时的实际像素宽度
|
|||
/// </summary>
|
|||
public double StaticImageActualPixelWidth { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// 当加载静态图时的实际像素高度
|
|||
/// </summary>
|
|||
public double StaticImageActualPixelHeight { get; set; } |
|||
} |
|||
} |
@ -0,0 +1,72 @@ |
|||
using System.Windows; |
|||
using System.Windows.Controls; |
|||
using System.Windows.Media; |
|||
|
|||
namespace SJ.Controls |
|||
{ |
|||
[StyleTypedProperty(Property = "Style", StyleTargetType = typeof(BButton))] |
|||
public class BButton : Button |
|||
{ |
|||
static BButton() |
|||
{ |
|||
DefaultStyleKeyProperty.OverrideMetadata(typeof(BButton), new FrameworkPropertyMetadata(typeof(BButton))); |
|||
} |
|||
|
|||
public static readonly DependencyProperty BorderCornerRadiusProperty = DependencyProperty.Register("BorderCornerRadius", typeof(CornerRadius), typeof(BButton)); |
|||
public static readonly DependencyProperty MouseOverBgColorProperty = DependencyProperty.Register("MouseOverBgColor", typeof(Brush), typeof(BButton)); |
|||
public static readonly DependencyProperty MouseOverFontColorProperty = DependencyProperty.Register("MouseOverFontColor", typeof(Brush), typeof(BButton)); |
|||
public static readonly DependencyProperty PressedBgColorProperty = DependencyProperty.Register("PressedBgColor", typeof(Brush), typeof(BButton)); |
|||
public static readonly DependencyProperty PressedFontColorProperty = DependencyProperty.Register("PressedFontColor", typeof(Brush), typeof(BButton)); |
|||
public static readonly DependencyProperty DisableBgColorProperty = DependencyProperty.Register("DisableBgColor", typeof(Brush), typeof(BButton)); |
|||
public static readonly DependencyProperty DisableTextProperty = DependencyProperty.Register("DisableText", typeof(string), typeof(BButton)); |
|||
public static readonly DependencyProperty PressedScaleProperty = DependencyProperty.Register("PressedScale", typeof(bool), typeof(BButton), new PropertyMetadata(true)); |
|||
|
|||
public CornerRadius BorderCornerRadius |
|||
{ |
|||
get { return (CornerRadius)GetValue(BorderCornerRadiusProperty); } |
|||
set { SetValue(BorderCornerRadiusProperty, value); } |
|||
} |
|||
|
|||
public Brush MouseOverBgColor |
|||
{ |
|||
get { return GetValue(MouseOverBgColorProperty) as Brush; } |
|||
set { SetValue(MouseOverBgColorProperty, value); } |
|||
} |
|||
|
|||
public Brush MouseOverFontColor |
|||
{ |
|||
get { return GetValue(MouseOverFontColorProperty) as Brush; } |
|||
set { SetValue(MouseOverFontColorProperty, value); } |
|||
} |
|||
|
|||
public Brush PressedBgColor |
|||
{ |
|||
get { return GetValue(PressedBgColorProperty) as Brush; } |
|||
set { SetValue(PressedBgColorProperty, value); } |
|||
} |
|||
|
|||
public Brush PressedFontColor |
|||
{ |
|||
get { return GetValue(PressedFontColorProperty) as Brush; } |
|||
set { SetValue(PressedFontColorProperty, value); } |
|||
} |
|||
|
|||
public Brush DisableBgColor |
|||
{ |
|||
get { return GetValue(DisableBgColorProperty) as System.Windows.Media.Brush; } |
|||
set { SetValue(DisableBgColorProperty, value); } |
|||
} |
|||
|
|||
public string DisableText |
|||
{ |
|||
get { return GetValue(DisableTextProperty).ToString(); } |
|||
set { SetValue(DisableTextProperty, value); } |
|||
} |
|||
|
|||
public bool PressedScale |
|||
{ |
|||
get { return (bool)GetValue(PressedScaleProperty); } |
|||
set { SetValue(PressedScaleProperty, value); } |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,210 @@ |
|||
using System.Text; |
|||
using System.Text.RegularExpressions; |
|||
using System.Windows; |
|||
using System.Windows.Controls; |
|||
using System.Windows.Input; |
|||
using System.Windows.Media; |
|||
|
|||
namespace SJ.Controls |
|||
{ |
|||
[StyleTypedProperty(Property = "Style", StyleTargetType = typeof(BTextBox))] |
|||
public class BTextBox : TextBox |
|||
{ |
|||
#region Property
|
|||
|
|||
private bool IsResponseChange; |
|||
private StringBuilder PasswordBuilder; |
|||
private int lastOffset; |
|||
|
|||
#endregion
|
|||
|
|||
#region DependencyProperty
|
|||
|
|||
public static readonly DependencyProperty WaterRemarkProperty = DependencyProperty.Register("WaterRemark", typeof(string), typeof(BTextBox)); |
|||
public static readonly DependencyProperty WaterRemarkFontColorProperty = DependencyProperty.Register("WaterRemarkFontColor", typeof(Brush), typeof(BTextBox)); |
|||
public static readonly DependencyProperty BorderCornerRadiusProperty = DependencyProperty.Register("BorderCornerRadius", typeof(CornerRadius), typeof(BTextBox)); |
|||
public static readonly DependencyProperty IsPasswordBoxProperty = DependencyProperty.Register("IsPasswordBox", typeof(bool), typeof(BTextBox), new FrameworkPropertyMetadata(false, new PropertyChangedCallback(OnIsPasswordBoxChnage))); |
|||
public static readonly DependencyProperty IsNumberBoxProperty = DependencyProperty.Register("IsNumberBox", typeof(bool), typeof(BTextBox), new PropertyMetadata(false, new PropertyChangedCallback(OnIsNumberBoxChnage))); |
|||
public static readonly DependencyProperty DisableBgColorProperty = DependencyProperty.Register("DisableBgColor", typeof(Brush), typeof(BTextBox)); |
|||
public static readonly DependencyProperty PasswordCharProperty = DependencyProperty.Register("PasswordChar", typeof(char), typeof(BTextBox), new FrameworkPropertyMetadata('●')); |
|||
public static readonly DependencyProperty PasswordStrProperty = DependencyProperty.Register("PasswordStr", typeof(string), typeof(BTextBox), new FrameworkPropertyMetadata(string.Empty, new PropertyChangedCallback(OnPasswordStrChanged))); |
|||
|
|||
/// <summary>
|
|||
/// 水印文字
|
|||
/// </summary>
|
|||
public string WaterRemark |
|||
{ |
|||
get { return GetValue(WaterRemarkProperty).ToString(); } |
|||
set { SetValue(WaterRemarkProperty, value); } |
|||
} |
|||
|
|||
public Brush WaterRemarkFontColor |
|||
{ |
|||
get { return GetValue(WaterRemarkFontColorProperty) as Brush; } |
|||
set { SetValue(WaterRemarkFontColorProperty, value); } |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 边框角度
|
|||
/// </summary>
|
|||
public CornerRadius BorderCornerRadius |
|||
{ |
|||
get { return (CornerRadius)GetValue(BorderCornerRadiusProperty); } |
|||
set { SetValue(BorderCornerRadiusProperty, value); } |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 是否为密码框
|
|||
/// </summary>
|
|||
public bool IsPasswordBox |
|||
{ |
|||
get { return (bool)GetValue(IsPasswordBoxProperty); } |
|||
set { SetValue(IsPasswordBoxProperty, value); } |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 是否为数字框
|
|||
/// </summary>
|
|||
public bool IsNumberBox |
|||
{ |
|||
get { return (bool)GetValue(IsNumberBoxProperty); } |
|||
set { SetValue(IsNumberBoxProperty, value); } |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 替换明文的密码字符
|
|||
/// </summary>
|
|||
public char PasswordChar |
|||
{ |
|||
get { return (char)GetValue(PasswordCharProperty); } |
|||
set { SetValue(PasswordCharProperty, value); } |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 密码字符串
|
|||
/// </summary>
|
|||
public string PasswordStr |
|||
{ |
|||
get |
|||
{ |
|||
var value = GetValue(PasswordStrProperty); |
|||
return value == null ? string.Empty : value.ToString(); |
|||
} |
|||
set { SetValue(PasswordStrProperty, value); } |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 按钮被禁用时的背景颜色
|
|||
/// </summary>
|
|||
public Brush DisableBgColor |
|||
{ |
|||
get { return GetValue(DisableBgColorProperty) as Brush; } |
|||
set { SetValue(DisableBgColorProperty, value); } |
|||
} |
|||
#endregion
|
|||
|
|||
|
|||
static BTextBox() |
|||
{ |
|||
DefaultStyleKeyProperty.OverrideMetadata(typeof(BTextBox), new FrameworkPropertyMetadata(typeof(BTextBox))); |
|||
} |
|||
|
|||
public BTextBox() |
|||
{ |
|||
IsResponseChange = true; |
|||
PasswordBuilder = new StringBuilder(); |
|||
this.Loaded += QLTextBox_Loaded; |
|||
} |
|||
|
|||
private void QLTextBox_Loaded(object sender, RoutedEventArgs e) |
|||
{ |
|||
if (IsPasswordBox && !string.IsNullOrEmpty(PasswordStr) && PasswordStr.Length > 0) |
|||
{ |
|||
OnPasswordStrChanged(); |
|||
} |
|||
} |
|||
|
|||
private static void OnPasswordStrChanged(DependencyObject d, DependencyPropertyChangedEventArgs args) |
|||
{ |
|||
(d as BTextBox).OnPasswordStrChanged(); |
|||
} |
|||
|
|||
private void OnPasswordStrChanged() |
|||
{ |
|||
if (!IsResponseChange) |
|||
return; |
|||
IsResponseChange = false; |
|||
this.Text = ConvertToPasswordChar(PasswordStr.Length); |
|||
IsResponseChange = true; |
|||
} |
|||
|
|||
private static void OnIsPasswordBoxChnage(DependencyObject sender, DependencyPropertyChangedEventArgs e) |
|||
{ |
|||
(sender as BTextBox).SetPwdEvent(); |
|||
} |
|||
|
|||
private static void OnIsNumberBoxChnage(DependencyObject sender, DependencyPropertyChangedEventArgs e) |
|||
{ |
|||
(sender as BTextBox).SetValidationNumberEvent(); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 定义TextChange事件
|
|||
/// </summary>
|
|||
private void SetPwdEvent() |
|||
{ |
|||
if (IsPasswordBox) |
|||
this.TextChanged += QLTextBox_TextChanged; |
|||
else |
|||
this.TextChanged -= QLTextBox_TextChanged; |
|||
} |
|||
|
|||
private void SetValidationNumberEvent() |
|||
{ |
|||
if (IsNumberBox) |
|||
this.PreviewTextInput += QLTextBox_PreviewTextInput; |
|||
else |
|||
this.PreviewTextInput -= QLTextBox_PreviewTextInput; |
|||
} |
|||
|
|||
private void QLTextBox_TextChanged(object sender, TextChangedEventArgs e) |
|||
{ |
|||
if (!IsResponseChange) |
|||
return; |
|||
IsResponseChange = false; |
|||
foreach (TextChange c in e.Changes) |
|||
{ |
|||
PasswordStr = PasswordStr.Remove(c.Offset, c.RemovedLength); |
|||
PasswordStr = PasswordStr.Insert(c.Offset, Text.Substring(c.Offset, c.AddedLength)); |
|||
lastOffset = c.Offset; |
|||
} |
|||
/*将文本转换为密码字符*/ |
|||
this.Text = ConvertToPasswordChar(Text.Length); |
|||
IsResponseChange = true; |
|||
this.SelectionStart = lastOffset + 1; |
|||
} |
|||
|
|||
private void QLTextBox_PreviewTextInput(object sender, TextCompositionEventArgs e) |
|||
{ |
|||
Regex re = new Regex("[^0-9.]+"); |
|||
e.Handled = re.IsMatch(e.Text); |
|||
} |
|||
|
|||
|
|||
/// <summary>
|
|||
/// 按照指定的长度生成密码字符
|
|||
/// </summary>
|
|||
/// <param name="length"></param>
|
|||
/// <returns></returns>
|
|||
private string ConvertToPasswordChar(int length) |
|||
{ |
|||
if (PasswordBuilder != null) |
|||
PasswordBuilder.Clear(); |
|||
else |
|||
PasswordBuilder = new StringBuilder(); |
|||
for (var i = 0; i < length; i++) |
|||
PasswordBuilder.Append(PasswordChar); |
|||
return PasswordBuilder.ToString(); |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,109 @@ |
|||
using System; |
|||
using System.Windows; |
|||
using System.Windows.Controls; |
|||
using System.Windows.Media; |
|||
using System.Windows.Media.Animation; |
|||
|
|||
namespace SJ.Controls |
|||
{ |
|||
[StyleTypedProperty(Property = "Style", StyleTargetType = typeof(BTextBoxAnimation))] |
|||
public class BTextBoxAnimation : BTextBox |
|||
{ |
|||
public static readonly DependencyProperty WaterRemarkTopStateColorProperty = DependencyProperty.Register("WaterRemarkTopStateColor", typeof(Brush), typeof(BTextBoxAnimation)); |
|||
public static readonly DependencyProperty WaterRemarkStateProperty = DependencyProperty.Register("WaterRemarkState", typeof(WaterRemarkState), typeof(BTextBoxAnimation), new PropertyMetadata(WaterRemarkState.Normal, new PropertyChangedCallback((d, e) => |
|||
{ |
|||
if (e.OldValue != e.NewValue) |
|||
{ |
|||
(d as BTextBoxAnimation).PlayWaterRemarkAnimation(); |
|||
} |
|||
}))); |
|||
|
|||
private TextBlock txtRemark; |
|||
private TimeSpan animationTimeSpan = new TimeSpan(0, 0, 0, 0, 200); |
|||
private IEasingFunction animationEasingFunction = new PowerEase() { EasingMode = EasingMode.EaseInOut }; |
|||
|
|||
|
|||
public Brush WaterRemarkTopStateColor |
|||
{ |
|||
get { return GetValue(WaterRemarkTopStateColorProperty) as Brush; } |
|||
set { SetValue(WaterRemarkTopStateColorProperty, value); } |
|||
} |
|||
|
|||
public WaterRemarkState WaterRemarkState |
|||
{ |
|||
get { return (WaterRemarkState)Convert.ToInt32(GetValue(WaterRemarkStateProperty)); } |
|||
set { SetValue(WaterRemarkStateProperty, value); } |
|||
} |
|||
|
|||
|
|||
static BTextBoxAnimation() |
|||
{ |
|||
DefaultStyleKeyProperty.OverrideMetadata(typeof(BTextBoxAnimation), new FrameworkPropertyMetadata(typeof(BTextBoxAnimation))); |
|||
} |
|||
public BTextBoxAnimation() |
|||
{ |
|||
this.Loaded += QLTextBoxAnimation_Loaded; |
|||
} |
|||
|
|||
public override void OnApplyTemplate() |
|||
{ |
|||
txtRemark = GetTemplateChild("txtRemark") as TextBlock; |
|||
base.OnApplyTemplate(); |
|||
} |
|||
|
|||
private void QLTextBoxAnimation_Loaded(object sender, RoutedEventArgs e) |
|||
{ |
|||
if (!string.IsNullOrEmpty(Text)) |
|||
WaterRemarkState = WaterRemarkState.Top; |
|||
} |
|||
|
|||
protected override void OnTextChanged(TextChangedEventArgs e) |
|||
{ |
|||
base.OnTextChanged(e); |
|||
if (!this.IsLoaded) |
|||
return; |
|||
if (string.IsNullOrEmpty(Text)) |
|||
WaterRemarkState = WaterRemarkState.Normal; |
|||
else |
|||
WaterRemarkState = WaterRemarkState.Top; |
|||
} |
|||
|
|||
protected override void OnGotFocus(RoutedEventArgs e) |
|||
{ |
|||
base.OnGotFocus(e); |
|||
WaterRemarkState = WaterRemarkState.Top; |
|||
} |
|||
|
|||
protected override void OnLostFocus(RoutedEventArgs e) |
|||
{ |
|||
base.OnLostFocus(e); |
|||
if (string.IsNullOrEmpty(Text)) |
|||
WaterRemarkState = WaterRemarkState.Normal; |
|||
} |
|||
|
|||
private void PlayWaterRemarkAnimation() |
|||
{ |
|||
var fontsize = WaterRemarkState == WaterRemarkState.Normal ? FontSize : 10.5; |
|||
var row = WaterRemarkState == WaterRemarkState.Normal ? 1 : 0; |
|||
|
|||
var storyboard = new Storyboard(); |
|||
var daukf_Remark_FontSize = new DoubleAnimationUsingKeyFrames(); |
|||
daukf_Remark_FontSize.KeyFrames.Add(new EasingDoubleKeyFrame(fontsize, animationTimeSpan, animationEasingFunction)); |
|||
Storyboard.SetTargetProperty(daukf_Remark_FontSize, new PropertyPath("(TextBlock.FontSize)")); |
|||
Storyboard.SetTarget(daukf_Remark_FontSize, txtRemark); |
|||
storyboard.Children.Add(daukf_Remark_FontSize); |
|||
|
|||
var i32aukf_Remark_Row = new Int32AnimationUsingKeyFrames(); |
|||
i32aukf_Remark_Row.KeyFrames.Add(new EasingInt32KeyFrame(row, animationTimeSpan, animationEasingFunction)); |
|||
Storyboard.SetTargetProperty(i32aukf_Remark_Row, new PropertyPath("(Grid.Row)")); |
|||
Storyboard.SetTarget(i32aukf_Remark_Row, txtRemark); |
|||
storyboard.Children.Add(i32aukf_Remark_Row); |
|||
storyboard.Begin(); |
|||
} |
|||
} |
|||
|
|||
public enum WaterRemarkState |
|||
{ |
|||
Normal, Top |
|||
} |
|||
} |
@ -0,0 +1,178 @@ |
|||
using System.ComponentModel; |
|||
using System.Reflection; |
|||
using System.Runtime.CompilerServices; |
|||
using System.Windows; |
|||
using System.Windows.Controls; |
|||
using System.Windows.Input; |
|||
using System.Windows.Media; |
|||
using System.Windows.Shell; |
|||
|
|||
namespace SJ.Controls |
|||
{ |
|||
[StyleTypedProperty(Property = "Style", StyleTargetType = typeof(BWindow))] |
|||
public class BWindow : Window, INotifyPropertyChanged |
|||
{ |
|||
public static readonly DependencyProperty CornerRadiusProperty = |
|||
DependencyProperty.Register("CornerRadius", typeof(CornerRadius), typeof(BWindow), new PropertyMetadata(new CornerRadius(0))); |
|||
|
|||
public static readonly DependencyProperty RightButtonGroupMarginProperty = |
|||
DependencyProperty.Register("RightButtonGroupMargin", typeof(Thickness), typeof(BWindow), new PropertyMetadata(new Thickness(0, 16, 16, 0))); |
|||
|
|||
public static readonly DependencyProperty CloseButtonVisibilityProperty = |
|||
DependencyProperty.Register("CloseButtonVisibility", typeof(Visibility), typeof(BWindow), new PropertyMetadata(Visibility.Visible)); |
|||
|
|||
public static readonly DependencyProperty MinButtonVisibilityProperty = |
|||
DependencyProperty.Register("MinButtonVisibility", typeof(Visibility), typeof(BWindow), new PropertyMetadata(Visibility.Visible)); |
|||
|
|||
public static readonly DependencyProperty MaxButtonVisibilityProperty = |
|||
DependencyProperty.Register("MaxButtonVisibility", typeof(Visibility), typeof(BWindow), new PropertyMetadata(Visibility.Visible)); |
|||
|
|||
public static readonly DependencyProperty CloseButtonColorProperty = |
|||
DependencyProperty.Register("CloseButtonColor", typeof(Brush), typeof(BWindow), new PropertyMetadata(new SolidColorBrush(Colors.White))); |
|||
|
|||
public static readonly DependencyProperty MinButtonColorProperty = |
|||
DependencyProperty.Register("MinButtonColor", typeof(Brush), typeof(BWindow), new PropertyMetadata(new SolidColorBrush(Colors.White))); |
|||
|
|||
public static readonly DependencyProperty MaxButtonColorProperty = |
|||
DependencyProperty.Register("MaxButtonColor", typeof(Brush), typeof(BWindow), new PropertyMetadata(new SolidColorBrush(Colors.White))); |
|||
|
|||
public CornerRadius CornerRadius |
|||
{ |
|||
get { return (CornerRadius)GetValue(CornerRadiusProperty); } |
|||
set { SetValue(CornerRadiusProperty, value); } |
|||
} |
|||
|
|||
public Thickness RightButtonGroupMargin |
|||
{ |
|||
get { return (Thickness)GetValue(RightButtonGroupMarginProperty); } |
|||
set { SetValue(RightButtonGroupMarginProperty, value); } |
|||
} |
|||
|
|||
public Visibility CloseButtonVisibility |
|||
{ |
|||
get { return (Visibility)GetValue(CloseButtonVisibilityProperty); } |
|||
set { SetValue(CloseButtonVisibilityProperty, value); } |
|||
} |
|||
|
|||
public Visibility MinButtonVisibility |
|||
{ |
|||
get { return (Visibility)GetValue(MinButtonVisibilityProperty); } |
|||
set { SetValue(MinButtonVisibilityProperty, value); } |
|||
} |
|||
|
|||
public Visibility MaxButtonVisibility |
|||
{ |
|||
get { return (Visibility)GetValue(MaxButtonVisibilityProperty); } |
|||
set { SetValue(MaxButtonVisibilityProperty, value); } |
|||
} |
|||
|
|||
public Brush CloseButtonColor |
|||
{ |
|||
get { return (Brush)GetValue(CloseButtonColorProperty); } |
|||
set { SetValue(CloseButtonColorProperty, value); } |
|||
} |
|||
|
|||
public Brush MinButtonColor |
|||
{ |
|||
get { return (Brush)GetValue(MinButtonColorProperty); } |
|||
set { SetValue(MinButtonColorProperty, value); } |
|||
} |
|||
|
|||
public Brush MaxButtonColor |
|||
{ |
|||
get { return (Brush)GetValue(MaxButtonColorProperty); } |
|||
set { SetValue(MaxButtonColorProperty, value); } |
|||
} |
|||
|
|||
static BWindow() |
|||
{ |
|||
DefaultStyleKeyProperty.OverrideMetadata(typeof(BWindow), new FrameworkPropertyMetadata(typeof(BWindow))); |
|||
} |
|||
|
|||
public BWindow() |
|||
{ |
|||
WindowStartupLocation = WindowStartupLocation.CenterScreen; |
|||
var chrome = new WindowChrome |
|||
{ |
|||
CornerRadius = new CornerRadius(), |
|||
GlassFrameThickness = new Thickness(1), |
|||
UseAeroCaptionButtons = false, |
|||
NonClientFrameEdges = NonClientFrameEdges.None, |
|||
ResizeBorderThickness = new Thickness(2), |
|||
CaptionHeight = 30 |
|||
}; |
|||
WindowChrome.SetWindowChrome(this, chrome); |
|||
} |
|||
|
|||
public override void OnApplyTemplate() |
|||
{ |
|||
Button PART_MIN = null; |
|||
Button PART_MAX = null; |
|||
Button PART_RESTORE = null; |
|||
Button PART_CLOSE = null; |
|||
|
|||
PART_MIN = GetTemplateChild("PART_MIN") as Button; |
|||
PART_MAX = GetTemplateChild("PART_MAX") as Button; |
|||
PART_RESTORE = GetTemplateChild("PART_RESTORE") as Button; |
|||
PART_CLOSE = GetTemplateChild("PART_CLOSE") as Button; |
|||
|
|||
if (PART_RESTORE != null) |
|||
PART_RESTORE.Click += PART_RESTORE_Click; |
|||
if (PART_MAX != null) |
|||
PART_MAX.Click += PART_MAX_Click; |
|||
if (PART_MIN != null) |
|||
PART_MIN.Click += PART_MIN_Click; |
|||
if (PART_CLOSE != null) |
|||
PART_CLOSE.Click += PART_CLOSE_Click; |
|||
|
|||
base.OnApplyTemplate(); |
|||
} |
|||
|
|||
private void PART_CLOSE_Click(object sender, RoutedEventArgs e) |
|||
{ |
|||
this.Close(); |
|||
} |
|||
|
|||
private void PART_MIN_Click(object sender, RoutedEventArgs e) |
|||
{ |
|||
WindowState = WindowState.Minimized; |
|||
} |
|||
|
|||
private void PART_MAX_Click(object sender, RoutedEventArgs e) |
|||
{ |
|||
WindowState = WindowState.Maximized; |
|||
} |
|||
|
|||
private void PART_RESTORE_Click(object sender, RoutedEventArgs e) |
|||
{ |
|||
WindowState = WindowState.Normal; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 判断是否为模态窗口
|
|||
/// </summary>
|
|||
/// <returns></returns>
|
|||
public bool IsModal() |
|||
{ |
|||
var filedInfo = typeof(Window).GetField("_showingAsDialog", BindingFlags.Instance | BindingFlags.NonPublic); |
|||
return filedInfo != null && (bool)filedInfo.GetValue(this); |
|||
} |
|||
|
|||
|
|||
#region PropertyNotify
|
|||
public event PropertyChangedEventHandler PropertyChanged; |
|||
protected void OnPropertyChanged([CallerMemberName] string propertyName = "") |
|||
{ |
|||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); |
|||
} |
|||
protected bool Set<T>(ref T oldValue, T newValue, [CallerMemberName] string propertyName = "") |
|||
{ |
|||
if (Equals(oldValue, newValue)) |
|||
return false; |
|||
oldValue = newValue; |
|||
OnPropertyChanged(propertyName); |
|||
return true; |
|||
} |
|||
#endregion
|
|||
} |
|||
} |
@ -0,0 +1,71 @@ |
|||
using System.Collections.Generic; |
|||
using System.Windows; |
|||
using System.Windows.Input; |
|||
using System.Windows.Media; |
|||
|
|||
namespace SJ.Controls.Extensions |
|||
{ |
|||
public static class VisualTreeExtension |
|||
{ |
|||
public static T HitTest<T>(this FrameworkElement fe, Point? point) where T : FrameworkElement |
|||
{ |
|||
if (point == null) |
|||
point = Mouse.GetPosition(fe); |
|||
var result = VisualTreeHelper.HitTest(fe, point.Value); |
|||
if (result == null) |
|||
return null; |
|||
if (result.VisualHit != null) |
|||
{ |
|||
var r = FindParentOfType<T>(result.VisualHit); |
|||
return r; |
|||
} |
|||
return null; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 查找父控件
|
|||
/// </summary>
|
|||
/// <typeparam name="T">父控件类型</typeparam>
|
|||
/// <param name="obj">子控件实例</param>
|
|||
/// <returns></returns>
|
|||
public static T FindParentOfType<T>(this DependencyObject obj) where T : FrameworkElement |
|||
{ |
|||
DependencyObject parent = VisualTreeHelper.GetParent(obj); |
|||
while (parent != null) |
|||
{ |
|||
if (parent is T) |
|||
{ |
|||
return (T)parent; |
|||
} |
|||
parent = VisualTreeHelper.GetParent(parent); |
|||
} |
|||
return null; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 查找子控件
|
|||
/// </summary>
|
|||
/// <typeparam name="T">需要查找的控件类型</typeparam>
|
|||
/// <param name="obj">父控件实例</param>
|
|||
/// <returns></returns>
|
|||
public static T FindFirstVisualChild<T>(this DependencyObject obj) where T : FrameworkElement |
|||
{ |
|||
var queue = new Queue<DependencyObject>(); |
|||
queue.Enqueue(obj); |
|||
while (queue.Count > 0) |
|||
{ |
|||
DependencyObject current = queue.Dequeue(); |
|||
for (int i = VisualTreeHelper.GetChildrenCount(current) - 1; 0 <= i; i--) |
|||
{ |
|||
DependencyObject child = VisualTreeHelper.GetChild(current, i); |
|||
if (child != null && child is T) |
|||
{ |
|||
return (T)child; |
|||
} |
|||
queue.Enqueue(child); |
|||
} |
|||
} |
|||
return null; |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,188 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Windows; |
|||
using System.Windows.Media.Animation; |
|||
|
|||
namespace SJ.Controls.Helpers |
|||
{ |
|||
public class StoryboardHelper |
|||
{ |
|||
/// <summary>
|
|||
/// 播放动画
|
|||
/// </summary>
|
|||
/// <param name="fe">控件源</param>
|
|||
/// <param name="from">开始值</param>
|
|||
/// <param name="to">结束值</param>
|
|||
/// <param name="duration">时间间隔</param>
|
|||
/// <param name="IsAutoReverse">是否反向播放</param>
|
|||
/// <param name="RepeatPlay">是否重复播放</param>
|
|||
/// <param name="ef">动画类型</param>
|
|||
/// <param name="Callback">回调函数</param>
|
|||
/// <param name="PropertyPath">动画属性</param>
|
|||
public static void _PlayDoubleAnimation(FrameworkElement fe, double from, double to, TimeSpan duration, bool IsAutoReverse, bool RepeatPlay, IEasingFunction ef, Action Callback, string PropertyPath) |
|||
{ |
|||
Storyboard _sb = new Storyboard(); |
|||
_sb.Completed += new EventHandler((s, e) => |
|||
{ |
|||
if (Callback != null) |
|||
Callback(); |
|||
_sb.Stop(); |
|||
_sb.Children.Clear(); |
|||
_sb = null; |
|||
}); |
|||
DoubleAnimation daRotation = new DoubleAnimation(); |
|||
daRotation.From = from; |
|||
daRotation.To = to; |
|||
daRotation.EasingFunction = ef; |
|||
daRotation.Duration = duration; |
|||
Storyboard.SetTargetProperty(daRotation, new PropertyPath(PropertyPath)); |
|||
Storyboard.SetTarget(daRotation, fe); |
|||
_sb.Children.Add(daRotation); |
|||
_sb.AutoReverse = IsAutoReverse; |
|||
if (RepeatPlay) |
|||
_sb.RepeatBehavior = RepeatBehavior.Forever; |
|||
_sb.Begin(); |
|||
} |
|||
|
|||
public static void _PlayAnimationUsingKeyFrames(IList<AnimationModel> AnimationUsingKeyFrameList, bool IsAutoReverse, bool IsRepeayPlay, Action Callback) |
|||
{ |
|||
if (AnimationUsingKeyFrameList == null || AnimationUsingKeyFrameList.Count == 0) |
|||
return; |
|||
Storyboard _sb = new Storyboard(); |
|||
_sb.Completed += new EventHandler((s, e) => |
|||
{ |
|||
if (Callback != null) |
|||
Callback(); |
|||
_sb.Stop(); |
|||
_sb.Children.Clear(); |
|||
_sb = null; |
|||
}); |
|||
_sb.AutoReverse = IsAutoReverse; |
|||
if (IsRepeayPlay) |
|||
_sb.RepeatBehavior = RepeatBehavior.Forever; |
|||
foreach (AnimationModel am in AnimationUsingKeyFrameList) |
|||
{ |
|||
AnimationTimeline animationTimeLine = null; |
|||
switch (am._KeyFrameType) |
|||
{ |
|||
case KeyFrameType.DoubleKeyFrame: |
|||
animationTimeLine = CreateDoubleAnimationUsingKeyFrames(am); |
|||
break; |
|||
case KeyFrameType.ColorKeyFrame: |
|||
animationTimeLine = CreateColorAnimationUsingKeyFrames(am); |
|||
break; |
|||
case KeyFrameType.ObjectKeyFrame: |
|||
animationTimeLine = CreateObjectAnimationUsingKeyFrames(am); |
|||
break; |
|||
} |
|||
_sb.Children.Add(animationTimeLine); |
|||
} |
|||
_sb.Begin(); |
|||
} |
|||
|
|||
private static AnimationTimeline CreateDoubleAnimationUsingKeyFrames(AnimationModel am) |
|||
{ |
|||
DoubleAnimationUsingKeyFrames animationTimeline = new DoubleAnimationUsingKeyFrames(); |
|||
Storyboard.SetTargetProperty(animationTimeline, new PropertyPath(am.PropertyPath)); |
|||
Storyboard.SetTarget(animationTimeline, am.Element); |
|||
foreach (BaseKeyFrame baseKeyFrame in am.KeyFrames) |
|||
{ |
|||
animationTimeline.KeyFrames.Add( |
|||
new EasingDoubleKeyFrame( |
|||
Convert.ToInt32(baseKeyFrame.Value), |
|||
baseKeyFrame._KeyTime, |
|||
baseKeyFrame.EasingFunction) |
|||
); |
|||
} |
|||
return animationTimeline; |
|||
} |
|||
|
|||
private static AnimationTimeline CreateColorAnimationUsingKeyFrames(AnimationModel am) |
|||
{ |
|||
ColorAnimationUsingKeyFrames animationTimeline = new ColorAnimationUsingKeyFrames(); |
|||
Storyboard.SetTargetProperty(animationTimeline, new PropertyPath(am.PropertyPath)); |
|||
Storyboard.SetTarget(animationTimeline, am.Element); |
|||
foreach (BaseKeyFrame baseKeyFrame in am.KeyFrames) |
|||
{ |
|||
animationTimeline.KeyFrames.Add( |
|||
new EasingColorKeyFrame( |
|||
(System.Windows.Media.Color)baseKeyFrame.Value, |
|||
baseKeyFrame._KeyTime, |
|||
baseKeyFrame.EasingFunction) |
|||
); |
|||
} |
|||
return animationTimeline; |
|||
} |
|||
|
|||
private static AnimationTimeline CreateObjectAnimationUsingKeyFrames(AnimationModel am) |
|||
{ |
|||
ObjectAnimationUsingKeyFrames animationTimeline = new ObjectAnimationUsingKeyFrames(); |
|||
Storyboard.SetTargetProperty(animationTimeline, new PropertyPath(am.PropertyPath)); |
|||
Storyboard.SetTarget(animationTimeline, am.Element); |
|||
foreach (BaseKeyFrame baseKeyFrame in am.KeyFrames) |
|||
{ |
|||
animationTimeline.KeyFrames.Add( |
|||
new DiscreteObjectKeyFrame( |
|||
baseKeyFrame.Value, |
|||
baseKeyFrame._KeyTime) |
|||
); |
|||
} |
|||
return animationTimeline; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 关键帧动画类型
|
|||
/// </summary>
|
|||
public enum KeyFrameType |
|||
{ |
|||
DoubleKeyFrame = 1, |
|||
ColorKeyFrame = 2, |
|||
ObjectKeyFrame = 3 |
|||
} |
|||
|
|||
public class AnimationModel |
|||
{ |
|||
public AnimationModel() |
|||
{ |
|||
this.KeyFrames = new List<BaseKeyFrame>(); |
|||
} |
|||
/// <summary>
|
|||
/// 执行动画的对象
|
|||
/// </summary>
|
|||
public FrameworkElement Element; |
|||
|
|||
/// <summary>
|
|||
/// 作用于动画的属性
|
|||
/// </summary>
|
|||
public string PropertyPath; |
|||
|
|||
/// <summary>
|
|||
/// 动画类型枚举
|
|||
/// </summary>
|
|||
public KeyFrameType _KeyFrameType; |
|||
|
|||
/// <summary>
|
|||
/// 关键帧动画帧集合
|
|||
/// </summary>
|
|||
public IList<BaseKeyFrame> KeyFrames; |
|||
} |
|||
|
|||
public class BaseKeyFrame |
|||
{ |
|||
/// <summary>
|
|||
/// 动画触发时间
|
|||
/// </summary>
|
|||
public TimeSpan _KeyTime; |
|||
|
|||
/// <summary>
|
|||
/// 值
|
|||
/// </summary>
|
|||
public object Value; |
|||
|
|||
/// <summary>
|
|||
/// 缓动函数类型
|
|||
/// </summary>
|
|||
public IEasingFunction EasingFunction; |
|||
} |
|||
} |
@ -0,0 +1,24 @@ |
|||
<UserControl x:Class="SJ.Controls.PageControl" |
|||
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" |
|||
xmlns:c="clr-namespace:SJ.Controls" |
|||
mc:Ignorable="d" |
|||
d:DesignHeight="30" d:DesignWidth="500"> |
|||
<StackPanel Orientation="Horizontal" VerticalAlignment="Center"> |
|||
<TextBlock Text="{Binding PageSize,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type c:PageControl}},StringFormat=每页\{0\}条}" VerticalAlignment="Center"/> |
|||
<TextBlock Text="{Binding PageIndex,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type c:PageControl}},StringFormat=当前显示第\{0\}}" VerticalAlignment="Center" Margin="15,0,0,0"/> |
|||
<TextBlock Text="{Binding PageCount,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type c:PageControl}},StringFormat=/\{0\}页}" VerticalAlignment="Center"/> |
|||
<TextBlock Text="{Binding RecordCount,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type c:PageControl}},StringFormat=共\{0\}条记录}" VerticalAlignment="Center" Margin="15,0,0,0"/> |
|||
<c:BButton x:Name="btn_first" Content="首页" Margin="15,0,0,0" VerticalAlignment="Center" Click="btn_first_Click" |
|||
Style="{StaticResource LinkButton}"/> |
|||
<c:BButton x:Name="btn_up" Margin="15,0,0,0" VerticalAlignment="Center" Click="btn_up_Click" Content="上一页" |
|||
Style="{StaticResource LinkButton}"/> |
|||
<!--<StackPanel x:Name="sp_pagenumber" Orientation="Horizontal" VerticalAlignment="Center"/>--> |
|||
<c:BButton x:Name="btn_next" Margin="15,0,0,0" VerticalAlignment="Center" Click="btn_next_Click" Content="下一页" |
|||
Style="{StaticResource LinkButton}"/> |
|||
<c:BButton x:Name="btn_last" Content="尾页" Margin="15,0,0,0" VerticalAlignment="Center" Click="btn_last_Click" |
|||
Style="{StaticResource LinkButton}"/> |
|||
</StackPanel> |
|||
</UserControl> |
@ -0,0 +1,137 @@ |
|||
using System; |
|||
using System.Windows; |
|||
using System.Windows.Controls; |
|||
|
|||
namespace SJ.Controls |
|||
{ |
|||
/// <summary>
|
|||
/// PageControl.xaml 的交互逻辑
|
|||
/// </summary>
|
|||
public partial class PageControl : UserControl |
|||
{ |
|||
public PageControl() |
|||
{ |
|||
InitializeComponent(); |
|||
this.Loaded += PageControl_Loaded; |
|||
} |
|||
|
|||
private void PageControl_Loaded(object sender, RoutedEventArgs e) |
|||
{ |
|||
this.PageIndex = 1; |
|||
pageArgs.PageIndex = this.PageIndex; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 分页事件
|
|||
/// </summary>
|
|||
public event RoutedEventHandler OnPageIndexChanged; |
|||
|
|||
/// <summary>
|
|||
/// 分页参数
|
|||
/// </summary>
|
|||
private PageArgs pageArgs = new PageArgs(); |
|||
|
|||
public static readonly DependencyProperty PageIndexProperty = DependencyProperty.Register("PageIndex", typeof(int), typeof(PageControl), new PropertyMetadata(1, new PropertyChangedCallback((s, e) => |
|||
{ |
|||
var pageControl = s as PageControl; |
|||
pageControl?.OnIndexChanged(); |
|||
}))); |
|||
|
|||
/// <summary>
|
|||
/// 当前页数
|
|||
/// </summary>
|
|||
public int PageIndex |
|||
{ |
|||
get { return (int)GetValue(PageIndexProperty); } |
|||
set { SetValue(PageIndexProperty, value); } |
|||
} |
|||
|
|||
public static readonly DependencyProperty PageSizeProperty = DependencyProperty.Register("PageSize", typeof(int), typeof(PageControl), new PropertyMetadata(1)); |
|||
|
|||
/// <summary>
|
|||
/// 每页记录数
|
|||
/// </summary>
|
|||
public int PageSize |
|||
{ |
|||
get { return (int)GetValue(PageSizeProperty); } |
|||
set { SetValue(PageSizeProperty, value); } |
|||
} |
|||
|
|||
public static readonly DependencyProperty PageCountProperty = DependencyProperty.Register("PageCount", typeof(int), typeof(PageControl), new PropertyMetadata(1)); |
|||
|
|||
/// <summary>
|
|||
/// 总页数
|
|||
/// </summary>
|
|||
public int PageCount |
|||
{ |
|||
get { return (int)GetValue(PageCountProperty); } |
|||
set { SetValue(PageCountProperty, value); } |
|||
} |
|||
|
|||
public static readonly DependencyProperty RecordCountProperty = DependencyProperty.Register("RecordCount", typeof(int), typeof(PageControl), new PropertyMetadata(0, new PropertyChangedCallback((s, e) => |
|||
{ |
|||
var pageControl = s as PageControl; |
|||
pageControl?.OnRecordChanged(); |
|||
}))); |
|||
|
|||
/// <summary>
|
|||
/// 总记录数
|
|||
/// </summary>
|
|||
public int RecordCount |
|||
{ |
|||
get { return (int)GetValue(RecordCountProperty); } |
|||
set { SetValue(RecordCountProperty, value); } |
|||
} |
|||
|
|||
private void OnRecordChanged() |
|||
{ |
|||
PageCount = (RecordCount - 1) / PageSize + 1; |
|||
} |
|||
|
|||
private void OnIndexChanged() |
|||
{ |
|||
pageArgs.PageIndex = this.PageIndex; |
|||
OnPageIndexChanged?.Invoke(this, pageArgs); |
|||
} |
|||
|
|||
private void Btn_Click(object sender, RoutedEventArgs e) |
|||
{ |
|||
var btn = sender as BButton; |
|||
var newPageIndex = Convert.ToInt32(btn.Content); |
|||
if (newPageIndex != PageIndex) |
|||
PageIndex = newPageIndex; |
|||
else |
|||
OnIndexChanged(); |
|||
} |
|||
|
|||
private void btn_first_Click(object sender, RoutedEventArgs e) |
|||
{ |
|||
if (PageIndex > 1) |
|||
PageIndex = 1; |
|||
} |
|||
|
|||
private void btn_up_Click(object sender, RoutedEventArgs e) |
|||
{ |
|||
if (PageIndex > 1) |
|||
PageIndex--; |
|||
} |
|||
|
|||
private void btn_next_Click(object sender, RoutedEventArgs e) |
|||
{ |
|||
if (PageIndex < PageCount) |
|||
PageIndex++; |
|||
} |
|||
|
|||
private void btn_last_Click(object sender, RoutedEventArgs e) |
|||
{ |
|||
if (PageIndex < PageCount) |
|||
PageIndex = PageCount; |
|||
} |
|||
} |
|||
|
|||
public class PageArgs : RoutedEventArgs |
|||
{ |
|||
public int PageIndex; |
|||
//其余自行扩展
|
|||
} |
|||
} |
@ -0,0 +1,56 @@ |
|||
<UserControl x:Class="SJ.Controls.RoundWaitProgress" |
|||
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" |
|||
xmlns:local="clr-namespace:SJ.Controls" |
|||
mc:Ignorable="d" |
|||
d:DesignHeight="300" d:DesignWidth="300"> |
|||
<Grid> |
|||
<Grid VerticalAlignment="Center" HorizontalAlignment="Center"> |
|||
<Grid.RowDefinitions> |
|||
<RowDefinition Height="auto"/> |
|||
<RowDefinition Height="auto"/> |
|||
</Grid.RowDefinitions> |
|||
<Grid Width="{Binding AnimationSize,Mode=OneWay,UpdateSourceTrigger=PropertyChanged,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type local:RoundWaitProgress}}}" Height="{Binding Width,RelativeSource={RelativeSource Self}}"> |
|||
<Grid x:Name="g1" RenderTransformOrigin="0.5,0.5" Opacity="0"> |
|||
<Grid.RenderTransform> |
|||
<RotateTransform Angle="0"/> |
|||
</Grid.RenderTransform> |
|||
<Border Width="8" Height="8" Background="{Binding Color,Mode=OneWay,UpdateSourceTrigger=PropertyChanged,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type local:RoundWaitProgress}}}" CornerRadius="5" VerticalAlignment="Bottom" HorizontalAlignment="Center"/> |
|||
</Grid> |
|||
|
|||
<Grid x:Name="g2" RenderTransformOrigin="0.5,0.5" Opacity="0"> |
|||
<Grid.RenderTransform> |
|||
<RotateTransform Angle="0"/> |
|||
</Grid.RenderTransform> |
|||
<Border Width="8" Height="8" Background="{Binding Color,Mode=OneWay,UpdateSourceTrigger=PropertyChanged,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type local:RoundWaitProgress}}}" CornerRadius="5" VerticalAlignment="Bottom" HorizontalAlignment="Center"/> |
|||
</Grid> |
|||
|
|||
<Grid x:Name="g3" RenderTransformOrigin="0.5,0.5" Opacity="0"> |
|||
<Grid.RenderTransform> |
|||
<RotateTransform Angle="0"/> |
|||
</Grid.RenderTransform> |
|||
<Border Width="8" Height="8" Background="{Binding Color,Mode=OneWay,UpdateSourceTrigger=PropertyChanged,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type local:RoundWaitProgress}}}" CornerRadius="5" VerticalAlignment="Bottom" HorizontalAlignment="Center" /> |
|||
</Grid> |
|||
|
|||
<Grid x:Name="g4" RenderTransformOrigin="0.5,0.5" Opacity="0"> |
|||
<Grid.RenderTransform> |
|||
<RotateTransform Angle="0"/> |
|||
</Grid.RenderTransform> |
|||
<Border Width="8" Height="8" Background="{Binding Color,Mode=OneWay,UpdateSourceTrigger=PropertyChanged,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type local:RoundWaitProgress}}}" CornerRadius="5" VerticalAlignment="Bottom" HorizontalAlignment="Center"/> |
|||
</Grid> |
|||
|
|||
<Grid x:Name="g5" RenderTransformOrigin="0.5,0.5" Opacity="0"> |
|||
<Grid.RenderTransform> |
|||
<RotateTransform Angle="0"/> |
|||
</Grid.RenderTransform> |
|||
<Border Width="8" Height="8" Background="{Binding Color,Mode=OneWay,UpdateSourceTrigger=PropertyChanged,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type local:RoundWaitProgress}}}" CornerRadius="5" VerticalAlignment="Bottom" HorizontalAlignment="Center"/> |
|||
</Grid> |
|||
</Grid> |
|||
<TextBlock Text="{Binding WaitText,Mode=OneWay,UpdateSourceTrigger=PropertyChanged,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type local:RoundWaitProgress}}}" |
|||
Grid.Row="1" HorizontalAlignment="Center" VerticalAlignment="Center" |
|||
Margin="0,15,0,0"/> |
|||
</Grid> |
|||
</Grid> |
|||
</UserControl> |
@ -0,0 +1,180 @@ |
|||
using SJ.Controls.Helpers; |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Windows; |
|||
using System.Windows.Controls; |
|||
using System.Windows.Media; |
|||
using System.Windows.Media.Animation; |
|||
|
|||
namespace SJ.Controls |
|||
{ |
|||
/// <summary>
|
|||
/// RoundWaitProgress.xaml 的交互逻辑
|
|||
/// </summary>
|
|||
public partial class RoundWaitProgress : UserControl |
|||
{ |
|||
public RoundWaitProgress() |
|||
{ |
|||
InitializeComponent(); |
|||
this.Loaded += RoundWaitProgress_Loaded; |
|||
InitAnimationData(); |
|||
} |
|||
|
|||
private void RoundWaitProgress_Loaded(object sender, RoutedEventArgs e) |
|||
{ |
|||
if (!IsPlaying) |
|||
this.Visibility = Visibility.Collapsed; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 初始化动画数据
|
|||
/// </summary>
|
|||
private void InitAnimationData() |
|||
{ |
|||
if (ControlList == null) |
|||
ControlList = new List<FrameworkElement>() { g1, g2, g3, g4, g5 }; |
|||
|
|||
if (AngleAnimationParamList == null) |
|||
AngleAnimationParamList = new List<BaseKeyFrame>(); |
|||
if (BeginOpacityAnimationParamList == null) |
|||
BeginOpacityAnimationParamList = new List<BaseKeyFrame>(); |
|||
if (EndOpacityAnimationParamList == null) |
|||
EndOpacityAnimationParamList = new List<BaseKeyFrame>(); |
|||
|
|||
AngleAnimationParamList.Clear(); |
|||
BeginOpacityAnimationParamList.Clear(); |
|||
EndOpacityAnimationParamList.Clear(); |
|||
|
|||
AngleAnimationParamList.Add(new BaseKeyFrame() { Value = 0, _KeyTime = new TimeSpan(0, 0, 0, 0, 0) }); |
|||
AngleAnimationParamList.Add(new BaseKeyFrame() { Value = 112, _KeyTime = new TimeSpan(0, 0, 0, 0, 400) }); |
|||
AngleAnimationParamList.Add(new BaseKeyFrame() { Value = 202, _KeyTime = new TimeSpan(0, 0, 0, 0, 1500) }); |
|||
AngleAnimationParamList.Add(new BaseKeyFrame() { Value = 472, _KeyTime = new TimeSpan(0, 0, 0, 0, 2200) }); |
|||
AngleAnimationParamList.Add(new BaseKeyFrame() { _KeyTime = new TimeSpan(0, 0, 0, 0, 3100), Value = 562 }); |
|||
AngleAnimationParamList.Add(new BaseKeyFrame() { _KeyTime = new TimeSpan(0, 0, 0, 0, 3500), Value = 720 }); |
|||
|
|||
BeginOpacityAnimationParamList.Add(new BaseKeyFrame() { _KeyTime = new TimeSpan(0, 0, 0, 0, 0), Value = 0 }); |
|||
BeginOpacityAnimationParamList.Add(new BaseKeyFrame() { _KeyTime = new TimeSpan(0, 0, 0, 0, 1), Value = 1 }); |
|||
|
|||
EndOpacityAnimationParamList.Add(new BaseKeyFrame() { _KeyTime = new TimeSpan(0, 0, 0, 0, 3499), Value = 1 }); |
|||
EndOpacityAnimationParamList.Add(new BaseKeyFrame() { _KeyTime = new TimeSpan(0, 0, 0, 0, 3500), Value = 0 }); |
|||
EndOpacityAnimationParamList.Add(new BaseKeyFrame() { _KeyTime = new TimeSpan(0, 0, 0, 0, 4500), Value = 0 }); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 动画属性
|
|||
/// </summary>
|
|||
public static readonly string AnglePropertyPath = "(UIElement.RenderTransform).(RotateTransform.Angle)"; |
|||
public static readonly string OpacityPropertyPath = "(UIElement.Opacity)"; |
|||
private IList<BaseKeyFrame> AngleAnimationParamList; |
|||
private IList<BaseKeyFrame> BeginOpacityAnimationParamList; |
|||
private IList<BaseKeyFrame> EndOpacityAnimationParamList; |
|||
private IList<FrameworkElement> ControlList; |
|||
private Storyboard _Storyboard; |
|||
private bool IsPlaying; |
|||
|
|||
/// <summary>
|
|||
/// 间隔时间
|
|||
/// </summary>
|
|||
public static readonly TimeSpan IntervalTimeSpan = new TimeSpan(0, 0, 0, 0, 200); |
|||
|
|||
public static readonly DependencyProperty WaitTextProperty = DependencyProperty.Register("WaitText", typeof(string), typeof(RoundWaitProgress), new PropertyMetadata("正在加载数据")); |
|||
|
|||
public string WaitText |
|||
{ |
|||
get { return GetValue(WaitTextProperty).ToString(); } |
|||
set { SetValue(WaitTextProperty, value); } |
|||
} |
|||
|
|||
public static readonly DependencyProperty ColorProperty = DependencyProperty.Register("Color", typeof(Brush), typeof(RoundWaitProgress), new PropertyMetadata(new SolidColorBrush(Colors.Black))); |
|||
|
|||
public Brush Color |
|||
{ |
|||
get { return GetValue(ColorProperty) as Brush; } |
|||
set { SetValue(ColorProperty, value); } |
|||
} |
|||
|
|||
public static readonly DependencyProperty AnimationSizeProperty = DependencyProperty.Register("AnimationSize", typeof(double), typeof(RoundWaitProgress), new PropertyMetadata(80.0)); |
|||
|
|||
public double AnimationSize |
|||
{ |
|||
get { return Convert.ToDouble(GetValue(AnimationSizeProperty)); } |
|||
set { SetValue(AnimationSizeProperty, value); } |
|||
} |
|||
|
|||
public static readonly DependencyProperty PlayProperty = DependencyProperty.Register("Play", typeof(bool), typeof(RoundWaitProgress), new PropertyMetadata(false, (s, e) => |
|||
{ |
|||
var waitControl = s as RoundWaitProgress; |
|||
if (waitControl.Play) |
|||
waitControl.Start(); |
|||
else |
|||
waitControl.Stop(); |
|||
})); |
|||
|
|||
public bool Play |
|||
{ |
|||
get { return (bool)GetValue(PlayProperty); } |
|||
set { SetValue(PlayProperty, value); } |
|||
} |
|||
|
|||
private void Start() |
|||
{ |
|||
this.IsPlaying = true; |
|||
this.Visibility = Visibility.Visible; |
|||
this._Storyboard = new Storyboard(); |
|||
foreach (var frameElement in ControlList) |
|||
{ |
|||
(frameElement.RenderTransform as RotateTransform).Angle = 0; |
|||
DoubleAnimationUsingKeyFrames daukf = new DoubleAnimationUsingKeyFrames(); |
|||
foreach (var item in AngleAnimationParamList) |
|||
{ |
|||
daukf.KeyFrames.Add(new EasingDoubleKeyFrame(Convert.ToDouble(item.Value), item._KeyTime)); |
|||
} |
|||
Storyboard.SetTargetProperty(daukf, new PropertyPath(AnglePropertyPath)); |
|||
Storyboard.SetTarget(daukf, frameElement); |
|||
this._Storyboard.Children.Add(daukf); |
|||
|
|||
DoubleAnimationUsingKeyFrames daukf1 = new DoubleAnimationUsingKeyFrames(); |
|||
foreach (var item in BeginOpacityAnimationParamList) |
|||
{ |
|||
daukf1.KeyFrames.Add(new EasingDoubleKeyFrame(Convert.ToDouble(item.Value), item._KeyTime)); |
|||
} |
|||
foreach (var item in EndOpacityAnimationParamList) |
|||
{ |
|||
daukf1.KeyFrames.Add(new EasingDoubleKeyFrame(Convert.ToDouble(item.Value), item._KeyTime)); |
|||
} |
|||
Storyboard.SetTargetProperty(daukf1, new PropertyPath(OpacityPropertyPath)); |
|||
Storyboard.SetTarget(daukf1, frameElement); |
|||
this._Storyboard.Children.Add(daukf1); |
|||
|
|||
for (var i = 0; i < AngleAnimationParamList.Count; i++) |
|||
{ |
|||
var item = AngleAnimationParamList[i]; |
|||
item._KeyTime = item._KeyTime.Add(IntervalTimeSpan); |
|||
} |
|||
|
|||
foreach (var item in BeginOpacityAnimationParamList) |
|||
{ |
|||
item._KeyTime = item._KeyTime.Add(IntervalTimeSpan); |
|||
} |
|||
|
|||
foreach (var item in EndOpacityAnimationParamList) |
|||
{ |
|||
item._KeyTime = item._KeyTime.Add(IntervalTimeSpan); |
|||
} |
|||
|
|||
this._Storyboard.RepeatBehavior = RepeatBehavior.Forever; |
|||
} |
|||
this._Storyboard.Begin(); |
|||
} |
|||
|
|||
private void Stop() |
|||
{ |
|||
this._Storyboard.Stop(); |
|||
this._Storyboard.Children.Clear(); |
|||
this._Storyboard = null; |
|||
this.IsPlaying = false; |
|||
InitAnimationData(); |
|||
this.Visibility = Visibility.Collapsed; |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,17 @@ |
|||
<Project Sdk="Microsoft.NET.Sdk"> |
|||
|
|||
<PropertyGroup> |
|||
<TargetFramework>net6.0-windows</TargetFramework> |
|||
<Nullable>enable</Nullable> |
|||
<UseWPF>true</UseWPF> |
|||
</PropertyGroup> |
|||
|
|||
<ItemGroup> |
|||
<PackageReference Include="System.Drawing.Common" Version="6.0.2-mauipre.1.22102.15" /> |
|||
</ItemGroup> |
|||
|
|||
<ItemGroup> |
|||
<ProjectReference Include="..\QYMessageCenter.Common\QYMessageCenter.Common.csproj" /> |
|||
</ItemGroup> |
|||
|
|||
</Project> |
@ -0,0 +1,377 @@ |
|||
<ResourceDictionary |
|||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" |
|||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
|||
xmlns:local="clr-namespace:SJ.Controls"> |
|||
<Style x:Key="BWin_MIN" |
|||
TargetType="{x:Type Button}"> |
|||
<Setter Property="HorizontalContentAlignment" |
|||
Value="Center" /> |
|||
<Setter Property="VerticalContentAlignment" |
|||
Value="Center" /> |
|||
<Setter Property="Foreground" Value="White"/> |
|||
<Setter Property="Cursor" Value="Hand"/> |
|||
<Setter Property="Template"> |
|||
<Setter.Value> |
|||
<ControlTemplate TargetType="{x:Type Button}"> |
|||
<Border x:Name="border" Background="Transparent" |
|||
BorderThickness="0"> |
|||
<Path x:Name="p" Stretch="Uniform" SnapsToDevicePixels="True" |
|||
HorizontalAlignment="Center" VerticalAlignment="Center" |
|||
Width="12" Height="2" Data="M0,0 12,0 12,1 0,1z" Fill="{TemplateBinding Foreground}"/> |
|||
</Border> |
|||
<ControlTemplate.Triggers> |
|||
<Trigger Property="IsEnabled" Value="false"> |
|||
<Setter Property="Opacity" Value="0.5" /> |
|||
</Trigger> |
|||
</ControlTemplate.Triggers> |
|||
</ControlTemplate> |
|||
</Setter.Value> |
|||
</Setter> |
|||
</Style> |
|||
<Style x:Key="BWin_MAX" |
|||
TargetType="{x:Type Button}"> |
|||
<Setter Property="HorizontalContentAlignment" |
|||
Value="Center" /> |
|||
<Setter Property="VerticalContentAlignment" |
|||
Value="Center" /> |
|||
<Setter Property="Foreground" Value="White"/> |
|||
<Setter Property="Cursor" Value="Hand"/> |
|||
<Setter Property="Template"> |
|||
<Setter.Value> |
|||
<ControlTemplate TargetType="{x:Type Button}"> |
|||
<Border x:Name="border" |
|||
Background="#00FFFFFF" |
|||
BorderThickness="0"> |
|||
<Path x:Name="p" Stretch="Uniform" Width="12" Height="12" Data="M1,0 10,0 11,1 11,10 10,11 1,11 0,10 0,1z" Stroke="{TemplateBinding Foreground}"/> |
|||
</Border> |
|||
<ControlTemplate.Triggers> |
|||
<Trigger Property="IsEnabled" Value="false"> |
|||
<Setter Property="Opacity" Value="0.5" /> |
|||
</Trigger> |
|||
</ControlTemplate.Triggers> |
|||
</ControlTemplate> |
|||
</Setter.Value> |
|||
</Setter> |
|||
</Style> |
|||
<Style x:Key="BWin_RESTORE" |
|||
TargetType="{x:Type Button}"> |
|||
<Setter Property="HorizontalContentAlignment" |
|||
Value="Center" /> |
|||
<Setter Property="VerticalContentAlignment" |
|||
Value="Center" /> |
|||
<Setter Property="Foreground" Value="White"/> |
|||
<Setter Property="Cursor" Value="Hand"/> |
|||
<Setter Property="Template"> |
|||
<Setter.Value> |
|||
<ControlTemplate TargetType="{x:Type Button}"> |
|||
<Border x:Name="border" |
|||
Background="#00FFFFFF" |
|||
BorderThickness="0"> |
|||
<Path x:Name="p" Stretch="Uniform" SnapsToDevicePixels="True" UseLayoutRounding="True" Data="M9,9 L9,9 9,12 L8,13 1,13 L0,12 0,5 L1,4 4,4 L4,3 4,1 L5,0 12,0 L13,1 13,8 L12,9 10,9 L9,9 9,5 L8,4 4,4" Width="14" Height="14" Stroke="{TemplateBinding Foreground}"/> |
|||
</Border> |
|||
<ControlTemplate.Triggers> |
|||
<Trigger Property="IsEnabled" Value="false"> |
|||
<Setter Property="Opacity" Value="0.5" /> |
|||
</Trigger> |
|||
</ControlTemplate.Triggers> |
|||
</ControlTemplate> |
|||
</Setter.Value> |
|||
</Setter> |
|||
</Style> |
|||
<Style x:Key="BWin_CLOSE" |
|||
TargetType="{x:Type Button}"> |
|||
<Setter Property="HorizontalContentAlignment" |
|||
Value="Center" /> |
|||
<Setter Property="VerticalContentAlignment" |
|||
Value="Center" /> |
|||
<Setter Property="Foreground" Value="White"/> |
|||
<Setter Property="Cursor" Value="Hand"/> |
|||
<Setter Property="Template"> |
|||
<Setter.Value> |
|||
<ControlTemplate TargetType="{x:Type Button}"> |
|||
<Border x:Name="border" |
|||
Background="#00FFFFFF" |
|||
BorderThickness="0"> |
|||
<Path x:Name="p" Stretch="Uniform" Width="12" Height="12" |
|||
Data="M814.060 781.227q-67.241-67.241-269.773-269.773 67.241-67.241 269.773-269.773 5.671-6.481 5.671-12.962 0 0-0.81-0.81 0-6.481-4.861-9.722-4.861-4.051-11.342-4.861-0.81 0-0.81 0-5.671 0-11.342 4.861-89.924 89.924-269.773 269.773-67.241-67.241-269.773-269.773-4.861-4.861-12.962-4.861-7.291 0.81-10.532 4.861-5.671 5.671-5.671 11.342 0 6.481 5.671 12.152 89.924 89.924 269.773 269.773-67.241 67.241-269.773 269.773-11.342 11.342 0 23.494 12.152 11.342 23.494 0 89.924-89.924 269.773-269.773 67.241 67.241 269.773 269.773 5.671 5.671 11.342 5.671 5.671 0 12.152-5.671 4.861-5.671 4.861-12.962 0-6.481-4.861-10.532z" |
|||
Fill="{TemplateBinding Foreground}"/> |
|||
</Border> |
|||
<ControlTemplate.Triggers> |
|||
<Trigger Property="IsEnabled" Value="false"> |
|||
<Setter Property="Opacity" Value="0.5" /> |
|||
</Trigger> |
|||
</ControlTemplate.Triggers> |
|||
</ControlTemplate> |
|||
</Setter.Value> |
|||
</Setter> |
|||
</Style> |
|||
|
|||
<Style TargetType="{x:Type local:BWindow}"> |
|||
<Setter Property="Background" Value="White"/> |
|||
<Setter Property="UseLayoutRounding" Value="True"/> |
|||
<Setter Property="SnapsToDevicePixels" Value="True"/> |
|||
<Setter Property="Template"> |
|||
<Setter.Value> |
|||
<ControlTemplate TargetType="{x:Type local:BWindow}"> |
|||
<Border SnapsToDevicePixels="True" |
|||
BorderThickness="{TemplateBinding BorderThickness}" |
|||
BorderBrush="{TemplateBinding BorderBrush}" |
|||
Background="{TemplateBinding Background}" |
|||
Padding="{TemplateBinding Padding}"> |
|||
<Grid x:Name="win_content"> |
|||
<AdornerDecorator> |
|||
<ContentPresenter/> |
|||
</AdornerDecorator> |
|||
<StackPanel Panel.ZIndex="99" Orientation="Horizontal" |
|||
Margin="{Binding Path=RightButtonGroupMargin,RelativeSource={RelativeSource Mode=TemplatedParent}}" |
|||
VerticalAlignment="Top" Height="22" |
|||
HorizontalAlignment="Right" |
|||
WindowChrome.IsHitTestVisibleInChrome="True"> |
|||
<Button WindowChrome.IsHitTestVisibleInChrome="True" |
|||
x:Name="PART_MIN" |
|||
Width="24" Height="22" |
|||
Style="{StaticResource BWin_MIN}" |
|||
Foreground="{Binding MinButtonColor,RelativeSource={RelativeSource Mode=TemplatedParent}}" |
|||
Visibility="{Binding Path=MinButtonVisibility, RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay}"/> |
|||
<Grid Visibility="{Binding Path=MaxButtonVisibility, RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay}"> |
|||
<Button WindowChrome.IsHitTestVisibleInChrome="True" x:Name="PART_MAX" Width="22" Height="22" Style="{StaticResource BWin_MAX}" |
|||
Foreground="{Binding MaxButtonColor,RelativeSource={RelativeSource Mode=TemplatedParent}}"/> |
|||
<Button WindowChrome.IsHitTestVisibleInChrome="True" x:Name="PART_RESTORE" Width="22" Height="22" Style="{StaticResource BWin_RESTORE}" |
|||
Foreground="{Binding MaxButtonColor,RelativeSource={RelativeSource Mode=TemplatedParent}}"/> |
|||
</Grid> |
|||
<Button WindowChrome.IsHitTestVisibleInChrome="True" |
|||
x:Name="PART_CLOSE" |
|||
Width="24" Height="22" |
|||
Style="{StaticResource BWin_CLOSE}" |
|||
Foreground="{Binding CloseButtonColor,RelativeSource={RelativeSource Mode=TemplatedParent}}" |
|||
Visibility="{Binding Path=CloseButtonVisibility, RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay}"></Button> |
|||
</StackPanel> |
|||
</Grid> |
|||
</Border> |
|||
<ControlTemplate.Triggers> |
|||
<Trigger Property="WindowState" Value="Maximized"> |
|||
<Setter Property="Visibility" Value="Collapsed" TargetName="PART_MAX"/> |
|||
<Setter Property="Visibility" Value="Visible" TargetName="PART_RESTORE"/> |
|||
<Setter Property="Margin" Value="8" TargetName="win_content"/> |
|||
</Trigger> |
|||
<Trigger Property="WindowState" Value="Normal"> |
|||
<Setter Property="Visibility" Value="Visible" TargetName="PART_MAX"/> |
|||
<Setter Property="Visibility" Value="Collapsed" TargetName="PART_RESTORE"/> |
|||
</Trigger> |
|||
</ControlTemplate.Triggers> |
|||
</ControlTemplate> |
|||
</Setter.Value> |
|||
</Setter> |
|||
</Style> |
|||
|
|||
<Style TargetType="{x:Type local:BButton}"> |
|||
<Setter Property="BorderThickness" Value="1" /> |
|||
<Setter Property="BorderBrush" Value="Black"/> |
|||
<Setter Property="HorizontalContentAlignment" Value="Center" /> |
|||
<Setter Property="HorizontalAlignment" Value="Center"/> |
|||
<Setter Property="VerticalAlignment" Value="Center" /> |
|||
<Setter Property="VerticalContentAlignment" Value="Center" /> |
|||
<!--<Setter Property="FontFamily" Value="Comic Sans MS" />--> |
|||
<Setter Property="BorderCornerRadius" Value="0" /> |
|||
<Setter Property="Background" Value="#02FFFFFF"/> |
|||
<Setter Property="DisableBgColor" Value="{Binding Background,RelativeSource={RelativeSource Self}}"/> |
|||
<Setter Property="MouseOverBgColor" Value="{Binding Background,RelativeSource={RelativeSource Self}}" /> |
|||
<Setter Property="MouseOverFontColor" Value="{Binding Foreground,RelativeSource={RelativeSource Self}}" /> |
|||
<Setter Property="PressedBgColor" Value="{Binding MouseOverBgColor,RelativeSource={RelativeSource Self}}" /> |
|||
<Setter Property="PressedFontColor" Value="{Binding MouseOverFontColor,RelativeSource={RelativeSource Self}}" /> |
|||
<Setter Property="SnapsToDevicePixels" Value="True"/> |
|||
<Setter Property="UseLayoutRounding" Value="True"/> |
|||
<Setter Property="Cursor" Value="Hand" /> |
|||
<Setter Property="FocusVisualStyle" Value="{x:Null}" /> |
|||
<Setter Property="Template"> |
|||
<Setter.Value> |
|||
<ControlTemplate TargetType="{x:Type local:BButton}"> |
|||
<Border x:Name="Bd" RenderTransformOrigin="0.5,0.5" |
|||
Background="{TemplateBinding Background}" |
|||
CornerRadius="{TemplateBinding BorderCornerRadius}" |
|||
BorderBrush="{TemplateBinding BorderBrush}" |
|||
BorderThickness="{TemplateBinding BorderThickness}" |
|||
SnapsToDevicePixels="True"> |
|||
<Border.RenderTransform> |
|||
<ScaleTransform ScaleX="1" ScaleY="1"/> |
|||
</Border.RenderTransform> |
|||
<ContentPresenter x:Name="btnContent" ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" ContentStringFormat="{TemplateBinding ContentStringFormat}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/> |
|||
</Border> |
|||
<ControlTemplate.Triggers> |
|||
<Trigger Property="IsMouseOver" Value="True"> |
|||
<Setter Property="Background" Value="{Binding MouseOverBgColor,RelativeSource={RelativeSource Mode=TemplatedParent}}" TargetName="Bd" /> |
|||
<Setter Property="TextBlock.Foreground" Value="{Binding MouseOverFontColor,RelativeSource={RelativeSource Mode=TemplatedParent}}" TargetName="Bd" /> |
|||
</Trigger> |
|||
<Trigger Property="IsPressed" Value="True"> |
|||
<Setter Property="Background" Value="{Binding PressedBgColor,RelativeSource={RelativeSource Mode=TemplatedParent}}" TargetName="Bd" /> |
|||
<Setter Property="TextBlock.Foreground" Value="{Binding PressedFontColor,RelativeSource={RelativeSource Mode=TemplatedParent}}" TargetName="Bd" /> |
|||
</Trigger> |
|||
<MultiTrigger> |
|||
<MultiTrigger.Conditions> |
|||
<Condition Property="IsPressed" Value="True"/> |
|||
<Condition Property="PressedScale" Value="True"/> |
|||
</MultiTrigger.Conditions> |
|||
<Setter Property="RenderTransform" TargetName="Bd"> |
|||
<Setter.Value> |
|||
<ScaleTransform ScaleX="0.93" ScaleY="0.93"/> |
|||
</Setter.Value> |
|||
</Setter> |
|||
</MultiTrigger> |
|||
<Trigger Property="IsEnabled" Value="False"> |
|||
<Setter Property="Opacity" Value="0.5" /> |
|||
<Setter Property="Background" Value="{Binding DisableBgColor,RelativeSource={RelativeSource Mode=TemplatedParent}}" TargetName="Bd" /> |
|||
<Setter Property="Content" Value="{Binding DisableText,RelativeSource={RelativeSource Mode=TemplatedParent}}" TargetName="btnContent" /> |
|||
</Trigger> |
|||
</ControlTemplate.Triggers> |
|||
</ControlTemplate> |
|||
</Setter.Value> |
|||
</Setter> |
|||
</Style> |
|||
|
|||
<Style TargetType="{x:Type local:BTextBox}"> |
|||
<Setter Property="VerticalAlignment" Value="Center"/> |
|||
<Setter Property="VerticalContentAlignment" Value="Center"/> |
|||
<Setter Property="BorderThickness" Value="1"/> |
|||
<Setter Property="BorderBrush" Value="Black"/> |
|||
<Setter Property="FontSize" Value="12"/> |
|||
<Setter Property="Cursor" Value="IBeam"/> |
|||
<Setter Property="Padding" Value="5,0,0,0"/> |
|||
<Setter Property="FocusVisualStyle" Value="{x:Null}" /> |
|||
<Setter Property="WaterRemarkFontColor" Value="Gray"/> |
|||
<Setter Property="DisableBgColor" Value="Gray"/> |
|||
<Setter Property="Height" Value="30"/> |
|||
<Setter Property="Template"> |
|||
<Setter.Value> |
|||
<ControlTemplate TargetType="{x:Type local:BTextBox}"> |
|||
<Border x:Name="border" |
|||
BorderBrush="{TemplateBinding BorderBrush}" |
|||
BorderThickness="{TemplateBinding BorderThickness}" |
|||
Background="{TemplateBinding Background}" |
|||
CornerRadius="{TemplateBinding BorderCornerRadius}" |
|||
SnapsToDevicePixels="True"> |
|||
<Grid> |
|||
<ScrollViewer x:Name="PART_ContentHost" Focusable="False" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden"/> |
|||
<TextBlock x:Name="txtRemark" Text="{TemplateBinding WaterRemark}" |
|||
Foreground="{TemplateBinding WaterRemarkFontColor}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" |
|||
Margin="{TemplateBinding Padding}" |
|||
Visibility="Collapsed"/> |
|||
</Grid> |
|||
</Border> |
|||
<ControlTemplate.Triggers> |
|||
<Trigger Property="Text" Value=""> |
|||
<Setter Property="Visibility" Value="Visible" TargetName="txtRemark"/> |
|||
</Trigger> |
|||
<Trigger Property="IsEnabled" Value="False"> |
|||
<Setter Property="Background" Value="{Binding DisableBgColor,RelativeSource={RelativeSource Mode=TemplatedParent}}" |
|||
TargetName="border"/> |
|||
</Trigger> |
|||
</ControlTemplate.Triggers> |
|||
</ControlTemplate> |
|||
</Setter.Value> |
|||
</Setter> |
|||
</Style> |
|||
|
|||
<Style TargetType="{x:Type local:BTextBoxAnimation}"> |
|||
<Setter Property="VerticalAlignment" Value="Center"/> |
|||
<Setter Property="VerticalContentAlignment" Value="Center"/> |
|||
<Setter Property="BorderThickness" Value="0,0,0,1"/> |
|||
<Setter Property="BorderBrush" Value="Gray"/> |
|||
<Setter Property="Cursor" Value="IBeam"/> |
|||
<Setter Property="FontSize" Value="12"/> |
|||
<Setter Property="Padding" Value="5,0,0,0"/> |
|||
<Setter Property="FocusVisualStyle" Value="{x:Null}" /> |
|||
<Setter Property="Focusable" Value="True"/> |
|||
<Setter Property="WaterRemarkFontColor" Value="Gray"/> |
|||
<Setter Property="WaterRemarkTopStateColor" Value="Gray"/> |
|||
<Setter Property="DisableBgColor" Value="Gray"/> |
|||
<Setter Property="MinHeight" Value="40"/> |
|||
<Setter Property="Template"> |
|||
<Setter.Value> |
|||
<ControlTemplate TargetType="{x:Type local:BTextBoxAnimation}"> |
|||
<Border x:Name="border" |
|||
BorderBrush="{TemplateBinding BorderBrush}" |
|||
BorderThickness="{TemplateBinding BorderThickness}" |
|||
Background="{TemplateBinding Background}" |
|||
CornerRadius="{TemplateBinding BorderCornerRadius}" |
|||
SnapsToDevicePixels="True"> |
|||
<Grid> |
|||
<Grid.RowDefinitions> |
|||
<RowDefinition Height="20"/> |
|||
<RowDefinition Height="*"/> |
|||
</Grid.RowDefinitions> |
|||
<ScrollViewer x:Name="PART_ContentHost" Focusable="False" IsTabStop="False" |
|||
HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden" |
|||
Grid.Row="1"/> |
|||
<TextBlock x:Name="txtRemark" |
|||
Text="{TemplateBinding WaterRemark}" |
|||
Foreground="{TemplateBinding WaterRemarkFontColor}" |
|||
VerticalAlignment="Center" |
|||
Margin="{TemplateBinding Padding}" |
|||
Grid.Row="1" |
|||
Panel.ZIndex="2"/> |
|||
</Grid> |
|||
</Border> |
|||
<ControlTemplate.Triggers> |
|||
<Trigger Property="IsEnabled" Value="False"> |
|||
<Setter Property="Background" Value="{Binding DisableBgColor,RelativeSource={RelativeSource Mode=TemplatedParent}}" |
|||
TargetName="border"/> |
|||
</Trigger> |
|||
<Trigger Property="WaterRemarkState" |
|||
Value="Top"> |
|||
<Setter TargetName="txtRemark" Property="Foreground" Value="{Binding WaterRemarkTopStateColor,RelativeSource={RelativeSource Mode=TemplatedParent}}"/> |
|||
<Setter TargetName="border" Property="BorderBrush" Value="{Binding WaterRemarkTopStateColor,RelativeSource={RelativeSource Mode=TemplatedParent}}"/> |
|||
</Trigger> |
|||
</ControlTemplate.Triggers> |
|||
</ControlTemplate> |
|||
</Setter.Value> |
|||
</Setter> |
|||
</Style> |
|||
|
|||
<Style TargetType="{x:Type local:BAsyncImage}"> |
|||
<Setter Property="HorizontalAlignment" Value="Center"/> |
|||
<Setter Property="VerticalAlignment" Value="Center"/> |
|||
<Setter Property="UseLayoutRounding" Value="True"/> |
|||
<Setter Property="SnapsToDevicePixels" Value="True"/> |
|||
<Setter Property="Template"> |
|||
<Setter.Value> |
|||
<ControlTemplate TargetType="{x:Type local:BAsyncImage}"> |
|||
<Border Background="{TemplateBinding Background}" |
|||
BorderBrush="{TemplateBinding BorderBrush}" |
|||
BorderThickness="{TemplateBinding BorderThickness}" |
|||
HorizontalAlignment="{TemplateBinding HorizontalAlignment}" |
|||
VerticalAlignment="{TemplateBinding VerticalAlignment}"> |
|||
<Grid> |
|||
<!-- Source="{TemplateBinding ImageSource}"--> |
|||
<Image x:Name="image" |
|||
Stretch="{TemplateBinding Stretch}" |
|||
UseLayoutRounding="{TemplateBinding UseLayoutRounding}" |
|||
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" |
|||
RenderOptions.BitmapScalingMode="HighQuality"/> |
|||
<TextBlock Text="{TemplateBinding LoadingText}" |
|||
FontSize="{TemplateBinding FontSize}" |
|||
FontFamily="{TemplateBinding FontFamily}" |
|||
FontWeight="{TemplateBinding FontWeight}" |
|||
Foreground="{TemplateBinding Foreground}" |
|||
HorizontalAlignment="Center" |
|||
VerticalAlignment="Center" |
|||
x:Name="txtLoading"/> |
|||
</Grid> |
|||
</Border> |
|||
<ControlTemplate.Triggers> |
|||
<Trigger Property="IsLoading" Value="False"> |
|||
<Setter Property="Visibility" |
|||
Value="Collapsed" |
|||
TargetName="txtLoading"/> |
|||
</Trigger> |
|||
</ControlTemplate.Triggers> |
|||
</ControlTemplate> |
|||
</Setter.Value> |
|||
</Setter> |
|||
</Style> |
|||
|
|||
<Style x:Key="middleTextBlock" TargetType="TextBlock"> |
|||
<Setter Property="HorizontalAlignment" Value="Center"/> |
|||
<Setter Property="VerticalAlignment" Value="Center"/> |
|||
</Style> |
|||
|
|||
</ResourceDictionary> |
Loading…
Reference in new issue