WinUI 3 runtime localization - c#

I am developing WinUI 3 app, currently stuck with localization. Although I wrote separate resw resource files for different cultures and localized with x:Uid I cannot find a way to change language in app runtime.
Setting Windows.Globalization.ApplicationLanguages.PrimaryLanguageOverride only works fine for settings startup language.
Is runtime localization in WinUI 3 even possible?

I've spent many hours on this subject. Here's my sincere advice: DO NOT TRY TO LOCALIZE YOUR VIEWS. Also, don't try to handle changes to the language at RunTime. No one does this, you'll never see an ROI in the investment.
Make all your localization in the view models and use the StringLocalizer class that's built into .NET's DI. Add the string localizer to the DI first:
this.serviceProvider = new ServiceCollection()
.AddLogging()
.AddLocalization();
Then, in your .NET or .Net Standard library, in your view model, add the following initialization:
private readonly IStringLocalizer<LandingViewModel> stringLocalizer;
public MyViewModel(IStringLocalizer<MyViewModel> stringLocalizer)
{
this.stringLocalizer = stringLocalizer;
}
Now, if you have some text you want to display, say on a button, you'd have:
public string SignUpText => this.stringLocalizer["SignUp"];
And in XAML, you'd have:
<Button Content="{x:Bind ViewModel.SignUpText}"/>
Finally, give the RESX file the same name as your view model. It should be an Embedded Resource with, and this is important, no custom tool:

Original Answer:
I think you're on the right track. If you are trying to change the language at runtime, call a method that will set Windows.Globalization.ApplicationLanguages.PrimaryLanguageOverride to the new language "string". But then after that, you will also have to reload your Page so that the new language takes effect.
private void ReloadLanguage(string languageOverride)
{
// Change the app language
Windows.Globalization.ApplicationLanguages.PrimaryLanguageOverride = languageOverride;
// Be sure to clear the Frame stack so that cached Pages are removed, otherwise they will have the old language.
Frame.BackStack.Clear();
// Reload the page that you want to have the new language
Frame.Navigate(typeof(MainPage));
}
-OR-
You'll have to call your ResourceLoader for the UI components you need/want to refresh one at a time.
private void RefreshUIText()
{
var resourceLoader = Windows.ApplicationModel.Resources.ResourceLoader.GetForCurrentView();
this.myXAMLTextBlockElement.Text = resourceLoader.GetString("Farewell");
}
Updated Answer:
According to Microsoft online documentation, they suggest that anytime you change the language for you "to reload your strings from the default ResourceContext". I know this is not ideal, but it appears to work.
I got the following Example Solution below to work:
MainWindow.xaml
<Grid>
<Frame x:Name="MainFrame"/>
</Grid>
MainWindow.xaml.cs
public MainWindow()
{
this.InitializeComponent();
MainFrame.Navigate(typeof(MainPage));
}
MainPage.xaml
<Grid>
<StackPanel>
<TextBlock x:Uid="Greeting" x:Name="Greeting" Text="" Margin="15"/>
<TextBlock x:Uid="Farewell" x:Name="Farewell" Text="" Margin="15"/>
<Button x:Name="SelectLanguageButton" Click="SelectLanguageButton_Click" Content="Select Language" Margin="15"/>
</StackPanel>
</Grid>
MainPage.xaml.cs
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
this.Loaded += MainPage_Loaded;
}
private void MainPage_Loaded(object sender, RoutedEventArgs e)
{
RefreshUIText();
}
private void SelectLanguageButton_Click(object sender, RoutedEventArgs e)
{
Frame.Navigate(typeof(LanguagePage));
}
private void RefreshUIText()
{
var resourceLoader = Windows.ApplicationModel.Resources.ResourceLoader.GetForViewIndependentUse();
this.Greeting.Text = resourceLoader.GetString("Greeting/Text");
this.Farewell.Text = resourceLoader.GetString("Farewell/Text");
}
}
LanguagePage.xaml
<Grid>
<StackPanel>
<Button x:Name="EnglishButton" Click="EnglishButton_Click" Content="English" Margin="15"/>
<Button x:Name="FrenchButton" Click="FrenchButton_Click" Content="French" Margin="15"/>
</StackPanel>
</Grid>
LanguagePage.xaml.cs
public sealed partial class LanguagePage : Page
{
public LanguagePage()
{
this.InitializeComponent();
}
private void EnglishButton_Click(object sender, RoutedEventArgs e)
{
ReloadLanguage("en");
}
private void FrenchButton_Click(object sender, RoutedEventArgs e)
{
ReloadLanguage("fr");
}
private void ReloadLanguage(string languageOverride)
{
// Change the app language
Windows.Globalization.ApplicationLanguages.PrimaryLanguageOverride = languageOverride;
// Be sure to clear the Frame stack so that cached Pages are removed, otherwise they will have the old language.
Frame.BackStack.Clear();
// Reload the page that you want to have the new language
Frame.Navigate(typeof(MainPage));
}
}
Resource Files and contents, Solution Explorer
Also remember to add your language declarations in the Package.appxmanifest file

I created new project - Blank App, Packaged with WAP(WinUI 3 in Desktop) with latest project templates, which come with VS extension Windows APP SDK C# VS2019. As you noticed - I am using VS 2019, Community edition. I am attaching csproj configuration of a project below.
There is a frame in main window which navigates to main page. There is only one button on main page which leads to LanguagePage on click.
Goal is to change language, clear navigation stack and navigate back to main page. However, various scenarios in SetAppLanguage didn't produced wanted result.
Please take a look at https://www.py4u.net/discuss/731870 - tried all scenarios, no effect on GUI.
Nevertheless Windows.ApplicationModel.Resources.Core.ResourceContext.GetForCurrentView(); is throwing a COMException: 'Resource Contexts may not be created on threads that do not have a CoreWindow. (0x80073B27)'

I have a NuGet package called WinUI3Localizer that helps you with localization.
GitHub:
https://github.com/AndrewKeepCoding/WinUI3Localizer
No app restart
You/users can edit localized strings even after deployment
You/users can add new languages even after deployment
Uses standard "Resources.resw"

Related

Creating a Popup in .Net Maui but "InitializeComponent()" ist not being recognized

I want to create a Popup with two Buttons. I have actually created other Popups just like this before but this time it doesn't work because the InitializeComponent() method does not exist in the current context.
C#-Code:
using CommunityToolkit.Maui.Views;
using SiRiAs.Lib.Helpers;
namespace SiRiAs.Views.Popups;
public partial class DeletePopup : Popup {
public DeletePopup() {
InitializeComponent();
}
private void Delete_Clicked(object sender, EventArgs e) => Close(DeletePopupResult.Delete);
private void Keep_Clicked(object sender, EventArgs e) => Close(DeletePopupResult.Keep);
}
Xaml:
<toolkit:Popup xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"
x:Class="SiRiAs.Views.Popups.DeletePopup">
<StackLayout>
<StackLayout Padding="15" Spacing="20">
<Button Style="{StaticResource BaseButtonStyle}"
Text="Ja,löschen"
Clicked="Delete_Clicked"
/>
<Button Style="{StaticResource BaseButtonStyle}"
Text="Nein, nicht löschen"
Clicked="Keep_Clicked"
/>
</StackLayout>
</StackLayout>
</toolkit:Popup>
I don't see, that I am doing anything different then written in the Documentation: https://learn.microsoft.com/de-de/dotnet/communitytoolkit/maui/views/popup
Also If I look up InitializeComponent() in the other Popups, it brings me to a file, that I cannot added, that is auto-generated.
The auto-generated file of another Popup, the MoreOptionsPopup, just as a reference with what I mean by auto-generated file
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a .NET MAUI source generator.
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
[assembly: global::Microsoft.Maui.Controls.Xaml.XamlResourceId("SiRiAs.Views.Popups.MoreOptionsPopup.xaml", "Views/Popups/MoreOptionsPopup.xaml", typeof(global::SiRiAs.Views.Popups.MoreOptionsPopup))]
namespace SiRiAs.Views.Popups
{
[global::Microsoft.Maui.Controls.Xaml.XamlFilePath("Views\\Popups\\MoreOptionsPopup.xaml")]
public partial class MoreOptionsPopup : global::CommunityToolkit.Maui.Views.Popup
{
[global::System.CodeDom.Compiler.GeneratedCode("Microsoft.Maui.Controls.SourceGen", "1.0.0.0")]
#if NET5_0_OR_GREATER
#endif
private void InitializeComponent()
{
global::Microsoft.Maui.Controls.Xaml.Extensions.LoadFromXaml(this, typeof(MoreOptionsPopup));
}
}
}
I tried building the project and closing VisualStudio, switching branches. I must oversee something but I don't know what and where.
I appriciate the help.
So, I tested your code. Now I am 100% sure everything is ok.
(I trust you have .UseMauiCommunityToolkit() in your MauiProgram.cs)
Most people forget to set Build Actions of their XAML file. You can:
Right click on XAML > Properties > Build Action MauiXaml.
Remove the file from the project and re-add it. (It will default to that build action)
I copied your code to my app and did a test on my android emulator, but it works well on my side.
You can try to delete the bin folders and the obj folders and rebuild it. If it doesn’t work,try to restart the Visual Studio.
Or you can create a new demo and copy your code to this new demo and try again.

Add EventListener to WPF control defined in Generic.xaml [duplicate]

I have a WPF control ParentWPFControl from a third party that I would like to inherit from (let's call the child class ChildWPFControl). In the process, I plan to override some of the back-end logic and parts of the front end styles. I can do the former just fine but I have problems doing the latter.
I attempt to use a xaml <-> xaml.cs structure for the child country, but that appears to be not allowed with the following warning from VS:
Partial declarations of 'ChildWPFControl' must not specify different base classes
Now, I suppose I can write a ResourceDictionary XAML and define the front end there, but that becomes a problem if I want to add event handlers to the XAML (at least I couldn't find a way to do that)
Another alternative I have is to define the override template directly in the objects that use the ChildWPFControl but that makes the design less modular.
A final alternative I can think of is to make a xaml <-> xaml.cs pair that is a XAML style container and then force the ChildWPFControl to use the ControlTemplate defined within through the back end event handler.
Anyway, what I am looking for is an elegant and modular solution for my problem. Any advice would be welcomed.
Thanks
There are a couple of steps necessary to completely override a WPF Control. Some are necessary some are optional depending on your needs. I will explain the two important ones for you:
Creating a new default style
Every WPF control has somewhere a default style which contains it visual representation and override properties. Now if you derive from control WPF still thinks you want to use this default style, to change that you change the DefaultStyle in a static constructor like this
class MyButton : Button
{
static MyButton()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(MyButton), new FrameworkPropertyMetadata(typeof(MyButton)));
}
}
Now if you use MyButton WPF tries to find a Style for MyButton, not for Button. OverridesDefaultStyle is a property in a style which might also be handy at some points. Usually these default styles should be placed in a theme related xaml.
Event Handlers when overriding classes
It is correct in a ControlTemplate or Style you can't use the syntactic sugar of using event like Click="OnClick". The point is, that the visual representation is decoupled from the logic part as much as possible. There are other ways though to overcome this, using the OnApplyTemplate method. By overriding this you ask the template "Give me this control" and then you just add your events there.
override OnApplyTemplate()
{
var innerChild = Template.FindName("PART_InnerChild", this) as MyInnerControl;
if(innerChild != null)
innerChild.SomeEvent += OnSomeEvent;
}
Note: The name of these controls usually begin with a PART_ by convention, this can be seen in WPF basic controls aswell. Its a nice way to tell the designers "Without this control, the logic part might break". There is also the attribute TemplatePart but it is not really important, WPF doesn't care about it. AFAIK Expression blend does some with it, personally i use it to tell other people what kind of inner controls are absolutely necessary to make this control work.
Personal advice
Deriving from a class is usually the last step we do when trying to customize controls. Because a lot of work is necessary to fully make it work and it can be limiting in reusability, we try to avoid it, for example a good alternatives are besides template overriding and styling; attached behaviors.
Lastly,
The whole subject is covered in a nice MSDN article.
Hope that helps
You can create your user control as wrapper, containing base control. In this way you can change styles in xaml add some logic in C# for wrapped contrоl. But it's tediously process.
Edit:adding sample(wrapper for telerik:RadComboBox )
XAML:
<UserControl x:Class="Controls.SingleDictionaryValueSelector"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:CardControls="clr-namespace:Controls"
xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation" MinWidth="150" MinHeight="25" >
<Grid >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="25"></ColumnDefinition>
</Grid.ColumnDefinitions>
<!-- customize visual for wrapped control -->
<telerik:RadComboBox x:Name="cb"
Grid.Column="0"
VerticalAlignment="Center"
SelectedValuePath="Key"
ClearSelectionButtonContent="Clear"
ClearSelectionButtonVisibility="Visible"
CanAutocompleteSelectItems="True"
CanKeyboardNavigationSelectItems="True"
SelectAllTextEvent="None"
OpenDropDownOnFocus="false"
IsFilteringEnabled="True"
TextSearchMode="Contains"
EmptyText="Select item"
telerik:StyleManager.Theme="Metro"
FontFamily="Calibri"
FontSize="14"
IsEditable="True"
Foreground="#666"
KeyDown="cb_KeyDown"
SelectionChanged="cb_SelectionChanged"
GotMouseCapture="cb_GotMouseCapture"
DropDownOpened="cb_DropDownOpened"
KeyUp="cb_KeyUp">
<telerik:RadComboBox.ItemTemplate>
<DataTemplate>
<TextBlock TextWrapping="Wrap" Width="{Binding RelativeSource={RelativeSource AncestorType=telerik:RadComboBox},Path=ActualWidth}" Text="{Binding Path=Value}" />
</DataTemplate>
</telerik:RadComboBox.ItemTemplate>
</telerik:RadComboBox>
<CardControls:ErrorInfo x:Name="errorInfoControl" Grid.Column="1" Visibility="Hidden"></CardControls:ErrorInfo>
</Grid>
</UserControl>
CS:
public partial class SingleDictionaryValueSelector : IMyCustomInterface
{
....
private void cb_KeyDown(object sender, KeyEventArgs e)
{
RadComboBox senderCombo = sender as RadComboBox;
...
}
private void cb_KeyUp(object sender, KeyEventArgs e)
{
SearchExecute();
}
private void cb_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
{
RadComboBox senderCombo = sender as RadComboBox;
...
}
private void cb_DropDownOpened(object sender, EventArgs e)
{
...
}
...
}
It looks like you have your inheritance mixed up more than that it is not allowed. Your root element of your xaml must match the base class of your xaml.cs.
If you are defining the base class in the same project, you will not be able to use it as the base class in the xaml, because it itself is still xaml and not a compiled control yet. Some ways to solve this: You can compile it in a seperate project and reference it, you can compile the base class entirely in .cs instead of a partial class, or you can use some style wizardry. Here is a link with examples of the last two: http://svetoslavsavov.blogspot.ca/2009/09/user-control-inheritance-in-wpf.html

How to open Page1.xaml into MainWindow.xaml

I have what should be a very simple desktop application I'm working on but I'm having issues doing a few basic tasks. I'm using Visual Studio 2013.
I have created a project from a blank WPF template. I created a new Page, named Page1.xaml, to go along with the default MainWindow.xaml Window.
In my MainWindow.xaml window I have Grid and inside the grid is an Image.
<Grid MouseDown="Grid_MouseDown_1" Cursor="Hand" >
<Image Name="ImageIntro" Source="images/Stories-intro.jpg" Stretch="None" />
</Grid>
The Grid has a MouseDown event so that I can detect when a user clicks anywhere inside the Grid.
private void Grid_MouseDown_1(object sender, MouseButtonEventArgs e)
{
}
Pretty basic and that all works and compiles as intended.
The issue I have is that I'm unable to load the Page1.xaml inside my window on MainWindow.xaml. I don't want to open a separate window, I just want the content on Page1.xaml to be displayed inside the visible window of MainWindow.xaml.
I tried using the following but I get an error when I click the on my link: An unhandled exception of type 'System.NullReferenceException' occurred
private void Grid_MouseDown_1(object sender, MouseButtonEventArgs e)
{
Uri uri = new Uri("Page1.xaml", UriKind.Relative);
NavigationService ns = NavigationService.GetNavigationService(this);
ns.Navigate(uri);
}
This is not a browser application, it's simply a desktop application. The first screen (MainWindow.xaml) should just click thru to display the second screen (Page1.xaml).
I want the Page1.xaml content to take up the entire Window of MainWindow.xaml (sorry, but I can't stress that enough, I don't want a frame or any content from MainWindow.xaml showing when the user is on Page1.xaml).
I'm pretty new to Desktop apps but I have extensive knowledge with .Net C# for web applications. I'm not against changing the flow of what I have if there's a better way to accomplish this. For example, perhaps I shouldn't be using a Window to Page navigation and should instead use a Window to Window or something else.
I would imagine this would be a relatively simple task, but I haven't found anything that works yet so hopefully someone on here can explain it.
create a frame in Main Window
then in your event hander
Page1 mypage=new Page1();//object of the page 1
frame.Navigate(mypage);//pass it to frame navigate method
Read this MSDN link, the requirements for that to work say that this (in your code) must be a Frame. I don't see any XAML code here, but I'm guessing this is a Window. You need a frame to host the navigation, so your MainWindow should probably just the frame, and the contents of your current window should be "Page0".
Thanks Everyone who helped, here is the solution I used (I wanted to make sure a code example was here for anyone who has this same issue in the future).
I added a Frame to my MainWindow.xaml page:
<Grid MouseDown="Grid_MouseDown_1" Cursor="Hand" >
<Image Name="ImageIntro" Source="images/Stories-intro.jpg" Stretch="None" />
<Frame Name="Frame1" Content="" HorizontalAlignment="Left" VerticalAlignment="Top"/>
</Grid>
Then I added the following to my event:
private void Grid_MouseDown_1(object sender, MouseButtonEventArgs e)
{
Page1 mypage = new Page1();
Frame1.Navigate(mypage);
}
This allowed me to click on my link and the new page, Page1.xaml appeared. There was also a navigation bar that appeared at the top and the content didn't completely take up the MainWindow.xaml window but I think I can fiddle around with the settings and get it to where I want it.
Much thanks to Filippo B, Nauman Ahmad, and CodingGorilla for the assist.

Open referenced control in a new window

Issue
I want to load a referenced control from the main window into a new window. The referenced control is already child of the main window, causing the following exception when attempting to render the new window:
System.ArgumentException was unhandled:
Must disconnect specified child from current parent Visual before attaching to new parent Visual.
I do not want to disconnect it from the main window and I also cannot create a new instance of the control since I do not know how it's instantiated or what members are applied.
Background
I'm developing an application that allows developers to extend the application with additional views of configuration options. The container of these views may turn out to be too small for large view extensions (imagine a scheduling control for agendas as example), so I wish to provide the user with the ability to open the extended view in a new window.
Code
So far I've created a behavior to attach to Hyperlinks that opens a new window with the referenced control upon the Click event. The following code is the most basic implementation to demonstrate my intention:
public class ExpandViewBehavior : Behavior<Hyperlink>
{
public static DependencyProperty ViewProperty = DependencyProperty.Register("View", typeof(object), typeof(ExpandViewBehavior));
public object View
{
get { return GetValue(ViewProperty); }
set { SetValue(ViewProperty, value); }
}
protected override void OnAttached()
{
this.AssociatedObject.Click += AssociatedObject_Click;
}
void AssociatedObject_Click(object sender, RoutedEventArgs e)
{
if (View != null)
{
var window = new Window()
{
Content = View
};
window.Show();
}
}
}
Attached to a Hyperlink in the main window, referencing a simple TextBox to load in the new window. Where i is the System.Windows.Interactivity namespace and local my project namespace.
xmlns:local="clr-namespace:WpfApplication"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
...
<StackPanel>
<TextBlock>
<Hyperlink>
<i:Interaction.Behaviors>
<local:ExpandViewBehavior
View="{Binding Source={x:Reference SomeControl}}" />
</i:Interaction.Behaviors>
<TextBlock
Text="(Open in new window)" />
</Hyperlink>
</TextBlock>
<TextBox
x:Name="SomeControl" />
</StackPanel>
My question is, is there is a way to load the referenced control without disconnecting it from the main window?
As you can't display the same control in two places at once, you will either need to disconnect the control from the main window (as noted in the error text), or create a copy of the control to place into the child window.
You can clone the control by exporting its XAML, and then create a new control from this XAML.
See this answer How can you clone a WPF object? for more details.

Silverlight + MVVM + Bindings = Memory leaks?

Thus far, my testing has shown that all standard approaches, examples, and frameworks leveraging the MVVM pattern in silverlight suffer from a huge problem: massive memory leaks which prevent VMs from being garbage collected.
Obviously this is a huge and ridiculous claim - so my expectation is that someone will have an obvious answer of why and where I'm going wrong :)
The steps to reproduce are simple:
Bind your viewmodel to a view by setting the views datacontext to the VM (assume the viewmodel leverages INotifyPropertyChanged to support data binding)
Bind a UI element to a property on the viewmodel, for example:
<TextBox Text="{Binding SomeText}" />
Leverage the binding in some way (for example - just type in the textbox).
This creates a reference chain that extends from the root, to a BindingExpression, to your viewmodel. You can then remove the View from your UI tree, as well as all refernences to the VM - however the VM will never be garbage collected thanks to the root<>BindingExpression<>VM reference chain.
I have created two examples illustrating the problem. They have a button to create a new view/viewmodel (which should dump all references to the old one(s)) and a button which forces garbage collection and reports on the current memory usage.
Example 1 is a super stripped down caliburn micro example. Example 2 uses no frameworks and just illustrates the problem in the simplest way I could think of.
Example 1
Example 2
For those who might like to help but don't wish to download the example projects, here is the code for example 2. We start with a viewmodel called FooViewModel:
public class FooViewModel : INotifyPropertyChanged
{
string _fooText;
public string FooText
{
get { return _fooText; }
set
{
_fooText = value;
NotifyPropertyChanged("FooText");
}
}
private byte[] _data;
public FooViewModel()
{
_data = new byte[10485760]; //use up 10mb of memory
}
private void NotifyPropertyChanged(String info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
It simply exposes a string property called FooText which we will bind too. INotifyPropertyChanged is neccessary to facilitate the binding.
Then we have a view called FooView which is a usercontrol containing:
<UserControl x:Class="MVVMLeak.FooView">
<StackPanel x:Name="LayoutRoot" Orientation="Horizontal">
<TextBlock Text="Bound textbox: " />
<TextBox Text="{Binding FooText}" Width="100"/>
</StackPanel>
</UserControl>
(namespaces omitted for brevity)
The important bit here is the textbox which is bound to the FooText property. Of course we need to set the datacontext, which I've chosen to do in the codebehind rather than introduce a ViewModelLocator:
public partial class FooView : UserControl
{
public FooView()
{
InitializeComponent();
this.DataContext = new FooViewModel();
}
}
MainPage looks like this:
<StackPanel x:Name="LayoutRoot" Background="White">
<Button Click="Button_Click" Content="Click for new FooView"/>
<Button Click="Button2_Click" Content="Click to garbage collect"/>
<ContentControl x:Name="myContent"></ContentControl>
</StackPanel>
with the following in the code behind:
private void Button_Click(object sender, RoutedEventArgs e)
{
myContent.Content = new FooView();
}
private void Button2_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show("Memory in use after collection: " + (GC.GetTotalMemory(true) / 1024 / 1024).ToString() + "MB");
}
Note: To replicate the problem, be sure to type something in the textbox, as I believe the Binding Expression isn't created until it's needed.
It's worth noting that this KB article may be related, however I'm not convinced since 'method 2' workaround doesn't seem to have an effect, and the reference chain doesn't seem to match.
Also, I'm not sure it matters, but I used CLR Profiler to diagnose the cause.
Update:
If anyone would like to test, and report their findings in a comment, I'm hosting the silverlight application via dropbox here: Hosted Example . To reproduce: Hit the top botton, type something, hit the top button, type something, hit the top button. Then hit the button. If it reports 10MB usage (or perhaps some other amount that is not increasing), you are not experiencing the memory leak.
Thus far, the problem seems to be happening on ALL of our development machines, which are ThinkPad w510 (43192RU) with 12GB Ram, 64 bit Win 7 Enterprise. This includes some which have not had development tools installed. It might be worth noting that they are running VMWare workstation.
The problem does NOT seem to happen on other machines I have tried - including several home PCs and other PCs in the office. We have somewhat ruled out SL versions, amount of memory, and probably vmware. Still haven't nailed down a cause.
A solution is yet to be found, however the problem is now identified. This behavior will occur if Silverlights' automation faculties are invoked due to:
Tablet PC Input Service (in other words, all 'tablet like' PCs)
Automated Testing tools
Screen Readers (and other accessability software)
More information here: http://www.wintellect.com/cs/blogs/sloscialo/archive/2011/04/13/silverlight-memory-leaks-and-automationpeers.aspx
So a new problem surfaces: How do we disable automationpeers or otherwise get them to clean-up correctly?
This post illustrates one approach: WPF UserControl Memory leak
However, it isn't really a viable solution as we'd have to override every silverlight control which we plan to use binding for, not to mention the control templates of complex controls.
I will change my answer if anyone can identify a good solution, but for now there doesn't seem to be one...
Edit:
Here is a nice little workaround which seems to do the job. Simply add the following parameter in your HTML where you define the silverlight object:
<param name="windowless" value="true" />
A side-effect of running in 'windowless' mode is that automation doesn't work :)
There is no memory leak in your second example.
After you affect a new FooView instance to your ContentControl using myContent.Content = new FooView();, there is no more used reference to the whole View + ViewModel object graph.
It'll be garbage-collected when needed, eventually.
Maybe you should clarify about what make you think there is a memory leak (i.e. statistics, repro steps...etc.)

Categories

Resources