cswork / libraryOpen practice workspace

Articles

WPF Interview Questions: Data Binding, Dependency Properties, and Dispatcher Work

Prepare WPF interview questions with binding update timing, dependency property precedence, collection notifications, Dispatcher work, and stale results.

WPF interview questions become easier when you separate three responsibilities: where a property's effective value comes from, which event propagates a change, and which thread owns the work. A screen can have a valid binding yet display stale data, use a correct Dispatcher call yet freeze, or ignore a style because another value has higher precedence.

This article uses official Microsoft documentation checked October 6, 2026. The invoice and search examples are original exercises. XAML and C# snippets are source-reviewed rather than compiled on Windows; local state-model checks establish the stated event ordering only. We do not claim these are reported questions from a particular employer.

Start with Build a Thread-Safe Video Playback Loop at 25 FPS. Its producer and presentation responsibilities provide a useful bridge to WPF's distinction between background computation and UI ownership.

Why is a TwoWay binding still showing an old source value?

A binding connects a target property to a source property. Its direction describes which way values can travel; its update trigger determines when a target edit travels back. Those are separate decisions. “TwoWay” does not mean “the source changes on every keystroke.”

Official facts: WPF binding targets are dependency properties. Bindings can resolve a source through the inherited DataContext or an explicit source. TextBox.Text normally updates its source on losing focus, while UpdateSourceTrigger=PropertyChanged requests updates as text changes. Data binding overview.

Our invoice screen begins with quantity 2 and unit price 10. The user types 3 into the quantity box while focus remains there. Under the ordinary LostFocus trigger, the view model can still contain 2. A preview computed from that source therefore still shows 20, even though the visible edit says 3.

<TextBox Text="{Binding Quantity,
                        Mode=TwoWay,
                        UpdateSourceTrigger=PropertyChanged}" />
<TextBlock Text="{Binding Total}" />

This changes the edit timing. It does not implement integer conversion, validation, or notification for the computed total. Ask what should happen while the user types an incomplete or invalid value; a typed integer property cannot represent every temporary string in an editor.

How should you trace a failed binding?

Use an evidence sequence: identify the target element, inspect its actual DataContext, resolve the path, check direction and trigger, and then inspect the notification or conversion failure. That sequence prevents a speculative rewrite of a view model whose binding simply points at the wrong object.

For our invoice, suppose the surrounding view has an InvoiceViewModel, but a nested panel assigns a different DataContext. The text box's Quantity path now resolves against that nested object. Raising PropertyChanged on the outer invoice will not repair the source selection.

For a reusable component, make the source contract explicit. Is it binding to a view model property, a named element, or a property on the templated control? Avoid treating a constructor assignment to DataContext as an innocent default if it prevents consumers from supplying their own source.

In an interview, say what observation would falsify your diagnosis. If the resolved source is correct and the setter executes, investigate notifications or target precedence next. If the setter never executes, inspect the binding direction, trigger, conversion, and validation before adding more events.

Which changes require PropertyChanged?

Official fact: a CLR binding source can implement INotifyPropertyChanged and raise an event naming the changed property so the binding target can update. Property change notification.

Our quantity setter needs to announce both the stored quantity and the derived total. The following sketch assumes UnitPrice is fixed; if it becomes editable, its setter must also announce Total. Namespace imports and application validation are omitted for focus.

private int _quantity = 2;
public decimal UnitPrice => 10m;
public decimal Total => Quantity * UnitPrice;
public event PropertyChangedEventHandler? PropertyChanged;

public int Quantity
{
    get => _quantity;
    set
    {
        if (_quantity == value) return;
        _quantity = value;
        PropertyChanged?.Invoke(this,
            new PropertyChangedEventArgs(nameof(Quantity)));
        PropertyChanged?.Invoke(this,
            new PropertyChangedEventArgs(nameof(Total)));
    }
}

Here is the expected edit ledger. Each row changes one assumption, so you can explain why the display differs.

Edit behaviorSource quantity while typing 3Expected total
LostFocus, before focus leaves220
LostFocus, after focus leaves and notifications fire330
PropertyChanged, with Quantity and Total notifications330
PropertyChanged, but no Total notification3Target may retain 20

The final row is the important trap. A getter returning 30 does not mean the binding engine has received a reason to read that getter again. Test the displayed target after the event, not just the view model's arithmetic.

Does ObservableCollection notify changes inside an item?

Official fact: ObservableCollection<T> supplies notifications for collection changes such as adding or removing elements and refreshing the list. ObservableCollection reference. It does not make every property inside every element observable by magic.

For our invoice, adding a line and changing an existing line's Quantity are different events. A line view model should supply the property notifications its bindings need. An invoice-level Total that depends on all lines also needs a deliberate way to observe additions, removals, and relevant item changes.

Trace a removed line carefully. If the invoice subscribes to each line's PropertyChanged event, it must detach when a line leaves the collection. Otherwise an invisible line can still trigger calculations and retain an unexpected lifetime. Replacing the collection itself also requires a source-property notification if the view binds to that property.

For a high-rate producer, define where collection mutation occurs. Our recommended design applies a bounded batch on the UI dispatcher and keeps the background producer's data separate. Alternative synchronization strategies require an explicit ownership contract; “use ObservableCollection” is not an answer to concurrent modification.

Why does a style setter lose to a local value?

A dependency property participates in WPF's property system rather than being only a backing field and setter. Officially, it can obtain values through inputs such as bindings, styles, resources, inheritance, and animation. Dependency properties overview.

In our simplified button example, the style sets Background to sage. A local assignment changes it to charcoal. A style trigger requests amber on hover. Without animation or coercion, the local value wins over the style setter and its trigger; the hover may appear ineffective.

Official facts: dependency property value precedence determines the effective value. Bindings can occupy the local-value level. Clearing a local value allows remaining inputs to participate; it does not promise that the registration default will become visible. Value precedence.

When debugging, ask which value source is currently active. Removing a local assignment can reveal a style, an inherited value, or another applicable input. A claim that “ClearValue resets everything” misses that interaction. Include animation and coercion in your investigation when the simpler trace does not explain the result.

How does a custom dependency property preserve consumer bindings?

Official pattern: register the dependency property with its name, type, owner, and metadata, and expose a CLR wrapper around GetValue and SetValue. Put property-system behavior in metadata callbacks rather than relying on wrapper code as the only change path. Custom dependency properties.

Suppose an AmountEditor has a Value property bound by its consumer. The control wants to propose a new value after a button click. An ordinary local assignment can replace the value's existing binding. Microsoft's precedence documentation describes SetCurrentValue as a way to change the current value without overwriting its existing value source. Value precedence.

That is a property-system tool, not a universal source-commit protocol. The binding's direction, update policy, validation, and control design still matter. Explain whether the control changes its current display, proposes an edit to the consumer, or commits a transaction. Test a later consumer update to ensure the relationship survives.

Why can Dispatcher work still freeze the UI?

Official facts: Dispatcher work runs on its associated thread, selected from a priority queue. A work item runs to completion; moving a long calculation into InvokeAsync does not move that calculation onto a worker thread. Most WPF UI objects enforce affinity to their creating dispatcher. Threading model.

Our original import operation parses a large file, then updates a small status label. Queueing both parsing and label assignment in one UI callback blocks input during parsing. The repair separates computation from a brief UI application step; lowering its priority alone does not make a long callback interruptible.

For naturally asynchronous I/O, await the operation rather than automatically wrapping it in Task.Run. For CPU work, a worker can calculate an immutable result and then schedule a small application step on the correct dispatcher. Avoid reading or mutating UI objects inside the worker to build that result.

Another failure involves waiting synchronously on work that requires the blocked UI thread. Microsoft's threading guide specifically warns against Task.Wait on the Task associated with a queued DispatcherOperation. Use the documented asynchronous path and trace the dependency, rather than describing every wait as harmless because another thread exists.

Does successful cancellation prevent stale search results?

Consider a search box whose first request is A and next request is B. B completes first and displays its rows. A completes afterward. Dispatching A's result to the UI thread is thread-safe but still logically wrong: the screen can revert to an older query.

Our policy assigns a generation number to each request. The UI dispatcher accepts a result only if its generation is still current and the screen remains active. Cancellation reduces unnecessary work; the generation check protects acceptance even when cancellation arrives too late or is not honored by a dependency.

Perform the acceptance check inside the UI application callback, where current generation changes are serialized with presentation. A worker-side check followed by a queued callback leaves a gap: another request may become current before the callback executes.

Test both completion orders, a canceled request that still completes, and a view that closes while an operation is outstanding. Record an error separately from an empty successful result. These tests check user-visible state transitions, not only that a continuation happened to run without a cross-thread exception.

For a Windows rehearsal, capture the source value, PropertyChanged names, effective target value, and dispatcher access at each transition. Keep this diagnostic instrumentation small enough to remove afterward. Assert that an identical quantity assignment emits no redundant update, a genuine edit refreshes Total, and an obsolete search completion changes neither rows nor loading state. Our local model checks these logical expectations; only a real WPF test can confirm binding-engine and control behavior in your project.

Sources and Further Reading

Documentation checked October 6, 2026. Examples and recommendations are original preparation material; runtime behavior still requires validation in the target Windows/WPF environment.