WPF memory allocation leaps using binding, inotifypropertychanged and dependency property - wpf

I'm writing a program that uses a bunch of two-way bindings and the amount of memory used has become a huge problem. In my full application, I start at 50Mb, and then, just by using the bindings (i.e. changing the value on one side and letting the binding update the other side), I usually break 100Mb, even though my code has not allocated anything new. My question is what this extra memory is and what I can do to control it. I have created a simple, reproducible example below:
Say I have a main window with the following contents:
<StackPanel Height="25" Orientation="Horizontal">
<TextBox UndoLimit="1" Name="TestWidth" />
<Label>,</Label>
<TextBox UndoLimit="1" Name="TestHeight" />
</StackPanel>
And then in this window's constructor, I generate a new window, show it, and then bind it's WidthProperty and HeightProperty dependency properties to variables that utilize INotifyPropertyChanged:
public partial class MainWindow : Window, INotifyPropertyChanged
{
private int _WidthInt;
public int WidthInt
{
get { return _WidthInt; }
set { _WidthInt = value; NotifyPropertyChanged("WidthInt"); }
}
private int _HeightInt;
public int HeightInt
{
get { return _HeightInt; }
set { _HeightInt = value; NotifyPropertyChanged("HeightInt"); }
}
public MainWindow()
{
InitializeComponent();
Window testWindow = new Window();
testWindow.Show();
Binding bind = new Binding("HeightInt");
bind.Source = this;
bind.Mode = BindingMode.TwoWay;
testWindow.SetBinding(Window.HeightProperty, bind);
//bind.Converter = new convert();
//this.TestHeight.SetBinding(TextBox.TextProperty, bind);
bind = new Binding("WidthInt");
bind.Source = this;
bind.Mode = BindingMode.TwoWay;
testWindow.SetBinding(Window.WidthProperty, bind);
//bind.Converter = new convert();
//this.TestWidth.SetBinding(TextBox.TextProperty, bind);
}
public event PropertyChangedEventHandler PropertyChanged;
protected void NotifyPropertyChanged(string sProp)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(sProp));
GC.Collect();
}
}
Then if I constantly resize the window, my memory usage in the task manager linearly increases with no apparent upper limit. The program starts at 17Mb, and within 30 seconds of resizing it increases to 20Mb and hovers after a certain point in the low 20's (thanks Ian). This actually happens even if there are no bindings, and the memory does not go back down. While annoying, this isn't the "memory leap" I'm talking about.
If I uncomment the lines that also bind the textboxes to the variables, I get the following result: in just a few seconds it jumps from 18Mb to 38Mb and then hovers there (Please note setting the binding for the textbox in the XAML does not affect the memory spike). I tried implementing my own converter for the text box binding, but this does not affect the memory usage.
The jump still exists if I change the variables to new dependency properties and bind to them, e.g.
public static readonly DependencyProperty WidthIntProperty = DependencyProperty.Register("WidthIntProperty", typeof(int), typeof(MainWindow), new UIPropertyMetadata(0, null));
int WidthInt
{
get { return (int)this.GetValue(WidthIntProperty); }
set { this.SetValue(WidthIntProperty, value); }
}
...
Binding bind = new Binding("Text");
bind.Source = TestHeight;
bind.Mode = BindingMode.TwoWay;
this.SetBinding(MainWindow.HeightIntProperty, bind);
testWindow.SetBinding(Window.HeightProperty, bind);
or if I bind directly between the text property and the width dependency property and use BindingMode.OneWay or vise versa.
Using a CLR profiler does not seem to show me what's being allocated and I don't have access to a commercial memory profiler. Can someone explain to me what is being kept in memory and how I can get rid of it while still having the functionality of a continuous BindingMode? Do I have to implement my own binding method and do the event handling myself? Or is there something I can regularly flush outside of the GC?
Thank you for your time.

One thing to remember with simple programs like this is that a small amount of code can end up hitting a fairly large amount of WPF's infrastructure. E.g., with a single TextBox you're using the layout engine, the property engine, the templating system, the styling system, and accessibility features. The moment you start to type, you also bring in the input system, the typography support, and some non-trivial internationalization infrastructure.
Those last two may well be a large part of what you're seeing in this particular example. WPF automatically exploits a lot of OpenType font features, which requires it to do a lot of work under the covers. (As it happens the default UI font doesn't actually do a lot with it, but you still end up paying the price of entry for the code that discovers that Segoe UI is not a very interesting typeface.) It's a comparatively expensive feature for saying how subtle a difference it makes. Likewise, it's amazing how much goes into locale-aware input handling - getting that comprehensively right with full i8n support is more work than most people imagine.
You'll probably pay the price for each of these subsystems eventually, because the TextBox is not the only piece of WPF to use them. So the effort required for hand-built solutions that attempt to avoid them may ultimately be for nothing.
Tiny test applications paint a misleading picture - in a real application the price payed is shared out a bit better. Your first TextBox might have cost your 30MB, but you've now paged in a load of stuff that the rest of your application was going to use anyway. Had you started with an application that uses nothing but a ListBox, you could then add a TextBox and compare the difference in memory consumption to the ListBox-only baseline. This would probably give you a rather different picture of the marginal cost of adding a TextBox to your application.
So outside of the context of a trivial test application, the effort required to write your own text box is likely to produce very little difference in private working set in practice. You'll almost certainly end up paging in all of the features and systems I mentioned in the first paragraph eventually, because TextBox is not the only thing in WPF to use them.
Could each of these systems be more frugal? No doubt they could, but sadly, WPF hasn't had as much engineering input as I'd like, what with the distraction that is Silverlight, not to mention the rumours that yet another attempt at a UI framework is coming in Win8... High memory usage is, unfortunately, a feature of WPF. (Although bear in mind that a WPF app will also tend to use more memory on a machine with more memory. It takes some memory pressure before its working set gets driven to its most efficient level.)

I'm really embarrassed about this... I thought I had checked everything and tried as many approaches as I could think of, but I didn't think the memory spike was from the TextBox itself. That's what causes the spike. If you remove all of the bindings and fluff and just have the TextBoxes, even with their UndoLimit set to zero and limiting the MaxLength, the program's memory still spikes by 15Mb+ after a dozen or so edits of the TextBox's contents. So because the bindings also updated the Textbox, they triggered this spike. I know default controls have to cover a wide variety of uses, but as my first C#/WPF program, I didn't realize how bloated they actually are in this case. I'm off to write my own TextBox Control and to remind myself to never assume too much when it comes to this. But hey, at least I can put my custom binding code to the side now!

Related

In a constructor for a WPF Window, what should go before InitializeComponent() and what after?

In general, I've been initializing the properties of the Window itself before InitializeComponent() and setting up controls contained within afterwards. However, I haven't been all that consistent, and I haven't really noticed a problem with the ordering. So:
Am I (potentially) doing something horrible? In particular, are there any issues with setting properties of child controls before InitializeComponent()?
What is good style in this regard?
Edit: Since the first two answers I got were a little bit contradictory, let me be more specific:
public Foo Foo {get; protected set}
public FooWindow (Foo foo)
{
Foo = foo;
this.Closing += FooWindow_Closing;
Foo.Frobbed += Foo_Frobbed;
InitializeComponent();
this.DataContext = this;
this.Title = Foo.Name() + " Window";
FooListView.ItemSource = Foo.CalculateList();
FocusManager.SetFocusedElement(this, FooListView);
}
Is this about right? Should I just be doing MVVM and not have anything in my Window constructor?
By calling InitializeComponents after some other code you run the risk of accidentally overwriting properties with things that were set in the XAML or of using an uninitialized object. Usually the code-behind is a higher priority than the XAML so I would leave InitializeComponents (aka, parse and load the XAML) at the top.
In answer to your specific questions:
Am I (potentially) doing something horrible? In particular, are there any issues with setting properties of child controls before InitializeComponent()?
Chances are that your child controls aren't available to you in code yet until you've called InitializeComponents. It would generally be bad form to do this.
What is good style in this regard?
This is going to be a matter of taste, but generally I would recommend that if you're going to take advantage of the separation that XAML affords you then I would take it as far as you can. If you're doing things that are logically about the UI try to do it in XAML. This isn't so much an MVVM thing as it is a separation of presentation from logic. Most of what you have in your sample code can be done declaratively, even if just through ValueConverters.
E.g if Foo was a DependencyProperty then you could also attach it in XAML and add the callbacks as part of the ValueChanged callback. Again, this isn't MVVM, but it is pretty fundamental to WPF.
For most other things, you actually probably want to wait until OnLoaded is called, rather than doing the work in the constructor.
Hope that helps,
I usually call anything that does not require the Visual Tree before I call InitializeComponent().
All of my implementations use the MVVM pattern, so I prefer to have my ViewModel instantiated and populated before the UI is loaded to the client.
If you always load InitializeComponent() first, you run the risk of creating a bad user experience by showing an unpopulated view that suddenly updates versus one that is populated when it comes into view.

Implementing Telerik VirtualQueryableCollectionView with MVVM pattern

I have an application that was implemented using the Telerik RadGridView control and Caliburn.Micro MVVM framework. Because of some performance problems, I needed to implement the Telerik VirtualQueryableCollectionView in place of the direct control-to-ObservableCollection binding that was being used. The original code has the ItemsSouce property of the RadGridView was bound to the Prices property of the view model. I had to eliminate that binding and this in the code-behind:
public PricingView(PricingViewModel vm)
{
InitializeComponent();
var dataView = new VirtualQueryableCollectionView()
{ LoadSize=20, VirtualItemCount = vm.Prices.Count };
dataView.ItemsLoading += (sender, e) =>
{
var view = sender as VirtualQueryableCollectionView;
if (dataView != null)
{
view.Load(e.StartIndex, vm.Prices.Skip(e.StartIndex).Take(e.ItemCount));
}
};
this.PricesGridView.ItemsSource = dataView;
}
Since this code only deals with UI specific functionality and it is specific the the view implementation, I am comfortable that this code belongs in the code-behind rather than the ViewModel as it would be a departure from ther MVVM pattern to put a reference to VirtualQueryableCollectionView in the ViewModel. The part that I am not happy with is passing the reference to the ViewModel into the constructor of the View. Is there a good way to get the reference in the code-behind without having to pass the reference in the constructor?
Or is there a better way to do all of this?
My application is implemented with MVVM Light, in my case I used the VirtualQueryableCollectionView class in the ViewModel instead the View.
I did so because I think this class is very similar to the ObservableCollection although it is not part of the core classes.
Actually, VirtualQueryableCollectionView is not limited to the Telerik controls but many other standard controls like the ListView.
The fetch is in my case implemented in the Model.
void MainViewModel()
{
this.Traces = new VirtualQueryableCollectionView<MyEntityClass>()
{
// ViewModel also manages the LoadSize
LoadSize = this.PageSize,
VirtualItemCount = myModel.TotalCount
};
this.Traces.ItemsLoading += (s, args) =>
{
this.Traces.Load(args.StartIndex,
myModel.FetchRange(args.StartIndex, args.ItemCount));
};
}
Not sure what "performance problems" means, but I'm going to assume that means that when you fill the collection from the UI thread it blocks the application long enough it appears unresponsive.
There are two common solutions for this. First is to simply fill your collection from a background thread.
The naive implementation is to simply push the loading onto a ThreadPool thread, then use the Dispatcher to marshall the calls to add items to the ObservableCollection onto the UI thread.
A nicer approach (one that doesn't involve the ViewModel at all) is to use asynchronous bindings. You configure the fallback to some value that indicates to the user you are loading. Sometimes (depending on the situation) you can use a PriorityBinding to gradually fill your UI.
Other alternatives are to load and cache your data beforehand while displaying a splash screen. They're a bit different in WPF, it isn't like the old "display this form for a bit while I do work, then show the main form" mode of winforms. And, of course, there is always the classic data pagination. Its tough to code, but effective. Actually, I should say its tough in the UI. Its easy now in code (database.Skip(pageNumber * pageSize).Take(pageSize)).

StatusBar not always updating

I am relatively new to MVVM, and I am trying to code up a basic Status Bar for an MVVM WPF application. I think I have the gist of things, but for some reason, the status bar does not always update, and I am not sure why.
In my ViewModel, I have a basic property that I update when I change a status message:
public string StatusMessage
{
get { return _statusMessage; }
set
{
if (value == _statusMessage) return;
_statusMessage = value;
base.OnPropertyChanged(() => this.StatusMessage);
}
}
My OnPropertyChanged method (which I have in a base ViewModel class that implements INotifyPropertyChanged) looks like so (got this idea from Gunther Foidl; wish I could claim credit for it because I think it's slick but I'm not quite that smart):
protected virtual void OnPropertyChanged<T>(Expression<Func<T>> exp)
{
MemberExpression me = exp.Body as MemberExpression;
string propName = me.Member.Name;
PropertyChangedEventHandler handler = this.PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propName));
}
}
At any rate, this all works great for all of my controls except one. On my MainWindow.xaml file, I have a StatusBarItem control bound to the above property, like so (the rest of the XAML has been trimmed for space reasons):
<StatusBarItem Grid.Column="0">
<TextBlock TextTrimming="CharacterEllipsis" Text="{Binding Path=StatusMessage}" />
</StatusBarItem>
When I run my application (which hits a couple of DBs in addition to generating a document from template and a bunch of other fairly resource-intensive stuff), some, but not all, messages show up on the status bar. I have debugged and verified that the messages all make it into the StatusMessage property, above (and the ensuing private variable), they just don't seem to be refreshing in the UI.
I have looked at several examples that use BackgroundWorker instances for ProgressBar controls, but haven't seen any for StatusBarItem controls, and am not really sure how to translate one to the other.
I have also used Tasks before in previous C# 4.0 and WPF apps, and figure it's probably a good way to go, but I haven't really been able to figure out how/where to designate the UI task (I've always done it in the code-behind for the MainWindow before, but I'm striving for a zero-code-behind to stay in keeping with MVVM here).
I'm pretty sure that a multi-threaded approach is the way to go; I just don't know enough about one approach (I know a little bit of this and a little bit of that) to make it work. I did see a couple of posts that used the older threading approach directly, but I pretty much stayed away from multithreading programming until I started using Tasks with .NET 4.0 (finding them a little easier to comprehend and keep track of), so I had a bit of trouble making sense of them.
Can anyone take pity on me and point me in the right direction, or suggest further debugging I can do? Thanks!
1)Reflection based binding can be source of error sometimes because of inlining. Try to see what happens if you notifypropertychanged with simple string instead of reflection.
2) if you are using multi threads there maybe a chance that you setup StatusMessage not from UIThread in that case it won't be able to update UI, you could invoke setter code on UI Dispatcher to see if that helps
3) check whether binding works , in constructor of xaml form modify StatusMessage directly on VM and see whether the change is shown on UI without invoking multithreaded service calls which introduce additional variables to simple textblock - string binding
4) if that doesn't help you could create a simple xaml form with single textblock bind it to your big viewmodel and see what happens, if nothing works you can begin cutting VM class to make it simpler so binding eventually starts to work and you find an error
5) if you think that statusbar is the problem see if single textblock without statusbar (extract xaml part from your example) works
Somewhere the notification does not get through.
I would try :
Add a dummy valueconverter on the textbinding so you can set a breakpoint and see if you are called
Dispatching the property set to set the value at a "better" time - that is sometimes nessesary.
Dispatching the set might do the trick.

Force binding in WPF

I'm writing tests which will check correctness of Binding elements specified in XAML. They work so far, the only issue is that I do not know how to correctly force databinding to happen. Surprisingly it is not enough to simply set something in DataContext, binding won't happen until you show your control/window. Please not that I'm writing 'unit'-tests and I'd like to avoid showing any windows.
Take a look at following code:
// This is main class in console application where I have all WPF references added
public class Program
{
[STAThread]
public static void Main()
{
var view = new Window();
BindingOperations.SetBinding(view, Window.TitleProperty, new Binding("Length"));
view.DataContext = new int[5];
//view.Show(); view.Close(); // <-- this is the code I'm trying not to write
Console.WriteLine(view.Title);
}
}
Here I'm creating a Window and putting an array as DataContext to that window. I'm binding Window.Title to Array.Length so I expect to see number 5 printed in console. But until I Show window (commented line) I will get empty string. If I uncomment that line then I will receive desired 5 in console output.
Is there any way I can make binding happen without showing a window? It is pretty annoying to look at ~20 windows while launching tests.
P.S.: I know I can make windows more transparent and etc, but I'm looking for more elegant solution.
UPDATE Code above is simplified version of what I really have. In real code I receive a View (some UIElement with bindings) and object ViewModel. I do not know which exactly binding there were set on View, but I still want all of them to be initialized.
UPDATE 2: Answering to the questions regarding what I test and I why. I do not intend to test that classes like Binding, BindingBase, etc are working as expected, I assume they are working. I'm trying to test that in all my XAML files I have written bindings correctly. Because bindings are stringly typed things, they are not verified during compilation and by default they cause only errors in output window, which I'm missing occasionally. So if we take my example from above and if we will made a typo there in binding: {Binding Lengthhh} then my tests will notify you that there is no property with name Lengthhh available for binding. So I have around 100 XAML files and for each XAML I have a test (3-5 lines of code) and after launching my tests I know for sure that there are no binding errors in my solution.
The bindings are updated by the dispatcher with the DispatcherPriority.DataBind - so if you wait for a dummy task with SystemIdle priority you are sure that any pending databinding is done.
try
{
this.Dispatcher.Invoke(DispatcherPriority.SystemIdle, new Action(() => { }));
}
catch
{
// Cannot perfom this while Dispatcher in suspended mode
}
If you are trying to test correctness of your view, I suggest you test your view :-)
Why not run the UI from a unit test and write code that checks content of UI after changing data.
VS2010 does have GUI testing, or you could take a look at the code of tools such as Snoop.
Edit following comment:
If ALL you want to do is test a few simple bindings, try writing a static code test that runs as a post build event using reflection on view models and regular expressions on XAMLs. Add attributes on VM or use a config file so your test will know which view receives which View Model as DataContext. Compare property names and types in View Models with binding strings in View (automatically search XAML for these) and throw exception (thus failing build) if strings do not match.
If your bindings are more complex (converters, multibindings, ...) this may be a bit more complicated to implement.
I think you should first set the DataContext and then do the Binding, e.g.:
view.DataContext = new int[5];
BindingOperations.SetBinding(view, Window.TitleProperty, new Binding("Length"));
I'm not sure if this is real solution for your general problem, but it works in this case.
I don't believe the Window's bindings will run without calling Show or ShowDialog, because that is the only way it gets associated with the UI message loop/dispatcher.
Your best bet would be to set it to be as least visible as possible, potentially using an extension method to clean things up:
public static void PokeWindowDispatcher(this Window window)
{
window.WindowState = WindowState.Minimized;
window.ShowInTaskbar = false;
window.Visibility = Visibility.None;
using (var wait = new ManualResetEvent())
{
Action<object, RoutedEventArgs> loaded = (sender, e) => wait.Set();
window.Loaded += loaded;
try
{
window.Show();
wait.WaitOne();
}
finally
{
window.Loaded -= loaded;
window.Close();
}
}
}
I had the same problem, and from sixlettervariables gave me an idea. It's very simple.
I am using WPF in WinForms application, so I use ElementHost control to host Wpf controls on WinForms control. To enforce WinForms control initialization you can just read value of Handle (which is actually Windows HWND) and this will force control to fully initialize itself including child ElementHost and all Wpf binding work.
I didn`t try to perform the same thing for pure Wpf control. But you can easily use ElementHost to initialize your Wpf controls like this:
var el = new ElementHost();
var p = new TextBlock();
p.DataContext = new { Data = "1234" };
p.SetBinding(TextBlock.TextProperty, "Data");
el.Child = p;
var t = el.Handle;
Debug.Assert(p.Text == "1234");
PS: Found, that everything work better, if you first set DataContext and only then force a Handle to be created (just like my example). But, I think, this is already the case for you, so should not be a problem.
Have you tryed to use the IsDataBound
http://msdn.microsoft.com/en-us/library/system.windows.data.bindingoperations.isdatabound.aspx
Also check this out:
System.Windows.Interop.WindowInteropHelper helper = new System.Windows.Interop.WindowInteropHelper(view).EnsureHandle();
http://msdn.microsoft.com/en-us/library/system.windows.interop.windowinterophelper.ensurehandle.aspx
My other question is why you trying to do a UNIT test on something that has been technically tested already? By the way I am not critising, just want to understand a little better.
Not sure, but maybe something like this will work?
view.GetBindingExpression(Window.TitleProperty).UpdateTarget();

What is the worst gotcha in WPF?

I've started to make myself a list of "WPF gotchas": things that bug me and that I had to write down to remember because I fall for them every time....
Now, I'm pretty sure you all stumbled upon similar situations at one point, and I would like you to share your experience on the subject:
What is the gotcha that gets you all the time? the one you find the most annoying?
(I have a few issues that seem to be without explanation, maybe your submissions will explain them)
Here are a few of my "personnal" gotchas (randomly presented):
For a MouseEvent to be fired even when the click is on the "transparent" background of a control (e.g. a label) and not just on the content (the Text in this case), the control's Background has to be set to "Brushes.Transparent" and not just "null" (default value for a label)
A WPF DataGridCell's DataContext is the RowView to whom the cell belong, not the CellView
When inside a ScrollViewer, a Scrollbar is managed by the scrollviewer itself (i.e. setting properties such as ScrollBar.Value is without effect)
Key.F10 is not fired when you press "F10", instead you get Key.System and you have to go look for e.SystemKey to get the Key.F10
... and now you're on.
Always watch the output window for
binding errors. Ignoring the output
window is a recipe for tears.
Use PresentationTraceOptions.TraceLevel="High" in a binding to get verbose binding information when debugging binding failures.
Make static, unchanging resources such as brushes PresentationOptions:Freeze="True" to save resources at runtime.
Use the WPF DataGrid as a datagrid. Modifying it to behave like Excel is a massive pain in the butt.
BindingList<T> does not play well with CollectionViewSource. Expose ObservableCollection<T> from your viewmodels instead.
The internet supplies half a dozen different ideas for displaying CueBanner text in a WPF textbox. They are all broken.
1) One that used to get me every half an hour when I was making my transition from WinForms: use TextBlock instead of Label when putting random text on the UI (or don't use any tag at all, if the text is static)!
2) DataTriggers/Triggers can't be put into Control.Triggers, but have to go into Control.Styles/Style/Style.Triggers
3) Property's type must implement IList, not IList<T>, if the property is to be recognized by XAML as a collection property.
4) Bindings capture exceptions.
5) Use singleton converters/static converter class, so you don't have to create a new converter every time you use it.
6) A type for default value of DependencyProperty has to be clearly specified: 0u as uint, (float) 0 as float, 0.0 as double...
7) It matters if the control's property definitions are before or after its content.
8) NEVER use PropertyMetadata to set a default value of reference type DependencyProperty. The same object reference will be assigned to all instances of the owning class.
When first starting out, the main gotchas that would get me would be
Lists not updating due to forgetting
to use ObservableCollection
Properties not being updated either
forgetting to add OnPropertyChanged
or incorrectly typing the property
name
Recently I have stumbled across these issues
Application failing to start due to
corrupt font cache
StringFormat localization issues
If enabled, Button.IsCancel assigns false to Window.DialogResult but Button.IsDefault no.
They are so similar and for me it seemed intuitive at first that both should close dialog. I usually break MVVM and fix this in code-behind
Button.IsCancel + Command = Dialog won't close (Window.DialogResult left unassigned) but Command executes
As I understand it: If IsCancel had higher priority than Command then on Esc it would assign 'false' to DialogResult and Command won't be called. Or, if Command would have higher priority then it would be called first and DialogResult would be assigned. I don't understand how it is skipped?
Binding swallows exceptions!
It not only steals time while debugging it is also wrong from the OOP point of view because if exception is thrown it means that something exceptional had happened somewhere in our system (anything from wrong data supply to unauthorized access to memory failure) so it can be handled only if you know what to do. You can't just catch(Exception){} catch 'em all and then ignore. If there is unknown exception in program it should notify user, log and close not pretend like everything is ok...
HeaderContent can have only one child control and has no padding
Everything should have padding even logical controls (containers), right? I think it is inconsistent. What do you think?
If you set focus to ListBox via FocusManager.FocusedElement you still won't be able to switch it's content with keyboard because focus is set to ListBoxes frame not it's content. I think I don't know other UI API that would expose something like controls frame to UI programmer it should be encapsulated from us because abstractly ListBox represents a list, it is just a list of things not a list of things in a box. ok it has box in its name but still... We almost have two different controls here.
MVVM not breaking fix
ListBox.IsSynchronizedWithCurrentItem by default is false so if you assign different value or null to ItesSource then SelectedItem still holds old value until user selects something from a new list. It could mess up CanExecute for example. Need to set it every time by hand.
No binding exposed in PasswordBox results in time waste and dirty hacks... But still it has a string property PasswordBox.Password exposed so don't even try to argue about security because Snoop...
It is not a gotcha but table layout is so IE6 IMO. Container design helps separate content from its layout.
Because every time I need to change something in places I need to mess up with Grid.Row and Grid.Column. Yes, we have DockPanel, StackPanel and others but you can't do some column alignment inside of them. (And DockPanel is like completely separate gotcha) If UniformGrid would be more customizable it would be ideal I think. You always need to choose between Grid and Panels and usually if you gain something you loose something else.
I got a pretty nifty one last week:
When Templating a RichTextBox, the event handling inside the template follows a strange route that has nothing to do neither with tunnelling nor bubbling
e.g.: In the case of an event that is supposed to tunnel: the event first tunnels through the ContentPresenter, then it tunnels back from the top of the template.
see my question on the subject
ToolTips and ContextMenus not sharing the DataContext of its owner? I think that gets everyone at first
There is no clean way to handle validation in WPF, I am not a fan of magic string which IDataErrorInfo offers by default:
public string this[string columnName]
{
if (columnName == "FirstName")
{
if (string.IsNullOrEmpty(FirstName))
result = "Please enter a First Name";
}
}
However, I have tried many frameworks like SimpleMVVM, FluentValidation and MVVMValidation and BY FAR MVVM Validation is the best getting to do stuff like:
Validator.AddRule(() => RangeStart,
() => RangeEnd,
() => RuleResult.Assert(RangeEnd > RangeStart, "RangeEnd must be grater than RangeStart");
My personal favorite is this one:
public double MyVariable
{
get { return (double)GetValue(MyVariableProperty); }
set { SetValue(MyVariableProperty, value); }
}
public static readonly DependencyProperty MyVariableProperty = DependencyProperty.Register(
"MyVariable", typeof(double), typeof(MyControl), new UIPropertyMetadata(0));
Try it, once this property is declared it will crash. Why? Because 0 can't be assigned to a double using reflection apparently.
Not really a gotcha but an advice: Use Snoop or something similar, if you don't use it you must be crazy ... Crazy i tell ya!
Binding.StringFormat only works if the type of the target property is string.
TreeView's SelectedItem property is not settable. Instead you have to bind TreeViewItem's IsSelected property to your item's viewmodel and set your selection there.
ListBox's SelectedItem, on the other hand is settable, but item selection is not equal to item focus. If you want to implement proper keyboard navigation along with selecting items from within viewmodel, you have to implement manual focus fix, like:
public void FixListboxFocus()
{
if (lbFiles.SelectedItem != null)
{
lbFiles.ScrollIntoView(lbFiles.SelectedItem);
lbFiles.UpdateLayout();
var item = lbFiles.ItemContainerGenerator.ContainerFromItem(viewModel.SelectedFile);
if (item != null && item is ListBoxItem listBoxItem && !listBoxItem.IsFocused)
listBoxItem.Focus();
}
}
...and call it every time you change selected item from viewmodel:
SelectedFile = files.FirstOrDefault();
viewAccess.FixListboxFocus();

Resources