Here I will post problems I and my colleagues met and solutions we found.

Friday, November 26, 2010

Performance in WPF

Recently we struggled with the performance of our WPF application. Everything was slow. Changing size of the window - slow, maximizing - slow, refreshing - slow. Then I looked at CPU - it was using CPU in idle. Something definitely wasn't right.

And then I found WPF Performance Tool

Using this tool I found that we had animation running in the background. We used it to indicate that something is going on when we do asynchronous calls, and then we hided animated elements with visibility. Well, even being invisible, animation continued to use resources, and very noticeably


My conclusions are:
1. Be very careful with animation. Especially if you run without expiration time, but wish to stop them manually, don't forget to stop them.
2. There are performance tools that can help. Particularly, I paid attention to the "frame rate", which helped me to identify my problem. The values should be close to zero when application is idle. If you are serious, learn these tools.

Monday, November 15, 2010

app.config file and MSI

There are so many examples in the internet demonstrating how to update your app.config file during installation. But these examples never tell you about consequences of this action. And there are some.

If you use installer from Visual Studio 2008 or 2010, you probably use RemovePreviousVersion property, by setting it to true. However, starting from 2008, the the implementation of this feature changed significantly, so significantly that it has nothing to do with the name of the property. Previous version is no longer uninstalled, and there some rules for updating old files with new ones. While "versioned" files handled straightforwardly, by replacing the file with newer version, content files are replaced only if they were not changed after previous installation.

Back to updating app.config files during installation. When you changing them during installation, you change them from those that were included in your .msi package. That means it will be ignored in the next update.

See this link. http://msdn.microsoft.com/en-us/library/aa370531.aspx

Wednesday, August 18, 2010

Images in Toolbar for Disabled buttons

I started to use ToolBar control in our WPF application. The problem is that when toolbar buttons have only images, these images are not grayed when button is disabled. The solution I googled (and little bit modified) is this:


<Style x:Key="{x:Static ToolBar.ButtonStyleKey}" TargetType="{x:Type Button}">
<!-- To support graying images when button is disabled-->
<Style.Resources>
<Style TargetType="{x:Type Image}">
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType={x:Type Button}, AncestorLevel=1}, Path=IsEnabled}" Value="False">
<Setter Property="Opacity" Value="0.30"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</Style.Resources>
<Setter Property="Margin" Value="3"/>
</Style>


Make sure this style is available in you resources.

Update:
When I tried to put images as content for the button I got an error "Specified element is already the logical child..."

So, my styles look like this:



<!-- Cannot use Content to display image to avoid "specified element is already the logical child" error -->
<Style x:Key="ToolButton_Edit" TargetType="{x:Type Button}" BasedOn="{StaticResource {x:Static ToolBar.ButtonStyleKey}}">
<Setter Property="ToolTip" Value="Edit"/>
<!--<Setter Property="Content">
<Setter.Value>
<Viewbox>
<Image Source="pack://application:,,,/Actsoft.Styles;Component/ToolImages/icons-paper-edit.png"/>
</Viewbox>
</Setter.Value>
</Setter>-->
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Image Source="pack://application:,,,/Actsoft.Styles;Component/ToolImages/icons-paper-edit.png"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

One more update
OK, now I lost the "Mouse Over" effects. So, I copied existing Button Template, modified it with putting Image instead of ContentPresenter and "stole" Tag property for Image Source.
Here is what I got now, hope this is the last change.


<Style x:Key="{x:Static ToolBar.ButtonStyleKey}" TargetType="{x:Type Button}">
<!-- To support graying images when button is disabled-->
<Style.Resources>
<Style TargetType="{x:Type Image}">
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType={x:Type Button}, AncestorLevel=1}, Path=IsEnabled}" Value="False">
<Setter Property="Opacity" Value="0.30"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</Style.Resources>
<Setter Property="Margin" Value="3"/>
<!-- To support images -->
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border x:Name="Bd"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Background="{TemplateBinding Background}"
Padding="{TemplateBinding Padding}"
SnapsToDevicePixels="True">
<Image Source="{Binding Path=Tag, RelativeSource={RelativeSource TemplatedParent}}"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="BorderBrush" TargetName="Bd" Value="#FF3399FF"/>
<Setter Property="Background" TargetName="Bd" Value="#FFC2E0FF"/>
</Trigger>
<Trigger Property="IsKeyboardFocused" Value="True">
<Setter Property="BorderBrush" TargetName="Bd" Value="#FF3399FF"/>
<Setter Property="Background" TargetName="Bd" Value="#FFC2E0FF"/>
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter Property="BorderBrush" TargetName="Bd" Value="#FF3399FF"/>
<Setter Property="Background" TargetName="Bd" Value="#FF99CCFF"/>
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

<!-- now buttons styles -->
<Style x:Key="ToolButton_Edit" TargetType="{x:Type Button}" BasedOn="{StaticResource {x:Static ToolBar.ButtonStyleKey}}">
<Setter Property="ToolTip" Value="Edit"/>
<Setter Property="Tag" Value="pack://application:,,,/Actsoft.Styles;Component/ToolImages/icons-paper-edit.png"/>
</Style>
<Style x:Key="ToolButton_Save" TargetType="{x:Type Button}" BasedOn="{StaticResource {x:Static ToolBar.ButtonStyleKey}}">
<Setter Property="ToolTip" Value="Save"/>
<Setter Property="Tag" Value="pack://application:,,,/Actsoft.Styles;Component/ToolImages/icon_save.png"/>
</Style>

Wednesday, June 30, 2010

TFS 2010 build machine workspace issues

When we converted from TFS 2008 to TFS 2010 everything seemed fine. But then I created new build definition and got this error:

The path XXX is already mapped in workspace YYY.

OK, I talked to IT who made the setup and they told they changed Build agent Working directory to

$(BuildDirectory)\$(BuildDefinitionPath)\$(BuildDefintionId) (added BuildDefinitionId).

When we tried to reverse it back we got the same error message for old converted builds, the new one started to work. Going back and forward, trying to clear workspace with tf.exe command we couldn't resolve it. Either one or another build failed.
Finally, I asked him to change Wokring Directory to some completely new folder, suspecting that we had conflict with some old settings in workspaces that we could not clean. And it helped. So, we may still have some old settings somewhere, but changing working folder to new one we had clean start and it's working so far.

Tuesday, June 29, 2010

Reporting Services and Web farm

So, we switched to using Microsoft Reporting Services instead of Local reporting. However we had one issue with our configuration. We have our web site running in a farm with two servers with NLB implemented. Also, we have one server where we have our Reporting Services running. Since reports not that critical for our application, we decided just to have one server for that.

What we found though, is very often we got this message: ReportServerException: Execution 'uj2yx4bxgzfvwsvegkwuex45' cannot be found (rsExecutionNotFound)

While first googling suggested problems with timeout, I was pretty sure it's not the issue, and started to google specifically for this error and load balancing.

What we found out is that Reporting Services create some session to handle subsequent requests. Since we have cluster, those requests come from different servers. The problem though is that in our configuration requests came from different users, particulary \NETWORK, since this is the user which is used in Application Pool. Reporting Services then denied access to since the session was created under one user and the attempt to get data was from another user.

Our solution was simple, we configured our web site to run under dedicated user, the same for both instances.

Here are links that helped me:

http://social.technet.microsoft.com/Forums/en-US/sqlreportingservices/thread/1eb12568-bfea-4e4e-bd09-1f09b055c595
http://www.andypotts.com/Blog/2009/03/30/rsExecutionNotFoundWithReportViewerInALoadBalancedReportingServicesEnvironment.aspx

Tuesday, April 13, 2010

Simple way of editing enumerators using ComboBox in WPF

Here is the simple way of setting ComboBox for editing values of some enum type.
I would not use in application for production, since it's not localizable etc. But when I need to quicky write some testing application, it works perfect.

First, put this to your resource section:


<Window.Resources>
<ObjectDataProvider
MethodName="GetValues"
ObjectType="{x:Type sys:Enum}"
x:Key="keyName">
<ObjectDataProvider.MethodParameters>
<x:Type TypeName="a:enumType" />
</ObjectDataProvider.MethodParameters>
</ObjectDataProvider>

</Window.Resources>

Then, in your combobox use it like this:


<ComboBox ItemsSource="{Binding Source={StaticResource keyName}}" SelectedItem="{Binding propertyName}">

Friday, February 12, 2010

Get Reflector Pro Beta

If you google Reflector and the open cached version of the page, you can download Beta version of Reflector Pro that integrates with Visual Studio. I assume it will be released soon for money.