Window code, note that we are binding the Overlay to the ImageSource property of the Counter.
<Window x:Class="IMAPChecker.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:main="clr-namespace:IMAPChecker" > <Window.TaskbarItemInfo> <TaskbarItemInfo Overlay="{Binding ElementName=Counter, Path=ImageSource}" /> </Window.TaskbarItemInfo> <Grid Margin="10"> …
<main:CountControl x:Name="Counter" DisplayCount="{Binding Path=Unseen}" HasIssue="{Binding Path=HasError}" IsChecking="{Binding Path=IsChecking}" />
…
</Grid> </Window>
The counter control Xaml is mainly defining brushes.
<UserControl x:Class="IMAPChecker.CountControl" 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:cc="clr-namespace:IMAPChecker" mc:Ignorable="d" Height="16" Width="16"> <UserControl.Resources> <BooleanToVisibilityConverter x:Key="boolToVisibility"/> <RadialGradientBrush x:Key="EmptyBrush" GradientOrigin="0.5,0.1" Center="0.5,0" RadiusX="2" RadiusY="0.9" > <GradientStop Color="#a0ffffff" Offset="0" /> <GradientStop Color="#40ffffff" Offset="0.6"/> <GradientStop Color="#40000000" Offset="0.7"/> <GradientStop Color="#00000000" Offset="1.25"/> </RadialGradientBrush> <RadialGradientBrush x:Key="HighlightBrush" GradientOrigin="0.5,0.1" Center="0.5,0" RadiusX="2" RadiusY="0.9" > <GradientStop Color="LightGreen" Offset="0" /> <GradientStop Color="Green" Offset="0.6"/> <GradientStop Color="DarkGreen" Offset="0.7"/> <GradientStop Color="Green" Offset="1.25"/> </RadialGradientBrush> <RadialGradientBrush x:Key="MutedBrush" GradientOrigin="0.5,0.1" Center="0.5,0" RadiusX="2" RadiusY="0.9" > <GradientStop Color="LightYellow" Offset="0" /> <GradientStop Color="CornflowerBlue" Offset="0.6"/> <GradientStop Color="Blue" Offset="0.7"/> <GradientStop Color="Gray" Offset="1.25"/> </RadialGradientBrush> <RadialGradientBrush x:Key="CheckingBrush" GradientOrigin="0.5,0.1" Center="0.5,0" RadiusX="2" RadiusY="0.9" > <GradientStop Color="LightYellow" Offset="0" /> <GradientStop Color="Gold" Offset="0.6"/> <GradientStop Color="GoldenRod" Offset="0.7"/> <GradientStop Color="Gold" Offset="1.25"/> </RadialGradientBrush> <RadialGradientBrush x:Key="IssueBrush" GradientOrigin="0.5,0.1" Center="0.5,0" RadiusX="2" RadiusY="0.9" > <GradientStop Color="LightPink" Offset="0" /> <GradientStop Color="Red" Offset="0.6"/> <GradientStop Color="DarkRed" Offset="0.7"/> <GradientStop Color="Red" Offset="1.25"/> </RadialGradientBrush> </UserControl.Resources> <Border BorderThickness="1" Name="ColourBorder" CornerRadius="5" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Background="{StaticResource CheckingBrush}"> <Viewbox HorizontalAlignment="Center"> <TextBlock Name="TextBlock" HorizontalAlignment="Stretch" VerticalAlignment="Center" TextAlignment="Center" TextWrapping="NoWrap" Foreground="Gray" FontWeight="Bold" Text="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type cc:CountControl}}, Path=DisplayCount}" /> <!--Text="1"--> </Viewbox> <Border.BorderBrush> <LinearGradientBrush EndPoint="1,1" StartPoint="0,0"> <GradientStop Color="LightGray" Offset="0" /> <GradientStop Color="DarkSlateGray" Offset="1" /> </LinearGradientBrush> </Border.BorderBrush> </Border> </UserControl>
The fun begins in the code behind, first there is state logic mapping the state to brushes, which I could alternatively do via a Convertor but the logic seemed to be part of the control so made sense here
public partial class CountControl : UserControl { public CountControl() { InitializeComponent(); InitializeBitmapGeneration(); DisplayCount = 40; } public static readonly DependencyProperty DisplayCountProperty = DependencyProperty.Register( "DisplayCount", typeof(int), typeof(CountControl), new UIPropertyMetadata(0, (d, e) => ((CountControl)d)._OnDisplayChanged())); public static readonly DependencyProperty HasIssueProperty = DependencyProperty.Register( "HasIssue", typeof(bool), typeof(CountControl), new UIPropertyMetadata(false, (d, e) => ((CountControl)d)._OnDisplayChanged())); public static readonly DependencyProperty IsCheckingProperty = DependencyProperty.Register( "IsChecking", typeof(bool), typeof(CountControl), new UIPropertyMetadata(false, (d, e) => ((CountControl)d)._OnDisplayChanged())); public static readonly DependencyProperty HasVolumeProperty = DependencyProperty.Register( "HasVolume", typeof(bool), typeof(CountControl), new UIPropertyMetadata(false, (d, e) => ((CountControl)d)._OnDisplayChanged())); public int DisplayCount { get { return (int)GetValue(DisplayCountProperty); } set { SetValue(DisplayCountProperty, value); } } public bool HasIssue { get { return (bool)GetValue(HasIssueProperty); } set { SetValue(HasIssueProperty, value); } } public bool HasVolume { get { return (bool)GetValue(HasVolumeProperty); } set { SetValue(HasVolumeProperty, value); } } public bool IsChecking { get { return (bool)GetValue(IsCheckingProperty); } set { SetValue(IsCheckingProperty, value); } } private void _OnDisplayChanged() { ImageSource = null; if (IsChecking) { ColourBorder.Background = (Brush)Resources["CheckingBrush"]; TextBlock.Foreground = Brushes.Black; return; } if (HasIssue) { ColourBorder.Background = (Brush)Resources["IssueBrush"]; TextBlock.Foreground = Brushes.White; return; } if (HasVolume == false) { ColourBorder.Background = (Brush)Resources["MutedBrush"]; TextBlock.Foreground = Brushes.Black; return; } if (DisplayCount == 0) { ColourBorder.Background = (Brush)Resources["EmptyBrush"]; TextBlock.Foreground = Brushes.Black; } else { ColourBorder.Background = (Brush)Resources["HighlightBrush"]; TextBlock.Foreground = Brushes.White; } }
And then we have the fun part where we convert the Control into an image.
#region Should be in base class protected void InitializeBitmapGeneration() { LayoutUpdated += (sender, e) => _UpdateImageSource(); } public static readonly DependencyProperty ImageSourceProperty = DependencyProperty.Register( "ImageSource", typeof(ImageSource), typeof(CountControl), new PropertyMetadata(null)); /// <summary> /// Gets or sets the ImageSource property. This dependency property /// indicates .... /// </summary> public ImageSource ImageSource { get { return (ImageSource)GetValue(ImageSourceProperty); } set { SetValue(ImageSourceProperty, value); } } private void _UpdateImageSource() { if (ActualWidth == 0 || ActualHeight == 0) { return; } ImageSource = GenerateBitmapSource(this, 16, 16); } public static BitmapSource GenerateBitmapSource(ImageSource img) { return GenerateBitmapSource(img, img.Width, img.Height); } public static BitmapSource GenerateBitmapSource(ImageSource img, double renderWidth, double renderHeight) { var dv = new DrawingVisual(); using (DrawingContext dc = dv.RenderOpen()) { dc.DrawImage(img, new Rect(0, 0, renderWidth, renderHeight)); } var bmp = new RenderTargetBitmap((int)renderWidth, (int)renderHeight, 96, 96, PixelFormats.Pbgra32); bmp.Render(dv); return bmp; } public static BitmapSource GenerateBitmapSource(Visual visual, double renderWidth, double renderHeight) { var bmp = new RenderTargetBitmap((int)renderWidth, (int)renderHeight, 96, 96, PixelFormats.Pbgra32); var dv = new DrawingVisual(); using (DrawingContext dc = dv.RenderOpen()) { dc.DrawRectangle(new VisualBrush(visual), null, new Rect(0, 0, renderWidth, renderHeight)); } bmp.Render(dv); return bmp; } #endregion } }
You must be logged in to post a comment.