14

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):

  1. 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)

  2. A WPF DataGridCell's DataContext is the RowView to whom the cell belong, not the CellView

  3. When inside a ScrollViewer, a Scrollbar is managed by the scrollviewer itself (i.e. setting properties such as ScrollBar.Value is without effect)

  4. 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.

Community
  • 1
  • 1
David
  • 6,014
  • 4
  • 39
  • 55
  • 1
    This isn't really a question and therefore not suitable for a question and answer site. You are asking for a "List of X" and there's no one answer that's any more correct than all the others. – ChrisF Feb 10 '11 at 13:30
  • 3
    @ChrisF: In the form of a question... "What are some WPF gotchas?" and then mark it as community wiki. We have plenty of those types of questions. – sourcenouveau Feb 10 '11 at 13:41
  • 3
    @emddudley - a) only moderators can make questions CW now and b) it's still a "list of x" question and c) the rules have been tightened since most (if not all) of those questions were asked. – ChrisF Feb 10 '11 at 13:51
  • 2
    I personally found this kind of question rather enlightening. I learned a lot on this one for instance: http://stackoverflow.com/questions/241134/what-is-the-worst-gotcha-in-c-or-net and I thought it would be a good idea to have the same kind of knowledge base for WPF (there are a few such questions about other subjects). I reformulated the question so that it looks like a question, In case it was really just about the way the question was aksed. – David Feb 10 '11 at 16:22
  • 1
    The `Key.F10` thing isn't a "gotcha". It's how Windows works. The F10 key is used to set focus to the menu bar for keyboard users. If it's difficult to override, *hopefully* application developers won't mess with it. It's called a `SystemKey` for a *reason*, not just to trip you up. – Cody Gray - on strike Feb 11 '11 at 08:16
  • 1
    ah yes, but I don't think any "gotcha" is made to "trip me up" ;) I hope the guys at MS are not that evil... I'm just merely stating that It is very counter-intuitive when you handle keystrokes to have to go look for the F10 key at a completely different place than the other F keys (if you have to use the F10 key, which is my case, and don't blame me for this, I don't like this either) – David Feb 11 '11 at 08:37
  • Same a "Hidden Features" and "Worst interfaces" and all the rest of their ilk. – dmckee --- ex-moderator kitten Feb 11 '11 at 21:45

10 Answers10

14
  1. Always watch the Output window for binding errors. Ignoring the Output window is a recipe for tears.

  2. Use PresentationTraceOptions.TraceLevel="High" in a binding to get verbose binding information when debugging binding failures.

  3. Make static, unchanging resources such as brushes PresentationOptions:Freeze="True" to save resources at runtime.

  4. Use the WPF DataGrid as a datagrid. Modifying it to behave like Excel is a massive pain in the butt.

  5. BindingList<T> does not play well with CollectionViewSource. Expose ObservableCollection<T> from your viewmodels instead.

  6. The internet supplies half a dozen different ideas for displaying CueBanner text in a WPF TextBox. They are all broken.

Mustafa Özçetin
  • 1,893
  • 1
  • 14
  • 16
Greg D
  • 43,259
  • 14
  • 84
  • 117
  • +1 for the first one (would put +2 if I could :) ). I did not know the second one at all. very interesting, though this is not really a gotcha. + 1 also for the 4... (I'm right in the middle of doing it :/ ) – David Feb 10 '11 at 14:48
  • @David: Yeah, me too. It's an exercise in constantly fighting the DataGrid's impl for keyboard focus. – Greg D Feb 10 '11 at 15:09
  • Output window can be a massive lifesaver when having issues with bindings. – Tom Dudfield Feb 11 '11 at 23:25
  • Actually only the last half are gotchas, the first half are tips. +1 because I love those tips, especially #2. Holy cow I wish I had known that when I was starting out on my WinPhone app. Binding is awesome, except when you do it wrong. – Steve Hiner Mar 15 '12 at 19:35
  • 1
    What are the issues with the various approaches to cue banner text in a WPF textbox? – John Zabroski Feb 03 '13 at 22:51
  • 2
    The only technique for reliable display of the watermark/cue banner text in a wpf textbox is to manually inject the textblock with the text into the textbox's visual tree. This takes a dependency on specific aspects of the textbox's visual tree, but it works consistently in different environments because you maintain the correct z-order for the banner text. Bonus points for making it an attached property. – Greg D Apr 02 '15 at 19:47
7

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.

Community
  • 1
  • 1
Matěj Zábský
  • 16,909
  • 15
  • 69
  • 114
3

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

Community
  • 1
  • 1
Tom Dudfield
  • 3,077
  • 2
  • 25
  • 39
2
  • 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.

  • You don't break MVVM by closing your window in the code-behind.If your view was replaced by an HTML page, you would redirect instead of closing the window. The code to close/redirect belongs to the view, not to the model. MVVM != no code-behind – Maxence Sep 25 '17 at 06:34
1

ToolTips and ContextMenus not sharing the DataContext of its owner? I think that gets everyone at first

Alan
  • 7,875
  • 1
  • 28
  • 48
1

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");
TMan
  • 4,044
  • 18
  • 63
  • 117
  • No clean built in way - I wouldn't call this a gotcha. Remember, the whole of XAML and the binding support is just a bunch of 'magic strings', reflection and cached expressions. You can quite happily extract property names from expressions http://stackoverflow.com/a/672212/286976 and in .net 4.5 you can use `[CallerMemberName]` https://msdn.microsoft.com/en-us/library/system.runtime.compilerservices.callermembernameattribute%28v=vs.110%29.aspx – Gusdor Apr 21 '15 at 14:50
  • 1
    `INotifyDataErrorInfo` is also a much cleaner interface to implement for WPF. – Gusdor Apr 21 '15 at 15:02
1

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

Community
  • 1
  • 1
David
  • 6,014
  • 4
  • 39
  • 55
0

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!

dowhilefor
  • 10,971
  • 3
  • 28
  • 45
0

Binding.StringFormat only works if the type of the target property is string.

Gusdor
  • 14,001
  • 2
  • 52
  • 64
0
  • 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();
    
Spook
  • 25,318
  • 18
  • 90
  • 167