Archive
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):
- Download the .vsix
- Extract contents with 7-Zip (since .vsix is a .zip file which you can see by renaming to .zip or .vsix.zip)
- Modify file with extension .vsixmanifest to add <visualstudio version="11.0"> to the <supportedproducts> node
- Change MaxVersion to <supportedframeworkruntimeedition minversion="3.5" maxversion="4.5" /> (this may not be necessary)
- Zip up contents again
- Rename extension back to .vsix
- 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
HowTo: Bind to a DataContext property named Source in XAML
While refactoring ClipFlair code to use MVVM (Model-View-ViewModel) pattern, I came across the XAML error “Object reference not set to an instance of an object.”, shown in Visual Studio when trying to bind to my ViewModel (accessed implicitly, being set as the DataContext of the XAML control) for a property named Source.
I have settled down to using the following MVVM-style pattern (of my own) at ClipFlair:
Update: Later on, at ClipFlair project, I renamed folder “Views” to “ViewModels” and folder “Components” to “Views” and moved “ViewModels” folder inside the “Views” one to keep view-related stuff in one place.
IImageViewer.cs:
ImageView.cs:
Update: Later on, I refactored this to initialize the fields directly instead of at the constructor:
//can set fields directly here or at the constructor
private Uri source = IImageViewerDefaults.DefaultSource;
ImageViewerWindow.xaml.cs (the so-called codebehind for the XAML control):
Note above how we set the "DataContext" of the control to our ViewModel, so that we can bind to its properties implicitly (without referencing it) in the XAML.
Update: There’s something very important I had forgotten to do at the implementation of the “View” property in the code above, that is to listen for PropertyChangeEvents emitted by the ViewModel. In specific, we need to listen for changes of the ViewModel’s “Source” property to keep the View’s “SourceProperty” (a DependencyProperty that is also accessed via the View’s “Source” property) in sync with the ViewModel’s “Source” property. So the code shown in the above screenshot has to be fixed by changing the “View” property’s implementation like below:
For extra safety in case you want to allow setting a null ViewModel to the View property, you could check for (value != null) before trying to add PropertyChanged event handler to it:
if (value != null)
value.PropertyChanged += new PropertyChangedEventHandler(View_PropertyChanged);
Obviously, if more DependencyProperties are added to the component (e.g. to be able to set them declaratively from XAML when instantiating the component) that have to be in sync to respective ones at the ViewModel (which is held by the View property), then the “View_PropertyChanged” method (event handler) implementation has to be extended with “else if” statements for each of those properties to set the respective dependency properties from the matching ViewModel properties.
BTW, if your ViewModel passes null to the changed property name to mark a single change event for multiple properties, then you have to also take that in mind (else you will get exception when you try to call “Equals” method on null string), by doing something like below:
if (e.PropertyName == null) {
Source = View.Source;OtherProperty = View.OtherProperty;
//…sync all properties since we are not told which ones changed
return;}
else if (e.PropertyName.Equals("Source") {
Source = View.Source;}
else if (e.PropertyName.Equals("OtherProperty")
{OtherProperty = View.OtherProperty;
}
//…
Note that instead of “.Equals” one could have also used “==” operator, since the C# compiler maps the string equality operator to string’s “.Equals” method.
Update: Another retouch I have since done to the code above is to avoid hardcoding property names and their default values and use nstead ithe proprerty name constants defined at the class IImageViewerProperties and the respective default values defined at IImageViewerDefaults. For example, I prefer to use (after adding a “using ClipFlair.Models.Views;” to the top):
public static readonly DependencyProperty SourceProperty =
DependencyProperty.Register(IImageViewerProperties.PropertySource, typeof(Uri), typeof(ImageWindow), new FrameworkPropertyMetadata((Uri)IImageViewerDefaults.DefaultSource,
new PropertyChangedCallback(OnSourceChanged)));
Update: I eventually opted for using a “switch” statement instead of nested if / else if statements, to keep things cleaner when more properties are added:
protected void View_PropertyChanged(object sender,
PropertyChangedEventArgs e)
{
if (e.PropertyName == null)
{
Source = View.Source;
//...
}
else switch (e.PropertyName)
//string equality check in .NET uses ordinal (binary) comparison
//semantics by default
{
case IImageViewerProperties.PropertySource:
Source = View.Source;
break;
//...
}
}
ImageViewerWindow.xaml (the XAML control):
The issue at the last screenshot is that you can’t write Source="{Binding Source}" as you’d write Source="{Binding SomeDataContextProperty}", but need to write Source="{Binding Path=Source}" instead, since Source is a keyword at Binding expression syntax.
BTW, note that at the “edImageURL” TextBox I use Mode=TwoWay (two-way binding, the default is one way binding from source [the DataContext in our case] to target), whereas at the Image control I don’t. Both get an image URI from the ViewModel’s “Source” property, but we also want to be able to edit the URI at the textbox and update the view’s Source property (which will in turn update the Image control with the new image).
Also, note that apart from passing a URI to the Source property of an Image control there’s also a more verbose syntax one could use above, which can be handy to know of:
<Image>
<Image.Source><BitmapImage UriSource="{Binding Path=Source}" />
</Image.Source>
</Image>
The <Image.Source> tag here is using the so-called property element syntax pattern. In the snippet above it sets a value to the Source property of the Image tag. XAML can use both XML attributes and child elements to set values to properties of controls, but whereas the attribute name would be “Source”, the child element tag has to be “Image.Source”, not just “Source”, since the XML schema needs to have unique definitions for the XML tags, whereas multiple objects could define different Source properties causing naming collisions.
According to http://10rem.net/blog/2012/03/27/tip-binding-an-image-elements-source-property-to-a-uri-in-winrt-xaml this more verbose syntax is needed at Windows 8 Metro-style apps (that is for the WinRT API) for binding an Image to a URI (but since that article is back from March 2012, probably this is not an issue any more).
Single statement ScaleTransform initialization in both WPF and SL
With Silverlight using a cut-down .NET API, some decisions have been at least ackward, causing Silverlight code to be sometimes unnecesserily more complex than its WPF counterpart and WPF code needing several changes to get ported for Silverlight. In ClipFlair I’ve implemented a WPFCompatibility layer to ease compiling WPF code for Silverlight (and vice-versa too) without source code changes.
One of the missing things from Silverlight is at ScaleTransform class, where only a parameterless constructor is available. That way, whereas in WPF you can construct a ScaleTransform and initialize it in one statement, in Silverlight you need to first construct the transform and then set its X scale and Y scale in two separate (property setter) statements. Obviously this also has a small cost in performance since you end up with 3 method calls instead of a single one.
That is the WPF statement
ScaleTransform t = new ScaleTransform(someXscale, someYscale);
has to be translated in Silverlight to:
ScaleTransform t = new ScaleTransform();
t.ScaleX = someXscale;
t.ScaleY = someYscale;
In WPF_ScaleTransform.cs file at WPF_Compatibility project, I provide two different approaches to aid in more portable code that uses ScaleTransform:
1) The first approach is to create a method named “new_ScaleTransform” that takes X & Y scale parameters and returns a new ScaleTransform object and use it instead of calls to ScaleTransform’s constructor that takes X and Y scale.
public static ScaleTransform new_ScaleTransform(double scaleX, double scaleY) //unfortunately there are is no extension method mechanism for contructors in C# yet (and the ScaleTransform class is sealed so we can’t create descendent class)
{
ScaleTransform result = new ScaleTransform();
result.ScaleX = scaleX;
result.ScaleY = scaleY;
return result;
}
Since WPF_Compatibility uses two separate projects WPF_Compatibility.WPF and WPF_Compatibility.Silverlight that share the same source files (added as file links from a common Source subfolder instead of copied into the projects), there is an extra optimization that I decided to do, using a conditional compilation statement so that in WPF we use more optimal code:
public static ScaleTransform new_ScaleTransform(double scaleX, double scaleY) //unfortunately there are is no extension method mechanism for contructors in C# yet (and the ScaleTransform class is sealed so we can’t create descendent class)
{
#if SILVERLIGHT
ScaleTransform result = new ScaleTransform();
result.ScaleX = scaleX;
result.ScaleY = scaleY;
#else
ScaleTransform result = new ScaleTransform(scaleX, scaleY);
#endif
return result;
}
So, with the above approach one will be able to write in both WPF and Silverlight (assuming they add a “Using WPF_Compatibility;” to the top of their C# source file):
ScaleTransform t = new_ScaleTransform(someXscale, someYscale);
2) The second approach is to create a (static) extension method (called SetScale) for the ScaleTransform class and have that method accept X and Y scale params (apart from the implicit ScaleTransform object), which, after setting X and Y scale, should return the ScaleTransform object so that one can construct a ScaleTransform with the parameterless constructor and daisy chain a call to the SetScale method in the same statement. Since that method returns the ScaleTransform object that was passed to it (after setting X and Y scale to it), the combination behaves like a parametric constructor.
public static ScaleTransform SetScale(this ScaleTransform transform, double scaleX, double scaleY)
//can use this in both WPF and Silveright (the last one misses a parametric
//constructor) to initialize on the same statement on which we construct the
//ScaleTransform
{
transform.ScaleX = scaleX;
transform.ScaleY = scaleY;
return transform; //return the transform so that it can be used in the form
ScaleTransform t = new ScaleTransform().SetScale(scaleX, scaleY)
}
After you import the namespace WPFCompatibility (via the using statement mentioned above), where the WPF_ScaleTransform static class belongs, you can make use of this static extension method like below:
ScaleTransform t = new ScaleTransform().SetValue(someXscale, someYscale);
As an added bonus, an extra extension method is provided to set both the X and Y scale from a single parameter:
public static ScaleTransform SetScale(this ScaleTransform transform, double scale)
{
return transform.SetScale(scale, scale);
}
Update:
In recent versions of C# (not sure if VB.net has such a feature) you can initialize multiple properties for a new instance in a single statement at the time of construction, so I have updated the “new_ScaleTransform” method like below. It still works at both WPF and Silverlight, while both get a single-line statement (the WPF version should still be the fastest, even though both are now one-liners).
public static ScaleTransform new_ScaleTransform(double scaleX, double scaleY)
//unfortunately there are is no extension method mechanism for contructors
//in C# yet (and the ScaleTransform class is sealed so we can't create
//descendent class) { #if SSILVERLIGHT
ScaleTransform result =
new ScaleTransform() { ScaleX = scaleX, ScaleY = scaleY }; #else ScaleTransform result = new ScaleTransform(scaleX, scaleY); #endif return result; }
How to space StackPanel items in XAML (has no Padding property)
While adding some properties to the back panels of ClipFlair windows, I came upon the issue of how to space items in a StackPanel. A Padding property is missing from multiple item containers (only single content controls have such), but a nice solution is described at: http://stackoverflow.com/questions/932510/how-do-i-space-out-the-child-elements-of-a-stackpanel
Sergey Aldoukhov suggested there (WPF example):
Use Margin or Padding, applied to the scope within the container:
<StackPanel>
<StackPanel.Resources>
<Style TargetType="{x:Type TextBox}">
<Setter Property="Margin" Value="0,10,0,0"/>
</Style>
</StackPanel.Resources>
<TextBox Text="Apple"/>
<TextBox Text="Banana"/>
<TextBox Text="Cherry"/>
</StackPanel>
EDIT: In case you would want to re-use the margin between two containers, you can convert the margin value to a resource in an outer scope, f.e.
<Window.Resources>
<Thickness x:Key="tbMargin">0,10,0,0</Thickness>
</Window.Resources>
and then refer to this value in the inner scope
<StackPanel.Resources>
<Style TargetType="{x:Type TextBox}">
<Setter Property="Margin" Value="{StaticResource tbMargin}"/>
</Style>
</StackPanel.Resources>
Following up on Sergey’s suggestion there, you can define and reuse a whole Style (with various property setters, including Margin) instead of just a Thickness object:
<Style x:Key="MyStyle" TargetType="SomeItemType">
<Setter Property="Margin" Value="0,5,0,5" />
...
</Style>
…
<StackPanel>
<StackPanel.Resources>
<Style TargetType="SomeItemType" BasedOn="{StaticResource MyStyle}" />
</StackPanel.Resources>
...
</StackPanel>
Note that the trick here is the use of Style Inheritance for the implicit style, inheriting from the style in some outer (probably merged from external XAML file) resource dictionary.
Sidenote:
At first, I naively tried to use the implicit style to set the Style property of the control to that outer Style resource (say defined with the key "MyStyle"):
<StackPanel>
<StackPanel.Resources>
<Style TargetType="SomeItemType">
<Setter Property="Style" Value={StaticResource MyStyle}" />
</Style>
</StackPanel.Resources>
</StackPanel>
which caused Visual Studio 2010 to shut down immediately with CATASTROPHIC FAILURE error (HRESULT: 0x8000FFFF (E_UNEXPECTED)), as described at https://connect.microsoft.com/VisualStudio/feedback/details/753211/xaml-editor-window-fails-with-catastrophic-failure-when-a-style-tries-to-set-style-property#
Note btw that there’s an even nicer solution that Elaz Katz mentioned at that StackOverflow discussion:
It shows how to create an attached behavior, so that syntax like this would work:
<StackPanel local:MarginSetter.Margin="5">
<TextBox Text="hello" />
<Button Content="hello" />
<Button Content="hello" />
</StackPanel>
Finally, another idea could be to use WPF’s UniformGrid, although that will try to space its children evenly in the available space:
http://msdn.microsoft.com/en-us/library/system.windows.controls.primitives.uniformgrid.aspx
http://www.longhorncorner.com/uploadfile/raj1979/uniformgrid-in-wpf/
Note that it has been ported to Silverlight too:
Collection of useful links for .NET, Silverlight, WPF etc. development
During the development of ClipFlair (currently at Alpha1-internal version), I’ve been doing lots of research, hunting for information (documentation, related discussion threads, useful download links) needed when writing and refactoring source code etc.
I have tried to organize these links as (Windows) Internet shortcut files into folders. They do need some further restructuring, but they can still be a useful reference. You can download the latest version of those developer links at (will add new separate releases with enhanced/refined developer links in the future):
http://clipflair.codeplex.com/releases/view/90654
Also, you can find blog posts related to issues I’ve come across up to now while developing ClipFlair at (will be updating that page):
How to compile code that uses WPF Decorator type in Silverlight
At ClipFlair I’m using a modified version of FloatingWindow control, where I try to make the WPF and Silverlight flavours of the original control share as much code as possible (this is work in progress currently, hoping to eventually have the WPF and Silverlight projects both link to the same source files [this is currently true for most of those files]).
With the ControlExtensions.cs file there (which has some useful extension methods for WPF and Silverlight controls), I had an issue, since they were very similar, apart from the fact that the WPF version had 2 methods that were using Decorator type in their implementation, whereas the Silverlight ones were identical apart from using the Border type.
WPF’s Border class extends WPF Decorator, whereas Silverlight’s Border doesn’t since Silerlight doesn’t have a Decorator class at all (to keep the size small for quick web installation they cut-off needless parts of WPF, that’s why they call Silverlight a small sibling of WPF [used to all call WPF/E if I remember well]).
Seems there’s a quick trick one can pull out to overcome this, based on C# support for “Type Aliases” with the using directive. You can add to the problematic source code file (either outside or inside any namespace declaration you have there), the following:
#if SILVERLIGHT using Decorator = System.Windows.Controls.Border; #endif
Then in that source code file you just use Decorator instead of Border for both WPF and Silverlight. Of course this works in method bodies, if you want to have that type in method parameters else well, you have to put the above type alias definition (called Using Alias Directive) in every source code file that uses this class. I’d prefer to put this in my WPF_Compatibility layer at ClipFlair codebase, but C# support for type aliases is very limited unfortunately, so I put a dummy WPF_Delegate.cs file there with the above usage info.
Isn’t it sad that you can place extension methods in existing namespaces, but can’t place type aliases similarly? In fact you can’t place say some of them in a file and refer to them alltogether, you have each user of your types replicate those using definitions to all code units where they use them. If you change somethine in the future in those definitions, things will break since some files will have outdated definitions (apart from having consumers of your types see unnecessary implementation details). I guess we need Alias Types, not Type Aliases (sic).
To see this in action, you can try opening in Visual Studio the FloatingWindow solution under Client folder of http://clipflair.codeplex.com source code base. You’ll notice the file Extensions/ControlExtensions.cs has a small arrow icon on it at both the Silverlight and the WPF projects, since it’s a link (added to both the projects using Add Existing File and clicking the dropdown menu next to the Add button to select “Add as Link”).
Speaking of file links in Visual Studio 2010, there seems to be a bug there. If you remove (not delete) a file from a project, then move that source file to another location (say one folder higher and into a Common subfolder), you can’t add the file to the project anymore till you Close the project (or right-click and Unload it) and Open it again (or reload it into the current Solution).
Zoom and Pan control for WPF and Silverlight (via WPF compatibility layer)
I’ve managed to combine
http://www.codeproject.com/Articles/85603/A-WPF-custom-control-for-zooming-and-panning
and a cut-down version of it for Silverlight that was out there:
http://www.codeproject.com/Articles/167453/A-Silverlight-custom-control-for-zooming-and-panni
I did it in a way that the Silverlight version is source-code compatible with the WPF version (via a WPF compatibility layer that even implements value coercion), so that both the WPF and the Silverlight projects share the same source code files.
The resulting libraries for WPF and Silverlight work with the existing samples (from the two articles mentioned above) without any changes to them.
Can checkout the latest version (plan to add the samples there too for convenience) under the "Client" subfolder of ClipFlair source-code base at http://clipflair.codeplex.com