Archive

Posts Tagged ‘WPF’

Difference between LocalizableAttribute and LocalizabilityAttribute in .NET

I’ve just updated an older answer of mine at:

https://social.msdn.microsoft.com/Forums/vstudio/en-US/716ef041-0a59-4c1d-9519-e14db4de7e75/localizability-vs-localizable-attributes-in-control-dev?forum=wpf

In case you’re wondering too what’s the difference between Localizable and Localizability attributes in .NET, maybe this helps a bit:

https://msdn.microsoft.com/en-us/library/ms753944(v=vs.100).aspx 

Seems the Localizability attribute is BAML-specific and makes sure localization-related comments (probably to make use by localization tools and show to the translators) are preserved/exposed when WPF XAML is compiled from text XML form into binary BAML.

Gotcha: WPF UserControl SizeChanged event not firing at resizing

Useful to know:

If you set the Width and Height on the UserControl though, you have set a fixed size and thus even if its parent tool window changes size, the UserControl never will.  You should not set Width and Height on the UserControl if you want that event to be raised as the parent tool window changes size.

from:

http://www.actiprosoftware.com/community/thread/20365/size-change-event-for-the-usercontrol

HowTo: List all known color names and find name of given color at WPF

This is my answer at
http://stackoverflow.com/questions/4475391/wpf-silverlight-find-the-name-of-a-color

Modified answer from Thomas Levesque to populate the Dictionary only when 1st needed, instead of taking the cost at startup (going to use at speech recognition-driven turtle graphics, so that user can pronounce known color names to change the turtle’s pen color)

  1. //Project: SpeechTurtle (http://SpeechTurtle.codeplex.com)
  2. //Filename: ColorUtils.cs
  3. //Version: 20150901
  4.  
  5. using System.Collections.Generic;
  6. using System.Linq;
  7. using System.Reflection;
  8. using System.Windows.Media;
  9.  
  10. namespace SpeechTurtle.Utils
  11. {
  12.   /// <summary>
  13.   /// Color-related utility methods
  14.   /// </summary>
  15.   public static class ColorUtils //based on http://stackoverflow.com/questions/4475391/wpf-silverlight-find-the-name-of-a-color
  16.   {
  17.     #region — Fields —
  18.  
  19.     private static Dictionary<string, Color> knownColors; //=null
  20.  
  21.     #endregion
  22.  
  23.     #region — Methods —
  24.  
  25.     #region Extension methods
  26.  
  27.     public static string GetKnownColorName(this Color color)
  28.     {
  29.       return GetKnownColors()
  30.           .Where(kvp => kvp.Value.Equals(color))
  31.           .Select(kvp => kvp.Key)
  32.           .FirstOrDefault();
  33.     }
  34.  
  35.     public static Color GetKnownColor(this string name)
  36.     {
  37.       Color color;
  38.       return GetKnownColors().TryGetValue(name, out color) ? color : Colors.Black; //if color for name is not found, return black
  39.     }
  40.  
  41.     #endregion
  42.  
  43.     public static Dictionary<string, Color> GetKnownColors()
  44.     {
  45.       if (knownColors == null)
  46.       {
  47.         var colorProperties = typeof(Colors).GetProperties(BindingFlags.Static | BindingFlags.Public);
  48.         knownColors = colorProperties.ToDictionary(
  49.           p => p.Name,
  50.           p => (Color)p.GetValue(null, null));
  51.       }
  52.       return knownColors;
  53.     }
  54.  
  55.     public static string[] GetKnownColorNames()
  56.     {
  57.       return GetKnownColors().Keys.ToArray();
  58.     }
  59.  
  60.     #endregion
  61.   }
  62. }

HowTo: Insert new line and spacing at content of WPF TextBlock control

While adding more voice commands at SpeechTurtle, I had to update the active legend where the available commands are displayed and their text is highlighted as the respective commands are recognized by the speech recognition engine (using .NET’s managed Speech API).

A problem I faced was how to add a newline and prefixing the 2nd line with some spaces to align with the first command at the 1st line…

First of all, adding a new line was easy, inserted a <LineBreak /> tag in the XAML inside the TextBlock tag’s content, as shown in the screenshot below:

image

Then I had the issue that I needed to add some spacing so that “Pen up” at the 2nd line starts exactly under the start of “Forward” at the 1st line (see screenshot above)…

Tried to add a Run tag, with its Text set to some spaces, but couldn’t get an exact positioning:

image

So I tried using a Separator instead, since I could define a Width for it, however, it was drawing as a gray line:

image

So I either had to change its color to White or Transparent, or use a Null Foreground Brush on it (one difference of a Null brush from a Transparent one is that the element ignores Mouse events in that case from what I remember), or just set its Visibility mode to Hidden:

image

Do note that WPF has another visibility mode apart from Visible and Hidden, that is Collapsed, where the respective control disappears from the layout flow (that value is not supported in Silverlight from what I remember), which is not what we wanted in this case (Hidden was the correct option to choose):

image

Managed .NET Speech API links

(this is my answer at http://stackoverflow.com/questions/14771474/voice-recognition-in-windows)

I’m looking into adding speech recognition to my fork of Hotspotizer Kinect-based app (http://github.com/birbilis/hotspotizer)

After some search I see you can’t markup the actionable UI elements with related speech commands in order to simulate user actions on them as one would expect if Speech input was integrated in WPF. I’m thinking of making a XAML markup extension to do that, unless someone can point to pre-existing work on this that I could reuse…

The following links should be useful:

http://www.wpf-tutorial.com/audio-video/speech-recognition-making-wpf-listen/

http://www.c-sharpcorner.com/uploadfile/mahesh/programming-speech-in-wpf-speech-recognition/

http://blogs.msdn.com/b/rlucero/archive/2012/01/17/speech-recognition-exploring-grammar-based-recognition.aspx

https://msdn.microsoft.com/en-us/library/hh855387.aspx (make use of Kinect mic array audio input)

http://kin-educate.blogspot.gr/2012/06/speech-recognition-for-kinect-easy-way.html

https://channel9.msdn.com/Series/KinectQuickstart/Audio-Fundamentals

https://msdn.microsoft.com/en-us/library/hh855359.aspx?f=255&MSPPError=-2147217396#Software_Requirements

https://www.microsoft.com/en-us/download/details.aspx?id=27225

https://www.microsoft.com/en-us/download/details.aspx?id=27226

http://www.redmondpie.com/speech-recognition-in-a-c-wpf-application/

http://www.codeproject.com/Articles/55383/A-WPF-Voice-Commanded-Database-Management-Applicat

http://www.codeproject.com/Articles/483347/Speech-recognition-speech-to-text-text-to-speech-a

http://www.c-sharpcorner.com/uploadfile/nipuntomar/speech-to-text-in-wpf/

http://www.w3.org/TR/speech-grammar/

https://msdn.microsoft.com/en-us/library/hh361625(v=office.14).aspx

https://msdn.microsoft.com/en-us/library/hh323806.aspx

https://msdn.microsoft.com/en-us/library/system.speech.recognition.speechrecognitionengine.requestrecognizerupdate.aspx

http://blogs.msdn.com/b/rlucero/archive/2012/02/03/speech-recognition-using-multiple-grammars-to-improve-recognition.aspx

HowTo: use PivotViewer in WPF

PivotViewer is an impressive Silverlight control (see my usage at http://gallery.clipflair.net), however Microsoft never released it for WPF.

One could work arround this by embedding Silverlight in their WPF app using the WebBrowser control and talking to it via the JavaScript Bridge of Silverlight, however they could also embed one of those HTML5 PivotViewer-compatible controls that have surfaced in recent years.

Apart from LobsterPot’s HTML5 PivotViewer and its older free version, for another HTML5 PivotViewer (and also a DeepZoom implementation for HTML5) you could host that comes from former SeaDragon team members at Microsoft and seems to work very well see:

http://seajax.github.io/

https://github.com/seajax/seajax/tree/master/v2/app/pivot

https://github.com/seajax/seajax/blob/master/v2/app/pivot/quickstart.html

https://github.com/seajax/seajax

Note that the WebBrowser control uses IE7 or something as HTML engine by default and you need some meta markup at the top of your HTML to tell it to use Edge mode – the latest IE engine that is installed)

<meta http-equiv="X-UA-Compatible" content="IE=edge">

Gotcha: OnLostMouseCapture always called by CaptureMouse at WPF

It seems that CaptureMouse is behaving differently in WPF and Silverlight, in that in the former one it immediately calls OnLostMouseCapture at a Visual, whereas in Silverlight it doesn’t get called if the element didn’t have the mouse capture already (btw, in Silverlight that method is at a UIElement – there is no Visual ancestor as in WPF).

    #region --- Events ---

    private void OnMouseLeftButtonDown(object source, MouseButtonEventArgs e)
    {
      if (IsMoveToPointEnabled)
      {
        MoveThumbToPoint(e.GetPosition(this));
        CaptureMouse(); //must do before setting dragging=true, since WPF seems
//to be always calling OnLostMouseCapture on all
//controls, even if they didn't have the mouse capture
dragging = true; //always set, we might not make it to capture the mouse } } private void OnMouseLeftButtonUp(object source, MouseButtonEventArgs e) { ReleaseMouseCapture(); dragging = false; //always clear, in case we never had the mouse capture } protected override void OnMouseMove(MouseEventArgs e) { base.OnMouseMove(e); if (dragging && IsMoveToPointEnabled) MoveThumbToPoint(e.GetPosition(this)); } protected override void OnLostMouseCapture(MouseEventArgs e) { base.OnLostMouseCapture(e); dragging = false; //set dragging to false whatever the value of
//IsMoveToPointEnabled (may have changed while dragging)
} #endregion

 

The rest of the code of the SliderExt class that I’ve just added to ClipFlair codebase is below, where … is where the code region that was quoted above goes. This class is a descendent of Slider and implements IsMoveToPointEnabled property for Silverlight (in WPF that property exists), plus in WPF it fixes the behavior of the control so that when that property is set, it not only supports moving the slider thumb to the point on its track where mouse button was held down (instead of stepping up/down as is usually done in scrollbars), but also supports dragging from any point in the slider track which WPF’s implementation of IsMouseToPointEnabled didn’t do (it only allowed to drag from the thumb).

//Project: ClipFlair (http://ClipFlair.codeplex.com)
//Filename: SliderExt.cs
//Version: 20140313

using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Input;

namespace SliderExtLib
{
  public class SliderExt : Slider
  {

    public SliderExt()
    {

      //peek into mouse button events (even handled ones)
AddHandler(MouseLeftButtonDownEvent,
new MouseButtonEventHandler(OnMouseLeftButtonDown), true); AddHandler(MouseLeftButtonUpEvent,
new MouseButtonEventHandler(OnMouseLeftButtonUp), true); } #region --- Fields --- protected bool dragging; #endregion #region --- Properties --- public bool IsMoveToPointEnabled //WPF has this prop (hiding it), doesn't
//implement move to point if you click and drag on the track instead of thumb
{ get { return (bool)GetValue(IsMoveToPointEnabledProperty); } set { SetValue(IsMoveToPointEnabledProperty, value); } } public static readonly DependencyProperty IsMoveToPointEnabledProperty = DependencyProperty.RegisterAttached("IsMoveToPointEnabled", typeof(bool), typeof(SliderExt),
new PropertyMetadata(false)); #endregion #region --- Methods --- private void MoveThumbToPoint(Point p) { if (Orientation == Orientation.Horizontal) Value = p.X / ActualWidth * Maximum; else //if (Orientation == Orientation.Vertical) Value = p.Y / ActualHeight * Maximum; } #endregion




...



}
}

The incentive of making such a slider was for using it at the ColorPicker control I’ve just added to the ClipFlair codebase.

HowTo: Make Project Linker extension’s VSIX install at Visual Studio 2012

Project Linker is a Visual Studio Extension that “helps to automatically create and maintain links from a source project to a target project to share code that is common to Silverlight and WPF”.

In ClipFlair, where I have shared code between a Silverlight and a WPF project (I guess same would be for XNA projects for Xbox360 and for PC), a practice I use is to put shared files in a “Source” project and add them to both projects as links (using “Open as link” action available from Add file dialog if you press the dropdown arrow next to the “Open” button).

An alternative is to put such files in say the WPF project and use the Project Linker tool from Microsoft Patterns & Practices group to link to those files from the Silverlight project easily.

However, that tool seems to be only available for Visual Studio 2010, not for the newer 2012 version. Luckily, some users have posted a workarround at the discussion there (Reviews and Q&A tabs):

  1. Download the .vsix
  2. Extract contents with 7-Zip (since .vsix is a .zip file which you can see by renaming to .zip or .vsix.zip)
  3. Modify file with extension .vsixmanifest to add <visualstudio version="11.0"> to the <supportedproducts> node
  4. Change MaxVersion to <supportedframeworkruntimeedition minversion="3.5" maxversion="4.5" /> (this may not be necessary)
  5. Zip up contents again
  6. Rename extension back to .vsix
  7. Install extension

According to comments there, this works but not for all project types. It works if one links the Silverlight project to the WPF one, but not the other way around. It throws a NullReferenceException somewhere in the extension.

HowTo: Clear contents of Silverlight’s RichTextBox control

Was just debugging an issue with loading of saved state at ClipFlair’s Text component, when I realized that Silverlight’s (and WPF’s) RichTextBox control doesn’t accept an empty string at its Xaml proprerty to clear its contents as one would expect. Instead clearing the contents of the RichTextBox requires a call to Blocks.Clear().

In ClipFlair’s case, the Text component (a FloatingWindow descendent) hosts a SilverTextEditor control, which in turn hosts a RichTextBox named rtb and has its own Xaml property, where I added the needed logic to clear the RichTextBox contents when getting a null or empty string. Wonder why Microsoft couldn’t do the same thing.

    public string Xaml     {
      get { return rtb.Xaml; }
      set {
if (value != null && value.Trim() != "") rtb.Xaml = value;
else rtb.Blocks.Clear(); 
} //allows to set null or blank value to clear the RichTextBox
    }

HowTo: Scale control arround its center using a render transform

In the context of ClipFlair development, I was recently adding independent scaling (zooming) functionality to its ZUI container’s floating windows (apart from the container zooming functionality) and came across some strange behavior, where the windows seemed to also move apart from getting scaled.

After banging my head a bit I decided to take a closer look at Microsoft’s documentation and noticed the following text at http://msdn.microsoft.com/en-us/library/system.windows.uielement.rendertransformorigin.aspx

"RenderTransformOrigin has a somewhat nonstandard use of the Point structure value, in that the Point does not represent an absolute location in a coordinate system. Instead, values between 0 and 1 are interpreted as a factor for the range of the current element in each x,y axis. For example, (0.5,0.5) will cause the render transform to be centered on the element, or (1,1) would place the render transform at the bottom right corner of the element. NaN is not an accepted value. Values beyond 0 and 1 are also accepted, and will result in more unconventional transform effects. For instance, if you set RenderTransformOrigin to be (5,5), and then apply a RotateTransform, the rotation point will be well outside the bounds of the element itself. The transform will spin your element around in a big circle that originates beyond bottom right. The origin might be somewhere inside its parent element and could possibly be possibly out of frame or view. Negative point values are similar, these will go beyond the top left bounds. Render transforms do not affect layout, and are typically used to animate or apply a temporary effect to an element."

Since ClipFlair’s FloatingWindowHostZUI template uses a Canvas to host its FloatingWindows, I obviously didn’t care about the phrase “Render transforms do not affect layout”, but the phrase “values between 0 and 1 are interpreted as a factor for the range of the current element in each x,y axis” rang a bell immediately.

Misguided by the poor Intellisense info for the RenderTransformOrigin property, I had thought that point was in the control’s coordinate system, and since I wanted to scale the control arround its center, I had used the following erroneous statement:

window.RenderTransformOrigin = new Point(window.ActualWidth/2, window.ActualHeight/2);
window.RenderTransform = new ScaleTransform().SetScale((double)e.NewValue);

instead of the correct one:

window.RenderTransformOrigin = new Point(0.5, 0.5);
                                                        //scale arround the window center
window.RenderTransform = new ScaleTransform().SetScale((double)e.NewValue);

That is the range 0 to 1 for x & y coordinates of RenderTransformOrigin refers to the UIElement region, whereas less or greater values are (proportionally) outside of it, useful for example if you want to rotate an object arround an external point with a RotateTransform.

Don’t get puzzled by the expression new ScaleTransform().SetScale(…), it’s a syntax I use for authoring portable source code between WPF and Silverlight (since Silverlight only has a parameter-less constructor for ScaleTransform and anyway WPF doesn’t have a constructor that takes a single parameter for both X and Y scale values).

To sum up, here’s the “Scale” property I added to the FloatingWindow class:

#region public double Scale   
/// <summary> /// Gets or sets current window scale. /// </summary> /// <value>Current scale.</value>
public double Scale {  
get { return (double)GetValue(ScaleProperty); }
  set { SetValue(ScaleProperty, value); } } /// <summary>
/// Identifies the <see cref="FloatingWindow.Scale" /> dependency property.
/// </summary>
/// <value>
/// The identifier for the <see cref="FloatingWindow.Scale" /> dependency property.
/// </value>
public static readonly DependencyProperty ScaleProperty =
    DependencyProperty.Register("Scale", typeof(double), typeof(FloatingWindow),
      new PropertyMetadata(1d, OnScalePropertyChanged));
//Must use 1d here, not 1 (else will get XAMLParseException at runtime)
/// <summary>
/// ScaleProperty PropertyChangedCallback call back static function.
/// </summary>
/// <param name="d">FloatingWindow object whose Scale property is changed.</param>
/// <param name="e">DependencyPropertyChangedEventArgs contains old and new values.</param>
private static void OnScalePropertyChanged(DependencyObject d,
DependencyPropertyChangedEventArgs e) {  
FloatingWindow window = (FloatingWindow)d;
  if (window != null)
  { 
    window.RenderTransformOrigin = new Point(0.5, 0.5); //scale arround the window center
    window.RenderTransform = new ScaleTransform().SetScale((double)e.NewValue);
}
} #endregion
%d bloggers like this: