Discovering .NET

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

Saturday, November 12, 2011

ResourceDictionary and memory leaks

I profiled our application for memory leaks recently, and finally get clear understanding for how ResourceDictionary can result in memory leaks or just excessive memory usage.


I can identify three problems:
  • MergedDictionaries
  • References from Control to ResourceDictionary
  • Using DropShadowEffect
MergedDictionaries:

The typical use of MergedDictionaries looks like this:


<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/X.Styles;component/TextBoxStyle.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
This code suggests that there was a ResourceDictionary with Source /X.Styles;component/TextBoxStyle.xaml defined somewhere. The way ResourceDictionary is implemented, there will be two instances of ResourceDictionary objects created in the memory. The original one, and then the one that is added to the MergedDictionaries collection.

Solution:
The solution to this problem is to create your own implementation of ResourceDictionary and use it instead. One of the examples can be found here.

Then, our code will look like this:

<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<a:CachedResourceDictionary Source="/X.Styles;component/TextBoxStyle.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>

References from control to Resource Dictionary
Assuming we implemented this approach, what if we have this code now in our application?

<UserControl A>
<UserControl.Resources>
<ResourceDictionary.MergedDictionaries>
<a:CachedResourceDictionary Source="/Actsoft.Styles;component/TextBoxStyle.xaml"/>
</ResourceDictionary.MergedDictionaries>
...
</UserControl.Resources>
...
</UserControl>
We should be fine now don't you think? Apparently not. The problem is that every ResourceDictionary keeps reference to what is called owner. Or even multiple owners. For example, when we add ResourceDictionary to UserControl, this user control becomes the owner of this ResourceDictionary. If we load ResourceDictionary to the application, the application becomes the owner. Not only that, when we add ResourceDictionary to the MergedDictionaries collection, all owners form parent dictionary added to the list of owners for child dictionary. In example above, if we have TextBoxStyle.xaml loaded to the application resources, and then to the UserControl resources, we create references from application to the instance of UserControl. As result, UserControl will remain in heap indefinitely and will not be disposed by garbage collector. And we created this problem by using CachedResourceDictionary, since if we used regular ResourceDictionary, we would have separate copy, which could be disposed as part of UserControl.

Solution:
If you decide to use CachedResourceDictionary, create and remove your user controls dynamically and want them to be disposed, you have to choose how you use resource dictionaries
  • Either use them in application resources only and don't use them in UserControl
  • Or, use them in User Controls only and don't use them in Application Resources. Beware if you activate one user control before you deactivate another one.
To simplify it, CachedResourceDictionary are for application resources or static user controls.

Problems with DropShadowEffect
The description of the problem can be found here. The problem will appear if you have code like that:


<ResourceDictionary>
<DropShadowEffect x:Key="key" ... />
And then, this resource dictionary is loaded into application resources.

Solution:
Most likely, you don't have intentions to modify this effect, so instead, you should make it look like this:

<ResourceDictionary>
<DropShadowEffect x:Key="key"
PresentationOptions:Freeze=True
... />
This will create frozen effect. As result there will be no events assigned, and no references.

Wednesday, May 18, 2011

Using .NET 2.0 assembies from .NET 4.0

I was always curious how exactly assemblies compiled for .NET 2.0 are used when you reference from asseblies compiled for .NET 4.0. Somehow, I could not find "an official" answer to this question, and was too lazy to check myself. Thankfully, I have a young collegue who was as curious as I am but not so lazy.

So, here is an experiment.

Exe A,

  • target platform 4.0
Assembly B,
  • target platform 2.0,
  • referenced by exe A.
  • references System.dll, .NET 2.0.

Question, will System.dll 2.0 will be loaded when we run A, or System.dll from 4.0?

The answer - System.dll from 4.0.

Thursday, March 24, 2011

The order in Xaml is important

Today I had one more chance to notice that the order in XAML is important.What I had was a button with code like this:



<Setter Property="Command" Value="{Binding Command}" />
<Setter Property="CommandParameter" Value="{Binding CommandParameter}"/>

Notice that I assigned Command before CommandParameter. When I was doing it, I din't even think about it. I just added support for CommandParameter at some point so I naturally added this line at the end. However, CanExecute method from ICommand was triggered immediatelly after Command was assigned to the control, even before CommandParameter was assigned. Obviously, it didn't work.

When I changed the order, it's all started to work.

Tuesday, March 22, 2011

TFS Sidekick

Nice tool. UI for all these commands from tf.exe command line. Free.


Wednesday, March 02, 2011

Offshore development

During my career I have seen several offshore teams and project. Some of them were quite successful, some of them failed.

There are numerous articles about offshore development, but I would like to write about my personal experience. Partly, to analyze what makes it work.

Generally, we can identify two different approaches. One, is where the whole project being outsourced to the offshore team. The offshore team would need to cover everything, design, architecture, development and QA.

In one of my previous companies such approach failed. Thinking about it, I would identify following problems:
1. The management of the team could not be trusted. At some point we found about money being just stolen.
2. Our company did not set requirements and priorities properly. In result we had very flexible architecture with terrible performance.
3. The team did not work in our domain before. In result, what they were doing was pure abstraction for them. Which is related to previous problem, they could not identify priorities properly.
4. Sometimes you may have problems with quality of the developers, but this wasn't the case. The developers were not worse than those in our company, which demonstrate the importance of project management.

At the same time I have seen successful offshore project developed with such kind of teams. My friend work in one of such offshore team. The team is working for the same company for more than 15 years now. The product became their own product. And they have managers visiting them regularly.

In my previous company we started working with another offshore team, and that company now outsourced all their development. Their secret is that product designs are still done here in US. The architecture, development and testing are done offshore, but release cycles are short, so the product is verified against design constantly. And the team is monitored by person with development experience.

And then there is my current company. We have few developers helping us. So, we actually have team combined from developers here and offshore. And it works! Now, what is our secret?
1. Designs are done here, with the people who knows our product and our customers
2. Since our offshore team speaks Russian and I speak Russian, we don't have language barrier.
3. And we talk often. This way I always know what the team is doing and if developers interpret design incorrectly, I can clarify things immediately, before it's too late
4. I am present at design meetings and know not only what will be in the design, but why, even though I am not subject expert myself. So, I can deliver that information to the developers. In fact, currently I am writing the design, but this is something I would love to delegate :)

In other words:
Either offshore team must have domain expertise and work in the area for a few years, or the team should actually include people from your company who knows the business. In both cases, don't let development go unsupervised. Make sure the team is on the right track. To do this, talk with them at least few times per week.
Also, have some forms of the designs. My friend uses Word or Excel documents attached to the TFS tasks, we use links to wiki.

Thursday, February 17, 2011

The power of DataTemplate.DataType property

Somehow I overlooked the existence of DataType property from DataTemplate class. I noticed it only when I started using Microsoft Ribbon and checked how they implemented MVVM pattern I realized how convenient it can be, particularly for lists.

So, how and when to use it.
1. You want to implement MVVM pattern for you lists, which means you have some objects in your view model to support your list.
2. These are objects of different types, which means you would need to create different UI elements to support them. Like for ribbon you can use buttons, or edit boxes, or anything.
3. You use some ItemsControl UI element, which supports ItemsSource property.

Make sure that it's DataTemplate you need to change. It won't work for separators, for example, since you would need to replace Control Template for that.

Friday, January 21, 2011

Default focus in XAML

Very simple task, you open window and you want some text box to have focus. And since it's common and simple task I thought it should be possible using XAML. To do this, you should use FocusManager. However, you should pay attention where you put it. I had to use it right in the Grid where I placed my TextBox. Which is logical, if you think about it. How else TextBox can be found.

Here is the xaml:



<UserControl x:Class="Actsoft.CometTracker.Layouts.AddViewView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="40" d:DesignWidth="300"
>
<Grid
FocusManager.FocusedElement="{Binding ElementName=textBox}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Label
Margin="4">View Name:</Label>
<TextBox Grid.Column="1" x:Name="textBox"
Margin="4" Text="{Binding Path=ViewName}"/>
</Grid>
</UserControl>