Tuesday, August 3, 2021

What are Windows' In-built service accounts available and why do we need them?

In Windows system's, there are some built-in user accounts without passwords and you can use them directly and each built-in account has a different purpose. See the below image,


  • LocalService (preferred) → (User + No Network) 

    A limited service account that is very similar to Network Service and meant to run standard least-privileged services. However, unlike Network Service it accesses the network as an Anonymous user.

    • Name : NT AUTHORITY\LocalService
    • The account has no password (any password information you provide is ignored)
    • HKCU represents the LocalService user account. It has minimal privileges on the local computer & presents anonymous credentials on the network
    • SID: S-1-5-19
    • Has its own profile under the HKEY_USERS registry key (HKEY_USERS\S-1-5-19)
        • NetworkService → (User + Network)

          The limited-service account is meant to run standard privileged services. This account is far more limited than the Local System (or even Administrator) but still has the right to access the network as the machine (see caveat above).

          • Name : NT AUTHORITY\NetworkService
          • the account has no password (any password information you provide is ignored)
          • HKCU represents the NetworkService user account. It has minimal privileges on the local computer & presents the computer's credentials to remote servers.
          • SID: S-1-5-20
          • Has its own profile under the HKEY_USERS registry key (HKEY_USERS\S-1-5-20)
              • LocalSystem (dangerous, don't use!) → (Admin + Network)

                Completely trusted account, more so than the administrator account. There is nothing on a single box that this account cannot do, and it has the right to access the network as the machine (this requires Active Directory and granting the machine account permissions to something)

                • Name : .\LocalSystem (can also use LocalSystem or ComputerName\LocalSystem)
                • The account has no password (any password information you provide is ignored)
                • SID: S-1-5-18
                • Does not have any profile of its own (HKCU represents the default user)
                • Has extensive privileges on the local computer & presents the computer's credentials to remote servers.

              Saturday, April 20, 2019

              TCP error code 10061: No connection could be made because the target machine actively refused it 127.0.0.1:8867.

              I am using WCF service in my application and it was good until yesterday. Suddenly it stops to work after recent windows (I am using Windows 10) update. It throws following error.

              TCP error code 10061: No connection could be made because the target machine actively refused it 127.0.0.1:8867.

              I couldn’t find much help from Internet and after a long struggle I managed to resolve it.

              After my windows update, the Net.Tcp Listener Adapter (NetTcpActivator) service got turned OFF. After I turn it ON, then my application started to work without any issue.



              I hope this post will help to someone who really struggle about this issue. 

              Friday, September 20, 2013

              Globalize WPF application using Localization

              When you create a new product, it should be available to all people in worldwide and they could understand by his own language. When you limit your product's availability to only one language (Say in English), you limit your potential customer base. If you want your applications to reach a global audience, cost-effective localization of your product is one of the best and most economical ways to reach more customers.

              Here I am going to apply globalization and localization in my Windows Presentation Foundation (WPF) application. Globalization is the design and development of applications that perform in multiple locations. Localization is the translation of application resources into localized versions for the specific cultures that the application supports.

              A simple and effective way to localize application resources is to write a custom MarkupExtension that provides a localized value. The extension takes a parameter in the constructor that is the unique resource key. When the DepdendencyProperty asks for the value, the markup extension looks up the value from a generic resource provider. This gives you the flexibility to reuse the resource management and translation process that is already established within your company.

              The localization module consists of the following parts.

              Localization manager

              The localization manager is a static class which manages the current language and notifies to all markup extensions which are specified in RESX file, to update their values when the language changes. It also provides access to localized resources. The resources itself are provided by a generic translation provider.

              public class LocalizationManager
                  {
                      public static event EventHandler CultureChanged;
                      public static ILocalizedResourceProvider LocalizationProvider { get; set; }
                      public static IList<CultureInfo> SupportedCultures { get; private set; }
              
                      public static CultureInfo CurrentCulture
                      {
                          get { return CultureInfo.CurrentUICulture; }
                          set
                          {
                              Thread.CurrentThread.CurrentUICulture = value;
              
                              if (CultureChanged != null)
                              {
                                  CultureChanged(null, EventArgs.Empty);
                              }
                          }
                      }
              
                      public static object GetValue(string key)
                      {
                          if (LocalizationProvider != null)
                          {
                              return LocalizationProvider.GetValue(key);
                          }
                          return null;
                      }
              
                      static LocalizationManager()
                      {
                          SupportedCultures = new List<CultureInfo>();
                      }
                  }

              Localize markup extension

              The localize markup extension knows the resource key and provides the localized value. It listens to the CultureChanged event of the localization manager and update its value. 

              [MarkupExtensionReturnType(typeof(string)), Localizability(LocalizationCategory.NeverLocalize)]
                  public class LocalizeExtension : MarkupExtension
                  {
                      private DependencyObject _targetObject;
                      private DependencyProperty _targetProperty;
                      private TypeConverter _typeConverter;
              
                      public LocalizeExtension()
                      {
                          LocalizationManager.CultureChanged += LocalizationManager_CultureChanged;
                      }
              
                      ~LocalizeExtension()
                      {
                          LocalizationManager.CultureChanged -= LocalizationManager_CultureChanged;
                      }
              
                      private void LocalizationManager_CultureChanged(object sender, EventArgs e)
                      {
                          UpdateTarget();
                      }
              
                      public LocalizeExtension(string key) : this()
                      {
                          Key = key;
                      }
              
                      [ConstructorArgument("key")]
                      public string Key { get; set; }
              
                      [ConstructorArgument("format")]
                      public string Format { get; set; }
              
                      [ConstructorArgument("DefaultValue")]
                      public object DefaultValue { get; set; }
              
                      [ConstructorArgument("Converter")]
                      public IValueConverter Converter { get; set; }
              
                      internal void UpdateTarget()
                      {
                          if (_targetObject != null && _targetProperty != null)
                          {
                              _targetObject.SetValue(_targetProperty, ProvideValueInternal());
                          }
                      }
              
                      public override object ProvideValue(IServiceProvider serviceProvider)
                      {
                          // Resolve the depending object and property
                          if (_targetObject == null)
                          {
                              var targetHelper = (IProvideValueTarget)serviceProvider.GetService(typeof(IProvideValueTarget));
                              _targetObject = targetHelper.TargetObject as DependencyObject;
                              _targetProperty = targetHelper.TargetProperty as DependencyProperty;
                              _typeConverter = TypeDescriptor.GetConverter(_targetProperty.PropertyType);
                          }
              
                          return ProvideValueInternal();
                      }
              
                      private object ProvideValueInternal()
                      {
                          // Get the localized value
                          object value = LocalizationManager.GetValue(Key);
              
                          // Automatically convert the type if a matching type converter is available
                          if (value != null && _typeConverter != null && _typeConverter.CanConvertFrom(value.GetType()))
                          {
                              value = _typeConverter.ConvertFrom(value);
                          }
              
                          // If the value is null, use the fallback value if available
                          if ((value == null && DefaultValue != null) || Convert.ToString(value) == "")
                          {
                              value = DefaultValue;
                          }
              
                          // If no fallback value is available, return the key
                          if (value == null)
                          {
                              if (_targetProperty != null && _targetProperty.PropertyType == typeof(string))
                              {
                                  // Return the key surrounded by question marks for string type properties
                                  value = string.Concat("?", Key, "?");
                              }
                              else
                              {
                                  // Return the UnsetValue for all other types of dependency properties
                                  return DependencyProperty.UnsetValue;
                              }
                          }
              
                          if (Converter != null)
                          {
                              value = Converter.Convert(value, _targetProperty.PropertyType, null, CultureInfo.CurrentCulture);
                          }
              
                          // Format the value if a format string is provided and the type implements IFormattable
                          if (value is IFormattable && Format != null)
                          {
                              ((IFormattable)value).ToString(Format, CultureInfo.CurrentCulture);
                          }
                          return value;
                      }
                  }

              Resource provider

              The resource provider is a class that provides the localized resources. It has to implement the ILocalizedResourceProvider and can access any kind of resources you like RESX files.

              public class ResourceFileProvider : ResourceManager, ILocalizedResourceProvider
                  {
                      private ResourceSet _resourceSet;
              
                      public object GetValue(string key)
                      {
                          try
                          {
                              if (_resourceSet != null)
                              {
                                  return _resourceSet.GetObject(key);
                              }
                              return null;
                          }
                          catch
                          {
                              return null;
                          }
                      }
              
                      private void LoadResources()
                      {
                          ReleaseAllResources();
                          _resourceSet = GetResourceSet(CultureInfo.CurrentUICulture, true, true);
                      }
              
                      public ResourceFileProvider(string baseName, Assembly assembly) : base(baseName, assembly)
                      {
                          LoadResources();
                          LocalizationManager.CultureChanged += (sender, e) => { LoadResources(); };
                      }
                  }

              How to use it

              The usage of the markup extension is very simple. Just replace the string you want to localize by {Localize resourceKey}. Where resource key is the ID which is defined in .resx file.

              In XAML :-

              <TextBlock Text="{Localize Txt_Language, DefaultValue=Language}" />
              <TextBlock Text="{Localize Txt_Welcome, DefaultValue='Welcome to WPF Applicaiton'}" />

              CodeBehind :-

              LocalizationManager.GetValue("Txt_Language")
              LocalizationManager.GetValue("Txt_Welcome")

              Sample Output

              In English :-


              In German :-



              Monday, May 16, 2011

              Saving WPF Framework element as Image (In different formats)

              In WPF, we have an option to set the object of DrawingBrush, RadialGradientBrush, LinearGradientBrush, etc., to the Background of FrameworkElements. We can save the element as an Image using the following code snippet.


                      public static void SaveImage(string fileName, FrameworkElement element)
                      {
                          string imageExtension = null;
                          imageExtension = new FileInfo(fileName).Extension.ToLower(CultureInfo.InvariantCulture);
                          BitmapEncoder imgEncoder = null;
                          switch (imageExtension)
                          {
                              case ".bmp":
                                  imgEncoder = new BmpBitmapEncoder();
                                  break;
                              case ".jpg":
                              case ".jpeg":
                                  imgEncoder = new JpegBitmapEncoder();
                                  break;
                              case ".png":
                                  imgEncoder = new PngBitmapEncoder();
                                  break;
                              case ".gif":
                                  imgEncoder = new GifBitmapEncoder();
                                  break;
                              case ".tif":
                              case ".tiff":
                                  imgEncoder = new TiffBitmapEncoder();
                                  break;
                              case ".wdp":
                                  imgEncoder = new WmpBitmapEncoder();
                                  break;
                              default:
                                  imgEncoder = new BmpBitmapEncoder();
                                  break;
                          }
                          if (element != null)
                          {
                              RenderTargetBitmap bmpSource = new RenderTargetBitmap((int)element.ActualWidth, (int)element.ActualHeight, 96, 96, PixelFormats.Pbgra32);
                              bmpSource.Render(element);
                              imgEncoder.Frames.Add(BitmapFrame.Create(bmpSource));
                              using (Stream stream = File.Create(fileName))
                              {
                                  imgEncoder.Save(stream);
                                  stream.Close();
                              }
                          }
                      }

              Hope it will help you. Leave your comments about it. Happy coding.

              Wednesday, October 20, 2010

              Creating and Showing Smart Tooltip in WPF XBAP application

              The Smart Tooltips are displayed when user hovers the cursor over an item, without clicking it, and a tooltip may appear. It may take a second or two to display the tooltip, but when it does appear, it usually is a small box with a yellow background explaining what the icon represents. For example, in Microsoft Word, when you mouse over the Paste icon, the “Paste” tooltip appears with its description. It helps us to know about the icon as well as its functionality. 

              MS Word 2010 Smart Tool-tip appearance
              In my project application, I thought of to show the Smart tooltip in my Enrolment module. My application is WPF XBAP application; hence I am not able to customize the Tooltip with my own style using shapes. Because internally Tooltips are showing using Popup, the customized tooltip are showing with black coloured shadow in smart tooltip. Then I have search through the internet about this issue and come to know about Adorners and its feature from this link then decided to use Adorner for Smart Tooltip. Here is the adorner control source. 

              ControlAdorner Class:-

              public class ControlAdorner : Adorner
                  {
                      private Control _child;
              
                      public ControlAdorner(UIElement adornedElement)
                          : base(adornedElement) { }
              
                      protected override int VisualChildrenCount
                      {
                          get
                          {
                              return 1;
                          }
                      }
              
                      protected override Visual GetVisualChild(int index)
                      {
                          if (index != 0) throw new ArgumentOutOfRangeException();
                          return _child;
                      }
              
                      public Control Child
                      {
                          get { return _child; }
                          set
                          {
                              if (_child != null)
                              {
                                  RemoveVisualChild(_child);
                              }
                              _child = value;
                              if (_child != null)
                              {
                                  AddVisualChild(_child);
                              }
                          }
                      }
              
                      protected override Size MeasureOverride(Size constraint)
                      {
                          Size max = new Size(double.PositiveInfinity, double.PositiveInfinity);
                          this._child.Measure(max);
                          this.InvalidateArrange();
                          return this._child.DesiredSize;
                      }
              
                      protected override Size ArrangeOverride(Size finalSize)
                      {
                          FrameworkElement target = AdornedElement as FrameworkElement;
                          Point location = new Point(target.ActualWidth + 2, -((_child.ActualHeight - target.ActualHeight) / 2));
                          Rect rect = new Rect(location, finalSize);
                          this._child.Arrange(rect);
                          return this._child.RenderSize;
                      }
                  }
              
                  public class Adorners : ContentControl
                  {
                      #region Attached Properties
              
                      // Template attached property
                      public static readonly DependencyProperty TemplateProperty =
                          DependencyProperty.RegisterAttached("Template", typeof(ControlTemplate), typeof(Adorners), new PropertyMetadata(TemplateChanged));
              
                      public static ControlTemplate GetTemplate(UIElement target)
                      {
                          return (ControlTemplate)target.GetValue(TemplateProperty);
                      }
                      public static void SetTemplate(UIElement target, ControlTemplate value)
                      {
                          target.SetValue(TemplateProperty, value);
                      }
                      private static void TemplateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
                      {
                          UpdateAdroner((UIElement)d, GetIsVisible((UIElement)d), (ControlTemplate)e.NewValue);
                      }
              
                      // IsVisible attached property
                      public static readonly DependencyProperty IsVisibleProperty =
                          DependencyProperty.RegisterAttached("IsVisible", typeof(bool), typeof(Adorners), new PropertyMetadata(IsVisibleChanged));
              
                      public static bool GetIsVisible(UIElement target)
                      {
                          return (bool)target.GetValue(IsVisibleProperty);
                      }
                      public static void SetIsVisible(UIElement target, bool value)
                      {
                          target.SetValue(IsVisibleProperty, value);
                      }
                      private static void IsVisibleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
                      {
                          UserControl rootPage = FindVisualParent<UserControl>((UIElement)d);
                          Control ctrl = GetChildWindow(rootPage) as Control;
                          if (ctrl != null)
                              UpdateAdroner((UIElement)d, (bool)e.NewValue, ctrl);
                          else
                              UpdateAdroner((UIElement)d, (bool)e.NewValue, GetTemplate((UIElement)d));
                      }
              
                      // ChildWindow attached property
                      public static readonly DependencyProperty ChildWindowProperty =
                          DependencyProperty.RegisterAttached("ChildWindow", typeof(DependencyObject), typeof(Adorners));
              
                      public static DependencyObject GetChildWindow(DependencyObject target)
                      {
                          return (DependencyObject)target.GetValue(ChildWindowProperty);
                      }
                      public static void SetChildWindow(UIElement target, DependencyObject value)
                      {
                          target.SetValue(ChildWindowProperty, value);
                      }
              
                      // InternalAdorner attached property
                      public static readonly DependencyProperty InternalAdornerProperty =
                          DependencyProperty.RegisterAttached("InternalAdorner", typeof(ControlAdorner), typeof(Adorners));
              
                      public static ControlAdorner GetInteranlAdorner(DependencyObject target)
                      {
                          return (ControlAdorner)target.GetValue(InternalAdornerProperty);
                      }
                      public static void SetInternalAdorner(DependencyObject target, ControlAdorner value)
                      {
                          target.SetValue(InternalAdornerProperty, value);
                      }
              
                      #endregion
              
                      #region Implementation
              
                      // Actually do all the work:
                      private static void UpdateAdroner(UIElement adorned)
                      {
                          UpdateAdroner(adorned, GetIsVisible(adorned), GetTemplate(adorned));
                      }
              
                      private static void UpdateAdroner(UIElement adorned, bool isVisible, ControlTemplate controlTemplate)
                      {
                          var layer = AdornerLayer.GetAdornerLayer(adorned);
              
                          if (layer == null)
                          {
                              // if we don't have an adorner layer it's probably because it's too early in the window's construction.
                              Dispatcher.CurrentDispatcher.BeginInvoke( DispatcherPriority.Loaded,
                                  new Action(() => { UpdateAdroner(adorned); }));
                              return;
                          }
              
                          var existingAdorner = GetInteranlAdorner(adorned);
              
                          if (existingAdorner == null)
                          {
                              if (controlTemplate != null && isVisible)
                              {
                                  // show
                                  var newAdorner = new ControlAdorner(adorned);
                                  newAdorner.Child = new Control() { Template = controlTemplate, Focusable = false, };
                                  layer.Add(newAdorner);
                                  SetInternalAdorner(adorned, newAdorner);
                              }
                          }
                          else
                          {
                              if (controlTemplate != null && isVisible)
                              {
                                  // switch template
                                  Control ctrl = existingAdorner.Child;
                                  ctrl.Template = controlTemplate;
                              }
                              else
                              {
                                  // hide
                                  existingAdorner.Child = null;
                                  layer.Remove(existingAdorner);
                                  SetInternalAdorner(adorned, null);
                              }
                          }
                      }
              
                      private static void UpdateAdroner(UIElement adorned, bool isVisible, Control childControl)
                      {
                          var layer = AdornerLayer.GetAdornerLayer(adorned);
              
                          if (layer == null)
                          {
                              // if we don't have an adorner layer it's probably because it's too early in the window's construction.
                              Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Loaded,
                                  new Action(() => { UpdateAdroner(adorned); }));
                              return;
                          }
              
                          var existingAdorner = GetInteranlAdorner(adorned);
                          if (existingAdorner == null)
                          {
                              if (childControl != null && isVisible)
                              {
                                  // show
                                  var newAdorner = new ControlAdorner(adorned);
                                  newAdorner.Child = childControl;
                                  layer.Add(newAdorner);
                                  SetInternalAdorner(adorned, newAdorner);
                              }
                          }
                          else
                          {
                              if (childControl != null && isVisible)
                              {
                                  // switch template
                                  Control ctrl = childControl;
                              }
                              else
                              {
                                  // hide
                                  existingAdorner.Child = null;
                                  layer.Remove(existingAdorner);
                                  SetInternalAdorner(adorned, null);
                              }
                          }
                      }
              
                      public static T FindVisualParent<T>(UIElement element) where T : UIElement
                      {
                          UIElement parent = element;
                          while (parent != null)
                          {
                              T correctlyTyped = parent as T;
                              if (correctlyTyped != null)
                              {
                                  return correctlyTyped;
                              }
              
                              parent = VisualTreeHelper.GetParent(parent) as UIElement;
                          }
              
                          return null;
                      }
              
                      #endregion
                  }
              

              Sample Output

               
              Happy coding.

              Win7/Vista like busy Indicator control using Spinner animation in WPF

              I have been working on WPF XBAP projects which establish the connection between mobile and system similar to Remote Desktop connectivity. I am in need to show the current status and waiting status between mobile and system connection. Hence I've created this control which is showing similar to Win7/Vista busy indicator. I am happy to share the control with you.

              Initially I have a tried to show the circle shaped rectangular using rotate animation.  But I couldn't get the expected feel similar to Win7/Vista like busy indicator. Then I have spent few minutes in net and I come to know about the spinner animation and found the ImageStrip control from this link for implementing Image animation.  Then I have created Win7/Vista like busy indicator using the following code and control template.
              ImageStrip Class:-
               
              
              1 public class ImageStrip : Control 2 { 3 #region Dependency Properties 4 5 public int Frame 6 { 7 get { return (int)GetValue(FrameProperty); } 8 set { SetValue(FrameProperty, value); } 9 } 10 11 public static readonly DependencyProperty FrameProperty = 12 DependencyProperty.Register("Frame", typeof(int), typeof(ImageStrip), new FrameworkPropertyMetadata(0, FrameworkPropertyMetadataOptions.AffectsRender)); 13 14 public double FrameSize 15 { 16 get { return (double)GetValue(FrameSizeProperty); } 17 set { SetValue(FrameSizeProperty, value); } 18 } 19 20 public static readonly DependencyProperty FrameSizeProperty = 21 DependencyProperty.Register("FrameSize", typeof(double), typeof(ImageStrip), new FrameworkPropertyMetadata(0D, FrameworkPropertyMetadataOptions.AffectsRender)); 22 23 public ImageSource Image 24 { 25 get { return (ImageSource)GetValue(ImageProperty); } 26 set { SetValue(ImageProperty, value); } 27 } 28 29 public static readonly DependencyProperty ImageProperty = 30 DependencyProperty.Register("Image", typeof(ImageSource), typeof(ImageStrip), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.AffectsRender)); 31 32 public Orientation Orientation 33 { 34 get { return (Orientation)GetValue(OrientationProperty); } 35 set { SetValue(OrientationProperty, value); } 36 } 37 38 public static readonly DependencyProperty OrientationProperty = 39 DependencyProperty.Register("Orientation", typeof(Orientation), typeof(ImageStrip), new FrameworkPropertyMetadata(Orientation.Horizontal, FrameworkPropertyMetadataOptions.AffectsRender)); 40 41 #endregion 42 43 #region Rendering 44 45 protected override void OnRender(DrawingContext drawingContext) 46 { 47 if (Image != null) 48 { 49 Rect rect = new Rect(0, 0, RenderSize.Width, RenderSize.Height); 50 51 ImageBrush brush = new ImageBrush(Image); 52 brush.Stretch = Stretch.None; 53 brush.Viewbox = (Orientation == Orientation.Vertical) ? 54 new Rect(0, (((Frame + 0.5) * FrameSize) / Image.Height) - 0.5, 1, 1) : 55 new Rect((((Frame + 0.5) * FrameSize) / Image.Width) - 0.5, 0, 1, 1); 56 57 drawingContext.DrawRectangle(brush, null, rect); 58 } 59 } 60 61 #endregion 62 } 63

              BusyIndicator Class:-
               
              
              1 public class BusyIndicator : Control 2 { 3 static BusyIndicator() 4 { 5 DefaultStyleKeyProperty.OverrideMetadata(typeof(BusyIndicator), new FrameworkPropertyMetadata(typeof(BusyIndicator))); 6 } 7 8 public string Text 9 { 10 get { return (string)GetValue(TextProperty); } 11 set { SetValue(TextProperty, value); } 12 } 13 public static readonly DependencyProperty TextProperty = DependencyProperty.Register("Text", typeof(string), typeof(BusyIndicator), new UIPropertyMetadata(null)); 14 } 15
              XAML Style:-
               
              
              1 <ResourceDictionary 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4 xmlns:local="clr-namespace:SpinnerAnimation"> 5 6 <Style x:Key="{x:Type local:BusyIndicator}" TargetType="{x:Type local:BusyIndicator}"> 7 <Setter Property="HorizontalAlignment" Value="Center" /> 8 <Setter Property="VerticalAlignment" Value="Center" /> 9 <Setter Property="Template" > 10 <Setter.Value> 11 <ControlTemplate TargetType="{x:Type local:BusyIndicator}"> 12 <Border x:Name="mainBorder" Background="#FFFFFFFF" CornerRadius="3"> 13 <Grid> 14 <Border x:Name="shaddowBorder" Background="#FFFFFFFF" CornerRadius="3" BorderBrush="#0D566B" BorderThickness="1"> 15 <Border.Effect> 16 <DropShadowEffect BlurRadius="2" ShadowDepth="3" Opacity="0.6" Color="#FF000000" Direction="310"/> 17 </Border.Effect> 18 </Border> 19 <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center"> 20 <Viewbox Height="24" Width="24" Margin="2"> 21 <local:ImageStrip Image="Images\BusyIndicator.png" FrameSize="20" Width="20" Height="20" Margin="0 3 0 0"> 22 <local:ImageStrip.Effect> 23 <DropShadowEffect BlurRadius="3" ShadowDepth="3" Opacity="0.6" Color="#FF000000" Direction="300"/> 24 </local:ImageStrip.Effect> 25 <FrameworkElement.Triggers> 26 <EventTrigger RoutedEvent="FrameworkElement.Loaded"> 27 <BeginStoryboard> 28 <Storyboard> 29 <Int32Animation From="0" To="17" Duration="0:0:0.75" Storyboard.TargetProperty="Frame" RepeatBehavior="Forever" /> 30 </Storyboard> 31 </BeginStoryboard> 32 </EventTrigger> 33 </FrameworkElement.Triggers> 34 </local:ImageStrip> 35 </Viewbox> 36 <Label x:Name="label" FontFamily="Calibri" Content="{TemplateBinding Text}" FontSize="12" FontWeight="Bold" HorizontalAlignment="Center" VerticalAlignment="Center" /> 37 </StackPanel> 38 </Grid> 39 </Border> 40 <ControlTemplate.Triggers> 41 <Trigger Property="Text" Value="{x:Null}"> 42 <Setter Property="Visibility" Value="Collapsed" TargetName="label" /> 43 <Setter Property="Visibility" Value="Collapsed" TargetName="shaddowBorder" /> 44 </Trigger> 45 </ControlTemplate.Triggers> 46 </ControlTemplate> 47 </Setter.Value> 48 </Setter> 49 </Style> 50 51 </ResourceDictionary>

              By using ImageStrip control, we can also show the downloading, ready to connect, etc., indicators. We just need to create an appropriate image and give the Frame, FrameSize, Image and Orientation (If it is required). The sample code is below,
               
              
              1 <local:ImageStrip Image="Images/Download.png" FrameSize="22.27" Width="22" Height="22" Margin="10" Grid.Row="2" Grid.Column="3"> 2 <FrameworkElement.Triggers> 3 <EventTrigger RoutedEvent="FrameworkElement.Loaded"> 4 <BeginStoryboard> 5 <Storyboard> 6 <Int32Animation From="0" To="6" Duration="0:0:1.5" Storyboard.TargetProperty="Frame" RepeatBehavior="Forever" /> 7 </Storyboard> 8 </BeginStoryboard> 9 </EventTrigger> 10 </FrameworkElement.Triggers> 11 </local:ImageStrip> 12 13 <local:ImageStrip Image="Images/Ready.png" FrameSize="21" Width="21" Height="21" Grid.Row="3" Grid.Column="2"> 14 <FrameworkElement.Triggers> 15 <EventTrigger RoutedEvent="FrameworkElement.Loaded"> 16 <BeginStoryboard> 17 <Storyboard> 18 <Int32Animation From="0" To="5" Duration="0:0:1.3" Storyboard.TargetProperty="Frame" RepeatBehavior="Forever" /> 19 </Storyboard> 20 </BeginStoryboard> 21 </EventTrigger> 22 </FrameworkElement.Triggers> 23 </local:ImageStrip> 24

              Sample Output:-
              Happy Coding… J