Showing posts with label wpf. Show all posts
Showing posts with label wpf. Show all posts

Monday, July 13, 2015

Signing ClickOnce WPF application

So let's say you have a WPF application that you want to distribute using ClickOnce. Like I am doing with my Visual Task Map.

If you want your users to download and run your application without going through multiple scary red dialog windows with warnings, you need to sing it.

A lot of information on this topic is scattered all over the web. Microsoft has a good set of articles about it. There are bunch of answered questions on Stack Overflow. But sometimes you just want the short version. So here it is.


  1. To sing any code you need to buy a code signing certificate
  2. Update project settings to sign and timestamp the ClickOnce manifest.
  3. Add a BeforePublish target into your project to sign the executable before it becomes part of the ClickOnce package.
I am using Comodo timestamping server - http://timestamp.comodoca.com/authenticode, but there are plenty of other servers to chose from. For example you can use this one: http://timestamp.verisign.com/scripts/timstamp.dll. It does not make any difference, any timestamping server will work.

Signing the manifest is simple as you just go o the project properties, Signing tab, and use your certificate (the one that you just bought, the one that has the private key) to sign the manifest. That is also where you can specify the timestamping server that will be used to timestamp the manifest.

You might also assume that signing the executable is as easy as signing the manifest because there is one more checkbox in the same dialog that says "Sign the assembly". You would be wrong. This is where you provide a certificate, used to create a Strong Name for your assembly, and your awesome new certificate won't work. Also, you don;t actually care about the strong-naming your executable. This is a good article about the difference between what VS does and what you need.

So how do you sing the executable ? There are no easy project options that will allow you to do that. And when you are dealing with ClickOnce, it all becomes a bit more complicated as ClickOnce sources binaries from the Obj folder, not the usual Bin folder, and the executable in the Obj folder has to be signed precisely at the right time: after it was actually built, but before the ClickOnce publishing mechanism has picked it up.

You can read more details about this here, and then here.
But the short version is that you need to add a call to singtool.exe into your project file. Something like this:
<Target Name="BeforePublish" Condition="'$(Configuration)|$(Platform)' == 'Release|AnyCPU'">
  <Exec Command=""C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\signtool.exe" sign /n "My Name" /t http://timestamp.comodoca.com/authenticode $(ProjectDir)obj\$(ConfigurationName)\$(TargetFileName)" />
</Target>

One important thing to remember is that the BeforePublish action works incorrectly with WPF applications in VS2013 RTM (and AfterCompile option did not work for me either). But this problem has been resolved in VS2013 Update 4 - be sure to install it.

Monday, May 26, 2008

How do I provide custom collection view for collection in WPF?

Some time ago, while "surfing" the WindowsBase.dll with Reflector, I have found one interesting interface: ICollectionViewFactory.
I made some digging, and found out that there are folks that are interested what is this interface doing (along with some other interesting interfaces...)
MSDN says nothing about this interface, but it turned out that it could be quite useful in fact.
Here is how it is declared:

/// An interface that enables implementing collections to create a view to their data. Normally, user code does not call methods on this interface.
public interface ICollectionViewFactory
{
/// Creates a new view on the collection that implements this interface. Typically, user code does not call this method.
/// The newly created view.
ICollectionView CreateView();
}

It turned out that when you try to create a default collection view for the collection(or when you provide your collection as an items source for the ItemsControl), databinding engine checks whether your collection implements ICollectionViewFactory interface, and if it does - your CreateView() method is called, so in case you want to implement some specific logic, like optimized grouping, or specific filtering - you just implement your own collection view and return it in CreateView() method.

Thursday, April 10, 2008

WPF tips: Get your own logical parent

Have you ever wondered how does the Popup knows its inheritance context, its logical parent and the route for the routed events after you set PlacementTarget property? Or how does the ContextMenu knows where to fire the commands?
Today I have incidentally found the answer.
Whenever you have the FrameworkElement, that does not have any kind of parent set directly( neither visual, nor logical ), you can choose your parent yourself :)
To do so, you should override GetUIParentCore() method and return whatever logical parent you want – one-way link will be created, so you will know who is your parent, and your parent could unaware of your existence :)
BTW Popup returns its PlacementTarget property value in this method.

This mechanism could be used to implement custom inheritance context in some cases, so it is really important to remember of its existence.

Friday, April 4, 2008

Weird solutions: Ho can I force WPF control to rerender itself.

Today I found out some strange solution for forcing control to invalidate itself.

It turned out that by default control invalidates itself only in case it's render size has been changed, his visual parent has been changed, or some of it's dependency properties with AffectsRender option set is changed. (also there are some other weird cases when control suddenly decides to rerender it's appearance)

So I decided that maybe I can use FrameworkElement's ability to react to the AffectsRender option - I implemented the attached dependency property, and tried setting it to some rendom values on an object I needed to invalidate...and it worked :)

Here is some sample class, that could be used to implement such workaround:


public class RenderingHelper : DependencyObject
{
private static int s_last = 0;

public static int GetForceRerender( DependencyObject obj )
{
return (int)obj.GetValue( ForceRerenderProperty );
}
public static void SetForceRerender( DependencyObject obj, int value )
{
obj.SetValue( ForceRerenderProperty, value );
}

public static readonly DependencyProperty ForceRerenderProperty = DependencyProperty.RegisterAttached( "ForceRerender", typeof( int ), typeof( RenderingHelper ),
new FrameworkPropertyMetadata( 0, FrameworkPropertyMetadataOptions.AffectsRender ) );


public static void InvalidateRender( Visual target )
{
SetForceRerender( target, s_last++ );
}
}



You should keep in mind that invalidation of a visual calls it's OnRender method and recreates only part of the elements visual graph. All Visual's children are left the same, so if you need to invalidate the appearance of the entire visual subtree, you should add FrameworkPropertyMetadataOptions.Inherits to the property options.

Friday, March 14, 2008

Why InvalidateZOrder is not public???

The worst case of what you can implement on WPF is custom control. In this case you have to use most of the extensebility of the framework, and it turns out that it is just, well, non-extensible...

Today it turned out that there is no way to change the z-order of the element if it's parent is not a Panel, and there is no way I can use Panel as a parent because it tries to steal my logical children :(

It also turned out that there is no way to change z-order without making this:

foreach( Visual child in children )
{
RemoveVisualChild( child );
AddVisualChild( child );
}

And that could be avoided if a method of a Visual, called InvalidateZOrder, would not be internal :(

Tuesday, March 11, 2008

Canceling keyboard focus change in WPF

Hah! Today I found out that the keyboard focus transition in WPF  is cancellable :)
It turned out that you should "handle" PreviewLostKeyboardFocus routed event (just set it's Handled to True) and magic happens - focus does not go anywhere.
Still, there are some cases when this event is not raised, for example, when user just Alt-Tabs to another application, but that does not matter in most cases :)