Skip to content

Conversation

@ChrisPulman
Copy link
Member

What kind of change does this PR introduce?

Fixes #4214

What is the current behavior?

#4214

What is the new behavior?

Adds tests and refactors PropertyBinderImplementation to ensure that BindTo only sets nested properties once per value, even when the host or nested object is replaced.
This prevents redundant setter invocations and ensures correct property update semantics for nested bindings across platforms.

What might this PR break?

One less value should be emitted from BindTo when used in the two-way binding manner as shown in #4214

Please check if the PR fulfills these requirements

  • Tests for the changes have been added (for bug fixes / features)
  • Docs have been added / updated (for bug fixes / features)

Other information:

Adds tests and refactors PropertyBinderImplementation to ensure that BindTo only sets nested properties once per value, even when the host or nested object is replaced. This prevents redundant setter invocations and ensures correct property update semantics for nested bindings across platforms.
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes issue #4214 by refactoring PropertyBinderImplementation to prevent redundant setter calls during nested property binding operations. The implementation adds equality checks and state tracking to ensure nested properties are set only once per value, even when host objects are replaced.

Key Changes

  • Refactored SetThenGet to return a tuple indicating whether the value changed and should be emitted
  • Implemented state tracking in nested property bindings using Observable.Create with latestHost, currentHost, and lastObservedValue variables
  • Added equality comparisons before invoking setters to avoid redundant calls when values haven't changed

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 5 comments.

File Description
src/ReactiveUI/Bindings/Property/PropertyBinderImplementation.cs Core fix implementing deduplication logic for nested property bindings, adds state tracking for host and value changes, and modifies EvalBindingHooks to require IViewFor constraint
src/ReactiveUI.Tests/Bindings/BindToNestedPropertyTests.cs New test file with three test cases verifying single setter invocation behavior for nested properties in various scenarios including host replacement
src/ReactiveUI.Tests/Platforms/windows-xaml/PropertyBindingTest.cs Adds two test cases for nested property binding behavior and corrects test method name from ViewToViewModel to ViewModelToView
src/ReactiveUI.Tests/Platforms/winforms/DefaultPropertyBindingTests.cs Minor style improvements converting multi-line methods to expression-bodied members

Renamed a test method for clarity, improved property setter logic in TrackingHostViewModel to only raise notifications and increment SetCallCount on value changes, and removed an unnecessary assignment in PropertyBinderImplementation.
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated 8 comments.

@codecov
Copy link

codecov bot commented Dec 21, 2025

Codecov Report

❌ Patch coverage is 82.65306% with 17 lines in your changes missing coverage. Please review.
✅ Project coverage is 40.77%. Comparing base (fe2a8c7) to head (db640b3).
⚠️ Report is 4 commits behind head on main.

Files with missing lines Patch % Lines
.../Bindings/Property/PropertyBinderImplementation.cs 82.65% 5 Missing and 12 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #4240      +/-   ##
==========================================
+ Coverage   40.33%   40.77%   +0.44%     
==========================================
  Files         146      146              
  Lines        6655     6744      +89     
  Branches     1025     1038      +13     
==========================================
+ Hits         2684     2750      +66     
- Misses       3779     3794      +15     
- Partials      192      200       +8     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@ChrisPulman
Copy link
Member Author

@copilot open a new pull request to apply changes based on the comments in this thread

Copy link
Contributor

Copilot AI commented Dec 21, 2025

@ChrisPulman I've opened a new pull request, #4241, to work on those changes. Once the pull request is ready, I'll request review from you.

Copilot AI added a commit that referenced this pull request Dec 21, 2025
- Fix type mismatch in EvalBindingHooks call (pass object, IViewFor type args)
- Add synchronization to hostChanges to prevent race conditions
- Convert static SetCallCount to instance-level in BindToNestedPropertyTests
- Update ViewModel property to use RaiseAndSetIfChanged pattern
- Fix test expectations after converting to instance counters
- Remove redundant using directives from PropertyBindingTest.cs
- Fix test expectation for deduplicated setter calls (9 -> 3)
- Remove readonly modifier from _nested field to allow RaiseAndSetIfChanged

Co-authored-by: ChrisPulman <[email protected]>
Addresses code review comments from the nested property binding fix,
focusing on type safety, thread safety, and test maintainability.

## Changes

**Type Safety**
- Fixed `EvalBindingHooks` call to provide both required type arguments
`<object, IViewFor>` (was missing second type parameter causing
compilation error)

**Thread Safety**
- Added `.Synchronize()` to `hostChanges` observable to prevent race
conditions between `hostDisposable` and `changeDisposable` subscriptions
accessing shared state variables

**Test Infrastructure**
- Converted `SetCallCount` from static to instance-level properties in
test classes to prevent test isolation issues during parallel execution
- Updated test expectations to match instance-level counting behavior
(9→1 for per-instance tests, 9→3 for deduplication tests)

**Code Cleanup**
- Removed redundant using directives already declared as global usings
- Removed `readonly` modifier from `_nested` field to allow
`RaiseAndSetIfChanged`
- Fixed property initializer structure to use explicit backing field
pattern

All tests passing (294/294) across .NET 8.0, 9.0, and 10.0.

<!-- START COPILOT CODING AGENT TIPS -->
---

💬 We'd love your input! Share your thoughts on Copilot coding agent in
our [2 minute survey](https://gh.io/copilot-coding-agent-survey).

---------

Co-authored-by: copilot-swe-agent[bot] <[email protected]>
Co-authored-by: ChrisPulman <[email protected]>
@ChrisPulman ChrisPulman merged commit be0eb89 into main Dec 21, 2025
6 checks passed
@ChrisPulman ChrisPulman deleted the FixBindTo branch December 21, 2025 17:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: BindTo pushes data to old nested objects

3 participants