<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: s-iguchi09</title>
    <description>The latest articles on DEV Community by s-iguchi09 (@s-iguchi09).</description>
    <link>https://dev.to/s-iguchi09</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4116074%2Fced7d4a4-c3cc-41a4-bf13-70305f1b7475.png</url>
      <title>DEV Community: s-iguchi09</title>
      <link>https://dev.to/s-iguchi09</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/s-iguchi09"/>
    <language>en</language>
    <item>
      <title>Why a WPF DataGrid Edit Does Not Reach the ViewModel When Save Is Clicked, and How to Use CommitEdit</title>
      <dc:creator>s-iguchi09</dc:creator>
      <pubDate>Fri, 16 Oct 2026 17:31:09 +0000</pubDate>
      <link>https://dev.to/s-iguchi09/why-a-wpf-datagrid-edit-does-not-reach-the-viewmodel-when-save-is-clicked-and-how-to-use-commitedit-59o0</link>
      <guid>https://dev.to/s-iguchi09/why-a-wpf-datagrid-edit-does-not-reach-the-viewmodel-when-save-is-clicked-and-how-to-use-commitedit-59o0</guid>
      <description>&lt;p&gt;A user types into a &lt;code&gt;DataGrid&lt;/code&gt; cell and clicks Save in the toolbar without leaving the cell. The grid still shows the new text, but the view model saves the old value. No exception, no warning.&lt;/p&gt;

&lt;p&gt;This is a short summary. The full article, with a table of measured results for each save path on .NET 10, is here:&lt;br&gt;
&lt;strong&gt;&lt;a href="https://s-iguchi09.github.io/articles/wpf-datagrid-edit-not-committed-on-save/" rel="noopener noreferrer"&gt;Why a WPF DataGrid Edit Does Not Reach the ViewModel When Save Is Clicked&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Three things get in the way
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Toolbar, menu, and Ctrl+S never end the edit.&lt;/strong&gt; &lt;code&gt;ToolBar&lt;/code&gt; and &lt;code&gt;Menu&lt;/code&gt; are focus scopes, so focus snaps back to the cell before the command runs. A &lt;code&gt;KeyBinding&lt;/code&gt; never moves focus at all. Only a plain button outside the toolbar happened to work.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;CommitEdit()&lt;/code&gt; with no arguments is not enough.&lt;/strong&gt; Called while a cell is being edited, it only commits the cell into the pending row. The source keeps the old value, and a later &lt;code&gt;ICollectionView.Refresh&lt;/code&gt; throws &lt;code&gt;InvalidOperationException&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Unconvertible input blocks the commit.&lt;/strong&gt; With &lt;code&gt;abc&lt;/code&gt; in an &lt;code&gt;int&lt;/code&gt; column, the commit returns &lt;code&gt;false&lt;/code&gt;. Saving anyway stores stale data.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
  
  
  The fix
&lt;/h2&gt;

&lt;p&gt;Commit the whole row at the start of the save, and stop if it fails:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;committed&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;grid&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CommitEdit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DataGridEditingUnit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Row&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(!&lt;/span&gt;&lt;span class="n"&gt;committed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Tell the user about the invalid input and do not save.&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To keep the view model unaware of the &lt;code&gt;DataGrid&lt;/code&gt;, the full article passes this call in from code-behind as a &lt;code&gt;Func&amp;lt;bool&amp;gt;&lt;/code&gt;. It also explains why &lt;code&gt;UpdateSourceTrigger=PropertyChanged&lt;/code&gt; and &lt;code&gt;FocusManager.IsFocusScope="False"&lt;/code&gt; are not real substitutes.&lt;/p&gt;

&lt;p&gt;A &lt;a href="https://s-iguchi09.github.io/ja/articles/wpf-datagrid-edit-not-committed-on-save/" rel="noopener noreferrer"&gt;Japanese version&lt;/a&gt; is also available.&lt;/p&gt;

</description>
      <category>wpf</category>
      <category>dotnet</category>
      <category>csharp</category>
    </item>
    <item>
      <title>Binding to a WPF UserControl's Own Dependency Property from Inside the Control</title>
      <dc:creator>s-iguchi09</dc:creator>
      <pubDate>Thu, 15 Oct 2026 17:42:47 +0000</pubDate>
      <link>https://dev.to/s-iguchi09/binding-to-a-wpf-usercontrols-own-dependency-property-from-inside-the-control-1eil</link>
      <guid>https://dev.to/s-iguchi09/binding-to-a-wpf-usercontrols-own-dependency-property-from-inside-the-control-1eil</guid>
      <description>&lt;p&gt;You add a &lt;code&gt;Title&lt;/code&gt; dependency property to a &lt;code&gt;UserControl&lt;/code&gt;, the caller passes &lt;code&gt;Title="{Binding HeaderText}"&lt;/code&gt;, and the debugger confirms the value arrived. Yet &lt;code&gt;&amp;lt;TextBlock Text="{Binding Title}"/&amp;gt;&lt;/code&gt; inside the control shows nothing.&lt;/p&gt;

&lt;p&gt;This is a short summary. The full write-up, with measurements on .NET 10 and every edge case, is here:&lt;br&gt;
&lt;strong&gt;&lt;a href="https://s-iguchi09.github.io/articles/wpf-usercontrol-dependencyproperty-binding-not-working/" rel="noopener noreferrer"&gt;Binding to a WPF UserControl's Own Dependency Property from Inside the Control&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Why it happens
&lt;/h2&gt;

&lt;p&gt;A binding with only a path resolves against &lt;code&gt;DataContext&lt;/code&gt;. Inside the control, &lt;code&gt;DataContext&lt;/code&gt; is inherited from the consuming view, so &lt;code&gt;{Binding Title}&lt;/code&gt; looks for &lt;code&gt;Title&lt;/code&gt; on the caller's view model, not on the control. The Output window reports the view model as the &lt;code&gt;DataItem&lt;/code&gt;, which gives it away.&lt;/p&gt;

&lt;p&gt;Two cases hide the problem completely: when the view model happens to have its own &lt;code&gt;Title&lt;/code&gt; (a wrong value shows, no error), and when &lt;code&gt;DataContext&lt;/code&gt; is &lt;code&gt;null&lt;/code&gt; (blank, no error).&lt;/p&gt;
&lt;h2&gt;
  
  
  The fix in one line
&lt;/h2&gt;

&lt;p&gt;Give the inner binding an explicit source:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;TextBlock&lt;/span&gt; &lt;span class="na"&gt;Text=&lt;/span&gt;&lt;span class="s"&gt;"{Binding Title,
           RelativeSource={RelativeSource AncestorType={x:Type local:InfoCard}}}"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;ElementName&lt;/code&gt; on a named root works too. If the control references many of its own properties, set &lt;code&gt;DataContext&lt;/code&gt; on the inner root panel (not on the &lt;code&gt;UserControl&lt;/code&gt; itself) and keep plain &lt;code&gt;{Binding Title}&lt;/code&gt; below it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to avoid
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;DataContext = this&lt;/code&gt; in the constructor makes the inside work but breaks the caller's binding. It only shows up when the caller passes a binding instead of a literal, so it often survives until the control is reused.&lt;/p&gt;

&lt;p&gt;The full article also covers &lt;code&gt;ContextMenu&lt;/code&gt; vs. inline &lt;code&gt;Popup&lt;/code&gt;, &lt;code&gt;DataTemplate&lt;/code&gt; name scopes, and when you need &lt;code&gt;BindsTwoWayByDefault&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;A &lt;a href="https://s-iguchi09.github.io/ja/articles/wpf-usercontrol-dependencyproperty-binding-not-working/" rel="noopener noreferrer"&gt;Japanese version&lt;/a&gt; is also available.&lt;/p&gt;

</description>
      <category>wpf</category>
      <category>dotnet</category>
      <category>csharp</category>
    </item>
    <item>
      <title>Fixing a RelayCommand Whose CanExecute Does Not Update the Button State in WPF</title>
      <dc:creator>s-iguchi09</dc:creator>
      <pubDate>Wed, 14 Oct 2026 17:45:30 +0000</pubDate>
      <link>https://dev.to/s-iguchi09/fixing-a-relaycommand-whose-canexecute-does-not-update-the-button-state-in-wpf-k3o</link>
      <guid>https://dev.to/s-iguchi09/fixing-a-relaycommand-whose-canexecute-does-not-update-the-button-state-in-wpf-k3o</guid>
      <description>&lt;p&gt;You fill in the required field, &lt;code&gt;CanExecute&lt;/code&gt; now returns &lt;code&gt;true&lt;/code&gt;, and the Save button stays grey. A hand-written &lt;code&gt;RelayCommand&lt;/code&gt; declares &lt;code&gt;CanExecuteChanged&lt;/code&gt; but never raises it, so the button never asks again.&lt;/p&gt;

&lt;p&gt;This is a short summary. The full article, with a table of what each call does to &lt;code&gt;Button.IsEnabled&lt;/code&gt; on .NET 10, is here:&lt;br&gt;
&lt;strong&gt;&lt;a href="https://s-iguchi09.github.io/articles/wpf-relaycommand-canexecute-not-updating/" rel="noopener noreferrer"&gt;Fixing a RelayCommand Whose CanExecute Does Not Update the Button State in WPF&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  What the measurements show
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;A new &lt;code&gt;CanExecute&lt;/code&gt; result alone changes nothing.&lt;/strong&gt; The button re-queries only when &lt;code&gt;CanExecuteChanged&lt;/code&gt; fires.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The way you raise it has to match the implementation.&lt;/strong&gt; &lt;code&gt;CommandManager.InvalidateRequerySuggested()&lt;/code&gt; and ordinary typing reach only a command that forwards to &lt;code&gt;RequerySuggested&lt;/code&gt;. A command with its own event ignores both and needs its own raise method.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
  
  
  The fix
&lt;/h2&gt;

&lt;p&gt;When a view model property decides executability, keep your own event and raise it from the setter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;event&lt;/span&gt; &lt;span class="n"&gt;EventHandler&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="n"&gt;CanExecuteChanged&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;RaiseCanExecuteChanged&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;CanExecuteChanged&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;Invoke&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;EventArgs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Empty&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// In the view model&lt;/span&gt;
&lt;span class="k"&gt;set&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;_name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;SaveCommand&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RaiseCanExecuteChanged&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When executability follows focus or selection instead, forward &lt;code&gt;add&lt;/code&gt;/&lt;code&gt;remove&lt;/code&gt; to &lt;code&gt;CommandManager.RequerySuggested&lt;/code&gt;. The full article covers when each fits, the cost of requerying every connected button, and why both raises belong on the UI thread.&lt;/p&gt;

&lt;p&gt;A &lt;a href="https://s-iguchi09.github.io/ja/articles/wpf-relaycommand-canexecute-not-updating/" rel="noopener noreferrer"&gt;Japanese version&lt;/a&gt; is also available.&lt;/p&gt;

&lt;h2&gt;
  
  
  Related Articles
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://s-iguchi09.github.io/articles/wpf-datatemplate-parent-datacontext-binding/" rel="noopener noreferrer"&gt;Binding to the Parent DataContext from Inside a WPF DataTemplate&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://s-iguchi09.github.io/articles/wpf-observablecollection-cross-thread-update/" rel="noopener noreferrer"&gt;Fixing the Cross-Thread Exception When Updating an ObservableCollection in WPF&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://s-iguchi09.github.io/apps/wpf-standard-control-demo/button.html" rel="noopener noreferrer"&gt;Button (WPF Standard Control Demo App)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>wpf</category>
      <category>dotnet</category>
      <category>csharp</category>
    </item>
    <item>
      <title>Why WPF Input Limits Such as MaxLength Do Not Apply to Values Set from Code or Bindings</title>
      <dc:creator>s-iguchi09</dc:creator>
      <pubDate>Sun, 04 Oct 2026 17:15:39 +0000</pubDate>
      <link>https://dev.to/s-iguchi09/why-wpf-input-limits-such-as-maxlength-do-not-apply-to-values-set-from-code-or-bindings-4pk6</link>
      <guid>https://dev.to/s-iguchi09/why-wpf-input-limits-such-as-maxlength-do-not-apply-to-values-set-from-code-or-bindings-4pk6</guid>
      <description>&lt;p&gt;A &lt;code&gt;TextBox&lt;/code&gt; has &lt;code&gt;MaxLength="50"&lt;/code&gt;, yet an 80-character name loaded from an old record shows up in full and gets saved again. The same happens with a &lt;code&gt;DatePicker&lt;/code&gt; range, a snapping &lt;code&gt;Slider&lt;/code&gt;, and a disabled &lt;code&gt;TabItem&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This is a short summary. The full article, with tables for seven limits across user input, code, and bindings on .NET 10, is here:&lt;br&gt;
&lt;strong&gt;&lt;a href="https://s-iguchi09.github.io/articles/wpf-input-limits-not-applied-to-code/" rel="noopener noreferrer"&gt;Why WPF Input Limits Such as MaxLength Do Not Apply to Values Set from Code or Bindings&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  What the measurements show
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;These limits restrict the user, not the property.&lt;/strong&gt; Assignment from code passed six of the seven. &lt;code&gt;MaxLength&lt;/code&gt;, &lt;code&gt;CharacterCasing&lt;/code&gt;, and &lt;code&gt;PasswordBox.MaxLength&lt;/code&gt; are documented this way.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;DatePicker&lt;/code&gt; leaks even for users.&lt;/strong&gt; A date outside the range typed into its text box became &lt;code&gt;SelectedDate&lt;/code&gt;, and &lt;code&gt;DisplayDateStart&lt;/code&gt; then moved back to that date.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;Slider.Maximum&lt;/code&gt; coerces only the screen.&lt;/strong&gt; Set to &lt;code&gt;150&lt;/code&gt; through a &lt;code&gt;TwoWay&lt;/code&gt; binding, the slider showed &lt;code&gt;100&lt;/code&gt; while the view model kept &lt;code&gt;150&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A disabled tab is still selectable&lt;/strong&gt; by setting &lt;code&gt;SelectedIndex&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
  
  
  The fix
&lt;/h2&gt;

&lt;p&gt;Guard the value in the view model, and keep the control limits only as typing aids. For a length, record an error through &lt;code&gt;INotifyDataErrorInfo&lt;/code&gt; instead of truncating:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;_nameErrors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Clear&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;MaxNameLength&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;_nameErrors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"Name must be at most &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;MaxNameLength&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt; characters."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;ErrorsChanged&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;Invoke&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;DataErrorsChangedEventArgs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;nameof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;)));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For a volume, clamp and round in the setter so the source and the slider agree. The full article also explains why a read-only period needs &lt;code&gt;Mode=OneWay&lt;/code&gt; on &lt;code&gt;DisplayDateStart&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;A &lt;a href="https://s-iguchi09.github.io/ja/articles/wpf-input-limits-not-applied-to-code/" rel="noopener noreferrer"&gt;Japanese version&lt;/a&gt; is also available.&lt;/p&gt;

&lt;h2&gt;
  
  
  Related Articles
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://s-iguchi09.github.io/articles/wpf-validation-error-not-displayed/" rel="noopener noreferrer"&gt;Why WPF Validation Errors Are Not Displayed, and Choosing Between IDataErrorInfo and INotifyDataErrorInfo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://s-iguchi09.github.io/articles/wpf-binding-mode-omitted-detached/" rel="noopener noreferrer"&gt;How User Input Silently Removes a WPF Binding Written Without Mode&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://s-iguchi09.github.io/articles/wpf-datagrid-edit-not-committed-on-save/" rel="noopener noreferrer"&gt;Why a WPF DataGrid Edit Does Not Reach the ViewModel When Save Is Clicked, and How to Use CommitEdit&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://s-iguchi09.github.io/articles/wpf-unhandled-exception-dispatcher-task-thread/" rel="noopener noreferrer"&gt;Exceptions WPF's DispatcherUnhandledException Never Sees — Where Thread, Task and async void Exceptions Go&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://s-iguchi09.github.io/apps/wpf-standard-control-demo/textbox.html" rel="noopener noreferrer"&gt;TextBox (WPF Standard Control Demo App)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://s-iguchi09.github.io/apps/wpf-standard-control-demo/passwordbox.html" rel="noopener noreferrer"&gt;PasswordBox (WPF Standard Control Demo App)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://s-iguchi09.github.io/apps/wpf-standard-control-demo/datepicker.html" rel="noopener noreferrer"&gt;DatePicker (WPF Standard Control Demo App)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://s-iguchi09.github.io/apps/wpf-standard-control-demo/slider.html" rel="noopener noreferrer"&gt;Slider (WPF Standard Control Demo App)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://s-iguchi09.github.io/apps/wpf-standard-control-demo/tabitem.html" rel="noopener noreferrer"&gt;TabItem (WPF Standard Control Demo App)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>wpf</category>
      <category>dotnet</category>
      <category>csharp</category>
    </item>
    <item>
      <title>Binding to the Parent DataContext from Inside a WPF DataTemplate</title>
      <dc:creator>s-iguchi09</dc:creator>
      <pubDate>Sat, 26 Sep 2026 08:21:22 +0000</pubDate>
      <link>https://dev.to/s-iguchi09/binding-to-the-parent-datacontext-from-inside-a-wpf-datatemplate-5d69</link>
      <guid>https://dev.to/s-iguchi09/binding-to-the-parent-datacontext-from-inside-a-wpf-datatemplate-5d69</guid>
      <description>&lt;p&gt;Each row of an &lt;code&gt;ItemsControl&lt;/code&gt; has a Delete button bound to &lt;code&gt;{Binding DeleteCommand}&lt;/code&gt;. The button looks enabled, but clicking it does nothing. The command lives on the parent view model, while everything inside the template gets the row item as its &lt;code&gt;DataContext&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This is a short summary. The full article, with a table per binding style and measurements inside &lt;code&gt;ContextMenu&lt;/code&gt; and &lt;code&gt;ToolTip&lt;/code&gt; on .NET 10, is here:&lt;br&gt;
&lt;strong&gt;&lt;a href="https://s-iguchi09.github.io/articles/wpf-datatemplate-parent-datacontext-binding/" rel="noopener noreferrer"&gt;Binding to the Parent DataContext from Inside a WPF DataTemplate&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Why nothing looks wrong
&lt;/h2&gt;

&lt;p&gt;When the binding fails, &lt;code&gt;Command&lt;/code&gt; stays &lt;code&gt;null&lt;/code&gt;. A null command leaves &lt;code&gt;IsEnabled&lt;/code&gt; at &lt;code&gt;True&lt;/code&gt;, so the screen gives no hint. The Output window does: its &lt;code&gt;DataItem&lt;/code&gt; names the item type instead of the view model.&lt;/p&gt;
&lt;h2&gt;
  
  
  The fix
&lt;/h2&gt;

&lt;p&gt;Walk up to the &lt;code&gt;ItemsControl&lt;/code&gt; and go through its &lt;code&gt;DataContext&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;Button&lt;/span&gt; &lt;span class="na"&gt;Content=&lt;/span&gt;&lt;span class="s"&gt;"Delete"&lt;/span&gt;
        &lt;span class="na"&gt;Command=&lt;/span&gt;&lt;span class="s"&gt;"{Binding DataContext.DeleteCommand,
                  RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"&lt;/span&gt;
        &lt;span class="na"&gt;CommandParameter=&lt;/span&gt;&lt;span class="s"&gt;"{Binding}"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;CommandParameter&lt;/code&gt; keeps the plain binding so the clicked item is passed along.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where it stops working
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;ElementName&lt;/code&gt; also works inside a &lt;code&gt;DataTemplate&lt;/code&gt; in WPF, but ties the template to one view.&lt;/li&gt;
&lt;li&gt;Inside a &lt;code&gt;ContextMenu&lt;/code&gt; or &lt;code&gt;ToolTip&lt;/code&gt;, neither &lt;code&gt;RelativeSource&lt;/code&gt; nor &lt;code&gt;ElementName&lt;/code&gt; reaches the window, because the popup is outside its element tree. Put the parent &lt;code&gt;DataContext&lt;/code&gt; in the owner's &lt;code&gt;Tag&lt;/code&gt;, then read &lt;code&gt;PlacementTarget.Tag&lt;/code&gt; from the menu.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A &lt;a href="https://s-iguchi09.github.io/ja/articles/wpf-datatemplate-parent-datacontext-binding/" rel="noopener noreferrer"&gt;Japanese version&lt;/a&gt; is also available.&lt;/p&gt;

&lt;h2&gt;
  
  
  Related Articles
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://s-iguchi09.github.io/articles/wpf-binding-error-debugging-output-window/" rel="noopener noreferrer"&gt;Reading WPF Binding Errors and Diagnosing Them with the Output Window&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://s-iguchi09.github.io/articles/wpf-treeview-select-item-programmatically/" rel="noopener noreferrer"&gt;Selecting and Expanding a WPF TreeView Node from Code, and Why SelectedItem Is Read-Only&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://s-iguchi09.github.io/articles/wpf-relaycommand-canexecute-not-updating/" rel="noopener noreferrer"&gt;Fixing a RelayCommand Whose CanExecute Does Not Update the Button State in WPF&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://s-iguchi09.github.io/articles/wpf-usercontrol-dependencyproperty-binding-not-working/" rel="noopener noreferrer"&gt;Binding to a WPF UserControl's Own Dependency Property from Inside the Control&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://s-iguchi09.github.io/articles/wpf-datagrid-cell-editing-template/" rel="noopener noreferrer"&gt;Switching Controls Between Display and Edit Modes in WPF DataGrid Cells&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://s-iguchi09.github.io/articles/wpf-combobox-itemssource-patterns/" rel="noopener noreferrer"&gt;WPF ComboBox ItemsSource Binding Patterns and Selected Value Retrieval&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://s-iguchi09.github.io/apps/wpf-standard-control-demo/treeview.html" rel="noopener noreferrer"&gt;TreeView | WPF Standard Control Demo App (.NET 10)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://s-iguchi09.github.io/apps/wpf-standard-control-demo/listbox.html" rel="noopener noreferrer"&gt;ListBox | WPF Standard Control Demo App (.NET 10)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>wpf</category>
      <category>dotnet</category>
      <category>csharp</category>
    </item>
    <item>
      <title>Expressing SQL Outer Joins in LINQ — Implementing LeftJoin, RightJoin and Shuffle</title>
      <dc:creator>s-iguchi09</dc:creator>
      <pubDate>Thu, 17 Sep 2026 14:02:53 +0000</pubDate>
      <link>https://dev.to/s-iguchi09/expressing-sql-outer-joins-in-linq-implementing-leftjoin-rightjoin-and-shuffle-476n</link>
      <guid>https://dev.to/s-iguchi09/expressing-sql-outer-joins-in-linq-implementing-leftjoin-rightjoin-and-shuffle-476n</guid>
      <description>&lt;p&gt;.NET 10 adds &lt;code&gt;LeftJoin&lt;/code&gt;, &lt;code&gt;RightJoin&lt;/code&gt;, and &lt;code&gt;Shuffle&lt;/code&gt; to LINQ. On .NET Framework 4.8 you still write a left join as &lt;code&gt;GroupJoin&lt;/code&gt; + &lt;code&gt;SelectMany&lt;/code&gt; + &lt;code&gt;DefaultIfEmpty&lt;/code&gt;, and shuffle with &lt;code&gt;OrderBy(_ =&amp;gt; Guid.NewGuid())&lt;/code&gt;. Both are easy to get subtly wrong.&lt;/p&gt;

&lt;p&gt;This is a short summary. The full article, with the complete polyfill and a &lt;code&gt;net48&lt;/code&gt; vs &lt;code&gt;net10.0&lt;/code&gt; output comparison, is here:&lt;br&gt;
&lt;strong&gt;&lt;a href="https://s-iguchi09.github.io/articles/linq-backport-netframework-to-net10/" rel="noopener noreferrer"&gt;Expressing SQL Outer Joins in LINQ — Implementing LeftJoin, RightJoin and Shuffle&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  The core of the polyfill
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;LeftJoin&lt;/code&gt; wraps the classic idiom behind the .NET 10 signature, with &lt;code&gt;TInner?&lt;/code&gt; marking the side that can be missing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;outer&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GroupJoin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;inner&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;outerKeySelector&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;innerKeySelector&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;inners&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;inners&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="n"&gt;comparer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SelectMany&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;inners&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;DefaultIfEmpty&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;resultSelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;RightJoin&lt;/code&gt; pivots the same &lt;code&gt;GroupJoin&lt;/code&gt; onto the inner sequence. The whole file sits behind &lt;code&gt;#if !NET10_0_OR_GREATER&lt;/code&gt;, so it switches off after migration.&lt;/p&gt;

&lt;h2&gt;
  
  
  Three things worth knowing
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;Shuffle&lt;/code&gt; is a one-pass Fisher–Yates&lt;/strong&gt;, not a GUID sort. On .NET Framework, eight threads that each created &lt;code&gt;new Random()&lt;/code&gt; at the same moment produced the same order in the measurement. The fix seeds each thread from one locked instance.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It re-shuffles on every enumeration.&lt;/strong&gt; Call &lt;code&gt;ToArray&lt;/code&gt; once if you need a fixed order.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Do not use it on &lt;code&gt;IQueryable&amp;lt;T&amp;gt;&lt;/code&gt;.&lt;/strong&gt; The &lt;code&gt;Enumerable&lt;/code&gt; method still binds, so an Entity Framework join silently runs in memory. Keep the &lt;code&gt;GroupJoin&lt;/code&gt; form for database queries.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A &lt;a href="https://s-iguchi09.github.io/ja/articles/linq-backport-netframework-to-net10/" rel="noopener noreferrer"&gt;Japanese version&lt;/a&gt; is also available.&lt;/p&gt;

&lt;h2&gt;
  
  
  Related Articles
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://s-iguchi09.github.io/articles/linq-backport-netframework-to-net5/" rel="noopener noreferrer"&gt;Designing LINQ Polyfills That Preserve Lazy Evaluation — Implementing Append, Prepend, TakeLast and SkipLast&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://s-iguchi09.github.io/articles/linq-backport-netframework-to-net6/" rel="noopener noreferrer"&gt;Replacing GroupBy and Full-Sort Workarounds — Implementing Chunk, MaxBy, MinBy and DistinctBy&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://s-iguchi09.github.io/articles/linq-backport-netframework-to-net7/" rel="noopener noreferrer"&gt;Order and OrderDescending by Pure Delegation — A Minimal Polyfill with IOrderedEnumerable Compatibility&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://s-iguchi09.github.io/articles/linq-backport-netframework-to-net8/" rel="noopener noreferrer"&gt;Selector-Free ToDictionary — Designing for Overload Resolution and the notnull Constraint&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://s-iguchi09.github.io/articles/linq-backport-netframework-to-net9/" rel="noopener noreferrer"&gt;Key-Based Aggregation Without GroupBy — Dictionary-Backed CountBy, AggregateBy and Index&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://s-iguchi09.github.io/articles/wpf-radiobutton-enum-binding/" rel="noopener noreferrer"&gt;Why a WPF RadioButton Bound to an Enum Shows No Initial Selection — The Role of GroupName&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://s-iguchi09.github.io/articles/csharp-operators-initialization-syntax-by-version/" rel="noopener noreferrer"&gt;C# Operators and Initialization Syntax by Version&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://s-iguchi09.github.io/articles/csharp14-extension-members-static-class-limitation/" rel="noopener noreferrer"&gt;C# 14 Extension Members on Static Classes: Static Members Only&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>csharp</category>
      <category>dotnet</category>
      <category>linq</category>
    </item>
    <item>
      <title>Why WPF Validation Errors Are Not Displayed, and Choosing Between IDataErrorInfo and INotifyDataErrorInfo</title>
      <dc:creator>s-iguchi09</dc:creator>
      <pubDate>Mon, 14 Sep 2026 16:54:09 +0000</pubDate>
      <link>https://dev.to/s-iguchi09/why-wpf-validation-errors-are-not-displayed-and-choosing-between-idataerrorinfo-and-475c</link>
      <guid>https://dev.to/s-iguchi09/why-wpf-validation-errors-are-not-displayed-and-choosing-between-idataerrorinfo-and-475c</guid>
      <description>&lt;p&gt;The required-field check is written, but the &lt;code&gt;TextBox&lt;/code&gt; never turns red. Sometimes the check never runs at all. Sometimes it runs, &lt;code&gt;Validation.GetHasError&lt;/code&gt; is &lt;code&gt;true&lt;/code&gt;, and the screen still shows nothing.&lt;/p&gt;

&lt;p&gt;This is a short summary. The full article, with measurements for each case on .NET 10, is here:&lt;br&gt;
&lt;strong&gt;&lt;a href="https://s-iguchi09.github.io/articles/wpf-validation-error-not-displayed/" rel="noopener noreferrer"&gt;Why WPF Validation Errors Are Not Displayed, and Choosing Between IDataErrorInfo and INotifyDataErrorInfo&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Start from &lt;code&gt;Validation.GetHasError&lt;/code&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;false&lt;/code&gt;:&lt;/strong&gt; no rule is attached, or the input has not reached the source yet. &lt;code&gt;IDataErrorInfo&lt;/code&gt; does nothing until the binding has &lt;code&gt;ValidatesOnDataErrors="True"&lt;/code&gt;, because that setting is &lt;code&gt;false&lt;/code&gt; by default. &lt;code&gt;INotifyDataErrorInfo&lt;/code&gt; is the only approach that is on by default. Typed text is checked only when it reaches the source, which for &lt;code&gt;TextBox.Text&lt;/code&gt; happens on focus loss.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;true&lt;/code&gt;, but nothing on screen:&lt;/strong&gt; the error template has nowhere to draw. A replaced &lt;code&gt;Window&lt;/code&gt; template without an &lt;code&gt;AdornerDecorator&lt;/code&gt; leaves no adorner layer. Inside a &lt;code&gt;ScrollViewer&lt;/code&gt; the layer still exists, so only some fields go silent.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A red border with no message:&lt;/strong&gt; this is just how the default &lt;code&gt;ErrorTemplate&lt;/code&gt; works. It never shows the text.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  The fix for the message
&lt;/h2&gt;

&lt;p&gt;Supply your own template:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;ControlTemplate&lt;/span&gt; &lt;span class="na"&gt;x:Key=&lt;/span&gt;&lt;span class="s"&gt;"FieldErrorTemplate"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;StackPanel&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;Border&lt;/span&gt; &lt;span class="na"&gt;BorderBrush=&lt;/span&gt;&lt;span class="s"&gt;"#D13438"&lt;/span&gt; &lt;span class="na"&gt;BorderThickness=&lt;/span&gt;&lt;span class="s"&gt;"1"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;AdornedElementPlaceholder&lt;/span&gt; &lt;span class="na"&gt;x:Name=&lt;/span&gt;&lt;span class="s"&gt;"Adorned"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/Border&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;TextBlock&lt;/span&gt; &lt;span class="na"&gt;Foreground=&lt;/span&gt;&lt;span class="s"&gt;"#D13438"&lt;/span&gt;
                   &lt;span class="na"&gt;Text=&lt;/span&gt;&lt;span class="s"&gt;"{Binding ElementName=Adorned,
                          Path=AdornedElement.(Validation.Errors)/ErrorContent}"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/StackPanel&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/ControlTemplate&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Adorners take no layout space, so reserve a bottom margin. For new code where the view model owns validation, the article recommends &lt;code&gt;INotifyDataErrorInfo&lt;/code&gt;, and remember to raise &lt;code&gt;ErrorsChanged&lt;/code&gt; when an error clears.&lt;/p&gt;

&lt;p&gt;A &lt;a href="https://s-iguchi09.github.io/ja/articles/wpf-validation-error-not-displayed/" rel="noopener noreferrer"&gt;Japanese version&lt;/a&gt; is also available.&lt;/p&gt;

&lt;h2&gt;
  
  
  Related Articles
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://s-iguchi09.github.io/articles/wpf-relaycommand-canexecute-not-updating/" rel="noopener noreferrer"&gt;Fixing a RelayCommand Whose CanExecute Does Not Update the Button State in WPF&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://s-iguchi09.github.io/articles/wpf-binding-error-debugging-output-window/" rel="noopener noreferrer"&gt;Reading WPF Binding Errors and Diagnosing Them with the Output Window&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://s-iguchi09.github.io/articles/wpf-datagrid-cell-editing-template/" rel="noopener noreferrer"&gt;Switching Controls Between Display and Edit Modes in WPF DataGrid Cells&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://s-iguchi09.github.io/articles/wpf-textbox-updatesourcetrigger-binding-timing/" rel="noopener noreferrer"&gt;Controlling When TextBox Input Reaches the Source with UpdateSourceTrigger in WPF&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://s-iguchi09.github.io/articles/wpf-textbox-updatesource-from-view-pitfalls/" rel="noopener noreferrer"&gt;Calling TextBox UpdateSource from the View in WPF: Implementation and Pitfalls&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://s-iguchi09.github.io/articles/wpf-datatemplate-parent-datacontext-binding/" rel="noopener noreferrer"&gt;Binding to the Parent DataContext from Inside a WPF DataTemplate&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://s-iguchi09.github.io/articles/wpf-selectable-readonly-text-display/" rel="noopener noreferrer"&gt;How to Display Selectable, Copyable Read-Only Text in WPF&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>wpf</category>
      <category>dotnet</category>
      <category>csharp</category>
    </item>
    <item>
      <title>Fixing the Cross-Thread Exception When Updating an ObservableCollection in WPF</title>
      <dc:creator>s-iguchi09</dc:creator>
      <pubDate>Fri, 11 Sep 2026 16:26:05 +0000</pubDate>
      <link>https://dev.to/s-iguchi09/fixing-the-cross-thread-exception-when-updating-an-observablecollection-in-wpf-kl4</link>
      <guid>https://dev.to/s-iguchi09/fixing-the-cross-thread-exception-when-updating-an-observablecollection-in-wpf-kl4</guid>
      <description>&lt;p&gt;You load data inside &lt;code&gt;Task.Run&lt;/code&gt; and call &lt;code&gt;Items.Add(line)&lt;/code&gt; on an &lt;code&gt;ObservableCollection&amp;lt;T&amp;gt;&lt;/code&gt; bound to a &lt;code&gt;ListBox&lt;/code&gt;. It throws &lt;code&gt;NotSupportedException&lt;/code&gt;: this type of &lt;code&gt;CollectionView&lt;/code&gt; does not support changes to its &lt;code&gt;SourceCollection&lt;/code&gt; from a thread other than the &lt;code&gt;Dispatcher&lt;/code&gt; thread.&lt;/p&gt;

&lt;p&gt;This is a short summary. The full article, with a bound vs unbound comparison and a 5,000-item timing test on .NET 10, is here:&lt;br&gt;
&lt;strong&gt;&lt;a href="https://s-iguchi09.github.io/articles/wpf-observablecollection-cross-thread-update/" rel="noopener noreferrer"&gt;Fixing the Cross-Thread Exception When Updating an ObservableCollection in WPF&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  The collection is not what throws
&lt;/h2&gt;

&lt;p&gt;The same &lt;code&gt;Add&lt;/code&gt; on an unbound collection did not throw. The exception comes from the &lt;code&gt;CollectionView&lt;/code&gt; that WPF puts between the collection and the control, which belongs to the UI thread. That does not make the collection thread-safe. It only tells you where the check lives.&lt;/p&gt;
&lt;h2&gt;
  
  
  Two fixes
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Few, occasional updates:&lt;/strong&gt; move the change onto the UI thread.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;dispatcher&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Invoke&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Many, frequent updates:&lt;/strong&gt; register a lock once on the UI thread, then take that same lock for every access.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;BindingOperations&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;EnableCollectionSynchronization&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Items&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_lock&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// on the worker&lt;/span&gt;
&lt;span class="k"&gt;lock&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_lock&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;Items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Adding 5,000 items one by one, the &lt;code&gt;Dispatcher.Invoke&lt;/code&gt; loop took 992 ms. With the shared lock the loop took 6 ms, and the view had all 5,000 notifications after 64 ms. The UI thread still applies them, just later.&lt;/p&gt;

&lt;p&gt;Controls themselves stay UI-thread-only either way.&lt;/p&gt;

&lt;p&gt;A &lt;a href="https://s-iguchi09.github.io/ja/articles/wpf-observablecollection-cross-thread-update/" rel="noopener noreferrer"&gt;Japanese version&lt;/a&gt; is also available.&lt;/p&gt;

&lt;h2&gt;
  
  
  Related Articles
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://s-iguchi09.github.io/articles/wpf-application-not-exiting-shutdownmode-threads/" rel="noopener noreferrer"&gt;Diagnosing a WPF Process That Stays Alive After the Window Closes — ShutdownMode and Foreground Threads&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://s-iguchi09.github.io/articles/wpf-combobox-itemssource-patterns/" rel="noopener noreferrer"&gt;WPF ComboBox ItemsSource Binding Patterns and Selected Value Retrieval&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://s-iguchi09.github.io/articles/wpf-listbox-virtualization-selecteditems/" rel="noopener noreferrer"&gt;How to Prevent SelectedItems from Appearing Lost in a Virtualized WPF ListBox&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://s-iguchi09.github.io/articles/wpf-bitmapimage-file-lock-cacheoption/" rel="noopener noreferrer"&gt;Releasing the Image File Locked by BitmapImage in WPF with BitmapCacheOption.OnLoad&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://s-iguchi09.github.io/articles/wpf-datagrid-sort-reset/" rel="noopener noreferrer"&gt;How to Reset DataGrid Sorting in WPF&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://s-iguchi09.github.io/articles/wpf-datagrid-sorting/" rel="noopener noreferrer"&gt;How to Implement DataGrid Sorting in WPF&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://s-iguchi09.github.io/apps/wpf-standard-control-demo/datagrid.html" rel="noopener noreferrer"&gt;DataGrid | WPF Standard Control Demo App (.NET 10)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://s-iguchi09.github.io/articles/wpf-task-result-deadlock-synchronizationcontext/" rel="noopener noreferrer"&gt;Why Task.Result Freezes a WPF App and When ConfigureAwait(false) Does Not Help&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>wpf</category>
      <category>dotnet</category>
      <category>csharp</category>
    </item>
    <item>
      <title>Why a WPF ScrollViewer Does Not Scroll and How to Fix It</title>
      <dc:creator>s-iguchi09</dc:creator>
      <pubDate>Thu, 10 Sep 2026 15:04:56 +0000</pubDate>
      <link>https://dev.to/s-iguchi09/why-a-wpf-scrollviewer-does-not-scroll-and-how-to-fix-it-2p9g</link>
      <guid>https://dev.to/s-iguchi09/why-a-wpf-scrollviewer-does-not-scroll-and-how-to-fix-it-2p9g</guid>
      <description>&lt;p&gt;You put a &lt;code&gt;ScrollViewer&lt;/code&gt; with &lt;code&gt;VerticalScrollBarVisibility="Auto"&lt;/code&gt; under a header in a vertical &lt;code&gt;StackPanel&lt;/code&gt;, fill it with items, and no scrollbar ever shows up. The list just runs off the bottom of the window.&lt;/p&gt;

&lt;p&gt;This is a short summary. The full article, with the measured heights for each parent layout on .NET 10, is here:&lt;br&gt;
&lt;strong&gt;&lt;a href="https://s-iguchi09.github.io/articles/wpf-scrollviewer-not-scrolling/" rel="noopener noreferrer"&gt;Why a WPF ScrollViewer Does Not Scroll and How to Fix It&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  The parent is the problem
&lt;/h2&gt;

&lt;p&gt;A vertical &lt;code&gt;StackPanel&lt;/code&gt; measures its children with unlimited height. The &lt;code&gt;ScrollViewer&lt;/code&gt; therefore asks for the full height of its content and never overflows. In the measurement, 800 px of rows inside a 200 px &lt;code&gt;StackPanel&lt;/code&gt; gave a viewport of 800 and a &lt;code&gt;ScrollableHeight&lt;/code&gt; of 0.&lt;/p&gt;
&lt;h2&gt;
  
  
  The fix
&lt;/h2&gt;

&lt;p&gt;Give the &lt;code&gt;ScrollViewer&lt;/code&gt; a finite height. A star row of a &lt;code&gt;Grid&lt;/code&gt; is the usual way:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;Grid&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Grid.RowDefinitions&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;RowDefinition&lt;/span&gt; &lt;span class="na"&gt;Height=&lt;/span&gt;&lt;span class="s"&gt;"Auto"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;RowDefinition&lt;/span&gt; &lt;span class="na"&gt;Height=&lt;/span&gt;&lt;span class="s"&gt;"*"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/Grid.RowDefinitions&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;TextBlock&lt;/span&gt; &lt;span class="na"&gt;Text=&lt;/span&gt;&lt;span class="s"&gt;"Header"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;ScrollViewer&lt;/span&gt; &lt;span class="na"&gt;Grid.Row=&lt;/span&gt;&lt;span class="s"&gt;"1"&lt;/span&gt; &lt;span class="na"&gt;VerticalScrollBarVisibility=&lt;/span&gt;&lt;span class="s"&gt;"Auto"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="c"&gt;&amp;lt;!-- items --&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/ScrollViewer&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/Grid&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A &lt;code&gt;DockPanel&lt;/code&gt; with the &lt;code&gt;ScrollViewer&lt;/code&gt; as its last child works too, and so does an explicit &lt;code&gt;Height&lt;/code&gt; or &lt;code&gt;MaxHeight&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The same cause breaks ListBox virtualization
&lt;/h2&gt;

&lt;p&gt;A 2,000-item &lt;code&gt;ListBox&lt;/code&gt; placed inside an outer &lt;code&gt;ScrollViewer&lt;/code&gt; or a &lt;code&gt;StackPanel&lt;/code&gt; realized all 2,000 containers, because it was given room for every item. Give the &lt;code&gt;ListBox&lt;/code&gt; itself a constrained height instead of wrapping it.&lt;/p&gt;

&lt;p&gt;A &lt;a href="https://s-iguchi09.github.io/ja/articles/wpf-scrollviewer-not-scrolling/" rel="noopener noreferrer"&gt;Japanese version&lt;/a&gt; is also available.&lt;/p&gt;

&lt;h2&gt;
  
  
  Related Articles
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://s-iguchi09.github.io/articles/wpf-listbox-virtualization-selecteditems/" rel="noopener noreferrer"&gt;How to Prevent SelectedItems from Appearing Lost in a Virtualized WPF ListBox&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://s-iguchi09.github.io/articles/wpf-collectionviewsource-filter-not-refreshing/" rel="noopener noreferrer"&gt;Causes of a Stale ICollectionView Filter in WPF and Choosing Between Refresh and Live Filtering&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://s-iguchi09.github.io/articles/wpf-fluent-thememode-runtime-switch/" rel="noopener noreferrer"&gt;Diagnosing Why Parts of a WPF App Stay Light After Switching ThemeMode at Runtime&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://s-iguchi09.github.io/articles/wpf-label-vs-textblock-performance/" rel="noopener noreferrer"&gt;Why WPF Slows Down with Many Labels and When to Switch to TextBlock&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://s-iguchi09.github.io/articles/wpf-tray-contextmenu-close-on-focus-loss/" rel="noopener noreferrer"&gt;Fixing a WPF Tray ContextMenu That Does Not Close on Focus Loss&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://s-iguchi09.github.io/apps/wpf-standard-control-demo/scrollviewer.html" rel="noopener noreferrer"&gt;ScrollViewer | WPF Standard Control Demo App (.NET 10)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>wpf</category>
      <category>dotnet</category>
      <category>csharp</category>
    </item>
    <item>
      <title>Why WPF Style Triggers and DataTriggers Do Not Apply — Dependency Property Value Precedence</title>
      <dc:creator>s-iguchi09</dc:creator>
      <pubDate>Wed, 09 Sep 2026 14:13:42 +0000</pubDate>
      <link>https://dev.to/s-iguchi09/why-wpf-style-triggers-and-datatriggers-do-not-apply-dependency-property-value-precedence-1ebg</link>
      <guid>https://dev.to/s-iguchi09/why-wpf-style-triggers-and-datatriggers-do-not-apply-dependency-property-value-precedence-1ebg</guid>
      <description>&lt;p&gt;A &lt;code&gt;DataTrigger&lt;/code&gt; in &lt;code&gt;Style.Triggers&lt;/code&gt; should turn a &lt;code&gt;Border&lt;/code&gt; pink when &lt;code&gt;HasError&lt;/code&gt; is &lt;code&gt;true&lt;/code&gt;. The binding resolves, the Output window is clean, and the background stays white. The trigger did fire. Its value simply lost to another one.&lt;/p&gt;

&lt;p&gt;This is a short summary. The full article, with &lt;code&gt;BaseValueSource&lt;/code&gt; readings for each case on .NET 10, is here:&lt;br&gt;
&lt;strong&gt;&lt;a href="https://s-iguchi09.github.io/articles/wpf-style-trigger-not-working-local-value/" rel="noopener noreferrer"&gt;Why WPF Style Triggers and DataTriggers Do Not Apply — Dependency Property Value Precedence&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  The cause: a local value
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;Background="White"&lt;/code&gt; written on the element is a local value. Local values outrank style triggers, and style triggers outrank style setters. &lt;code&gt;DependencyPropertyHelper.GetValueSource&lt;/code&gt; reports &lt;code&gt;Local&lt;/code&gt; on the broken element. Note that &lt;code&gt;{Binding ...}&lt;/code&gt; or &lt;code&gt;{DynamicResource ...}&lt;/code&gt; written on the element is also a local value.&lt;/p&gt;
&lt;h2&gt;
  
  
  The fix
&lt;/h2&gt;

&lt;p&gt;Move the default out of the element and into the style:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;Style&lt;/span&gt; &lt;span class="na"&gt;x:Key=&lt;/span&gt;&lt;span class="s"&gt;"StatusBox"&lt;/span&gt; &lt;span class="na"&gt;TargetType=&lt;/span&gt;&lt;span class="s"&gt;"Border"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Setter&lt;/span&gt; &lt;span class="na"&gt;Property=&lt;/span&gt;&lt;span class="s"&gt;"Background"&lt;/span&gt; &lt;span class="na"&gt;Value=&lt;/span&gt;&lt;span class="s"&gt;"White"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Style.Triggers&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;DataTrigger&lt;/span&gt; &lt;span class="na"&gt;Binding=&lt;/span&gt;&lt;span class="s"&gt;"{Binding HasError}"&lt;/span&gt; &lt;span class="na"&gt;Value=&lt;/span&gt;&lt;span class="s"&gt;"True"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;Setter&lt;/span&gt; &lt;span class="na"&gt;Property=&lt;/span&gt;&lt;span class="s"&gt;"Background"&lt;/span&gt; &lt;span class="na"&gt;Value=&lt;/span&gt;&lt;span class="s"&gt;"#FFD4D4"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/DataTrigger&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/Style.Triggers&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/Style&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  From code-behind
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;border.Background = ...&lt;/code&gt; creates a local value and blocks the trigger again.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;SetCurrentValue&lt;/code&gt; changes the value without creating one, but it does not remove a local value that is already there.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ClearValue&lt;/code&gt; removes it, along with any binding on that property.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The full article also covers theme triggers that a local &lt;code&gt;Foreground&lt;/code&gt; silently disables.&lt;/p&gt;

&lt;p&gt;A &lt;a href="https://s-iguchi09.github.io/ja/articles/wpf-style-trigger-not-working-local-value/" rel="noopener noreferrer"&gt;Japanese version&lt;/a&gt; is also available.&lt;/p&gt;

&lt;h2&gt;
  
  
  Related Articles
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://s-iguchi09.github.io/articles/wpf-binding-error-debugging-output-window/" rel="noopener noreferrer"&gt;Reading WPF Binding Errors and Diagnosing Them with the Output Window&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://s-iguchi09.github.io/articles/wpf-usercontrol-dependencyproperty-binding-not-working/" rel="noopener noreferrer"&gt;Binding to a WPF UserControl's Own Dependency Property from Inside the Control&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://s-iguchi09.github.io/articles/wpf-treeview-select-item-programmatically/" rel="noopener noreferrer"&gt;Selecting and Expanding a WPF TreeView Node from Code, and Why SelectedItem Is Read-Only&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://s-iguchi09.github.io/articles/wpf-staticresource-vs-dynamicresource/" rel="noopener noreferrer"&gt;Why StaticResource Changes Are Not Reflected in WPF and How to Fix It&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://s-iguchi09.github.io/articles/wpf-binding-stringformat-number-currency-date/" rel="noopener noreferrer"&gt;Formatting Numbers, Currency, and Dates with Binding.StringFormat in WPF&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://s-iguchi09.github.io/articles/wpf-label-underscore-issue/" rel="noopener noreferrer"&gt;Why WPF Label Hides Underscores and How to Fix It&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://s-iguchi09.github.io/articles/wpf-datepicker-custom-format/" rel="noopener noreferrer"&gt;Customising the DatePicker Display Format in WPF&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>wpf</category>
      <category>dotnet</category>
      <category>csharp</category>
    </item>
    <item>
      <title>Controls with Custom Styles Fall Back to the Old Look Under the WPF Fluent Theme</title>
      <dc:creator>s-iguchi09</dc:creator>
      <pubDate>Tue, 08 Sep 2026 16:14:33 +0000</pubDate>
      <link>https://dev.to/s-iguchi09/controls-with-custom-styles-fall-back-to-the-old-look-under-the-wpf-fluent-theme-46ah</link>
      <guid>https://dev.to/s-iguchi09/controls-with-custom-styles-fall-back-to-the-old-look-under-the-wpf-fluent-theme-46ah</guid>
      <description>&lt;p&gt;You set &lt;code&gt;ThemeMode="Light"&lt;/code&gt; in &lt;code&gt;App.xaml&lt;/code&gt;, and check boxes turn Fluent while every &lt;code&gt;Button&lt;/code&gt; keeps square corners and a grey background. The only suspect is a &lt;code&gt;&amp;lt;Style TargetType="Button"&amp;gt;&lt;/code&gt; that sets nothing but &lt;code&gt;Padding&lt;/code&gt;. There is no error and no warning.&lt;/p&gt;

&lt;p&gt;This is a short summary. The full article, with a table of style placements measured on .NET 9 and .NET 10, is here:&lt;br&gt;
&lt;strong&gt;&lt;a href="https://s-iguchi09.github.io/articles/wpf-fluent-theme-custom-style-not-applied/" rel="noopener noreferrer"&gt;Controls with Custom Styles Fall Back to the Old Look Under the WPF Fluent Theme&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why one setter drops the whole theme
&lt;/h2&gt;

&lt;p&gt;Older themes such as Aero2 come in as the theme style, which still supplies the template under your own style. Fluent comes in differently: &lt;code&gt;ThemeMode&lt;/code&gt; merges a resource dictionary of implicit styles keyed by type. Your &lt;code&gt;{x:Type Button}&lt;/code&gt; style has the same key and wins, so the Fluent template is never used. &lt;code&gt;Style="{x:Null}"&lt;/code&gt; gives the same legacy look.&lt;/p&gt;

&lt;h2&gt;
  
  
  The fix, and the trap inside it
&lt;/h2&gt;

&lt;p&gt;Inherit Fluent with &lt;code&gt;BasedOn="{StaticResource {x:Type Button}}"&lt;/code&gt;. Written directly in &lt;code&gt;Application.Resources&lt;/code&gt;, though, it silently resolves to &lt;code&gt;null&lt;/code&gt;. In the measurements, that happened whenever the referenced key equals the style's own key and also exists in a dictionary merged into the one declaring the style.&lt;/p&gt;

&lt;p&gt;The layout that worked:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Set &lt;code&gt;ThemeMode&lt;/code&gt; on &lt;code&gt;Application&lt;/code&gt;, not on a &lt;code&gt;Window&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Move the style into its own &lt;code&gt;Styles.xaml&lt;/code&gt; and merge that file from &lt;code&gt;App.xaml&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Do not merge &lt;code&gt;Fluent.xaml&lt;/code&gt; inside that file.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;Style&lt;/span&gt; &lt;span class="na"&gt;TargetType=&lt;/span&gt;&lt;span class="s"&gt;"Button"&lt;/span&gt; &lt;span class="na"&gt;BasedOn=&lt;/span&gt;&lt;span class="s"&gt;"{StaticResource {x:Type Button}}"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Setter&lt;/span&gt; &lt;span class="na"&gt;Property=&lt;/span&gt;&lt;span class="s"&gt;"Padding"&lt;/span&gt; &lt;span class="na"&gt;Value=&lt;/span&gt;&lt;span class="s"&gt;"16,6"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/Style&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check the result by eye. A non-null &lt;code&gt;BasedOn&lt;/code&gt; can still point at the old theme.&lt;/p&gt;

&lt;p&gt;A &lt;a href="https://s-iguchi09.github.io/ja/articles/wpf-fluent-theme-custom-style-not-applied/" rel="noopener noreferrer"&gt;Japanese version&lt;/a&gt; is also available.&lt;/p&gt;

&lt;h2&gt;
  
  
  Related Articles
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://s-iguchi09.github.io/articles/wpf-fluent-design-with-systemcolors/" rel="noopener noreferrer"&gt;Applying Fluent Design in WPF Without Extra Libraries&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://s-iguchi09.github.io/articles/wpf-fluent-textbox-hide-clear-button/" rel="noopener noreferrer"&gt;Hiding the Clear Button on a Fluent-Themed WPF TextBox&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://s-iguchi09.github.io/articles/wpf-staticresource-vs-dynamicresource/" rel="noopener noreferrer"&gt;Why StaticResource Changes Are Not Reflected in WPF and How to Fix It&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://s-iguchi09.github.io/articles/csharp-natural-sort-strcmplogicalw-icomparer/" rel="noopener noreferrer"&gt;Replicating Windows Explorer Sort Order in C# with StrCmpLogicalW and IComparer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://s-iguchi09.github.io/apps/wpf-standard-control-demo.html" rel="noopener noreferrer"&gt;WPF Standard Control Demo App (.NET 10)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>wpf</category>
      <category>dotnet</category>
      <category>csharp</category>
    </item>
  </channel>
</rss>
