Repository navigation
fix(ui): mirror the page host so an RTL language applies on startup - #94
Merged
Merged
Conversation
PART_FrameCP is the ContentPresenter that hosts every page, and it does not pick the inherited FlowDirection up when the template is applied. It only landed on the next change of the property, so with fa-IR, ar-SA or he-IL already stored in appsettings.json the whole content area stayed left to right on a cold start. Switching to an LTR language and back was the only way out.
The parent NavigationViewContentPresenter was already right to left, which is why the navigation pane mirrored correctly while the content did not, and why the dashboard looked right while the optimize page did not.
Both page hosts need it. There are two NavigationViewContentPresenter templates in this file: the pane templates, used by the main navigation, and the scrollable top template, which OptimizePage uses for its category tabs. Fixing only the first left the optimize page left to right.
Binding the property off the templated parent also covers a direction change at runtime. Left to right is unaffected, the binding resolves to LeftToRight there.
Verified by walking the live visual tree of a cold start with fa-IR stored, before and after, and by replaying the reported workaround. Before:
NavigationViewContentPresenter RightToLeft
ContentPresenter LeftToRight <-- page host, left to right at startup
after switching to en-US and back to fa-IR:
ContentPresenter RightToLeft
After the fix the page host is right to left on the cold start, OptimizePage and its category page inherit it, and the only remaining LeftToRight elements are the window chrome above MainWindow's root grid (AdornerDecorator, ClientAreaBorder, its ContentPresenter, AdornerLayer), which is outside the app content.
This is layout direction only. Rows that hardcode HorizontalAlignment or rely on the child order of a StackPanel or WrapPanel are still left to right inside the now mirrored pages, because WPF mirrors text and TextAlignment and no layout. That is separate work.
No test covers a ControlTemplate binding. Full suite with -longRunning 30: 755 total, 0 failed.
itsfatduck
approved these changes
Oct 10, 2026
itsfatduck
left a comment
Owner
There was a problem hiding this comment.
Thank you very much for fixing this bug!
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes right-to-left languages rendering left to right on a cold start.
Cause
PART_FrameCPis theContentPresenterthat hosts every page. It does not pick the inheritedFlowDirectionup when the template is applied, so withfa-IR,ar-SAorhe-ILalready stored inappsettings.jsonthe whole content area stayed left to right. It only landed on the next change of the property, which made "switch to an LTR language and back" the only way out.The parent
NavigationViewContentPresenterwas already right to left, so the navigation pane mirrored correctly while the content did not.Fix
Bind
FlowDirectionoff the templated parent on both page hosts. There are twoNavigationViewContentPresentertemplates inNavigationViewOverride.xaml: the pane templates used by the main navigation, and the scrollable top template thatOptimizePageuses for its category tabs. One file, 18 lines.Left to right is unaffected: the binding resolves to
LeftToRightthere, and it also covers a language change at runtime.Verification
Walked the live visual tree of a cold start with
fa-IRstored, before and after, and replayed the reported workaround.Before:
After the fix, on the cold start:
No element is left to right under a right to left ancestor except the window chrome above
MainWindow's root grid (AdornerDecorator,ClientAreaBorder, itsContentPresenter,AdornerLayer), which is outside the app content.dotnet build optimizerDuck.slnx --configuration Release: 0 warnings, 0 errors-longRunning 30:Total: 755, Errors: 0, Failed: 0, Skipped: 5csharpier check .: clean (302 files)Scope
Direction only, deliberately. This is what made the reported symptom reproducible and fixable in one place; anything else that is still left to right inside a mirrored page is separate work and not guessed at here.
No test covers a
ControlTemplatebinding, which is why the visual tree dump is the evidence.