UnigramDev/Unigram/develop • 70a965e • 2 files, +72/-17
Reuse the text selection manager across recycled containers
MessageSelector built a TextSelectionManager on load and dropped it on unload,
so a virtualized history allocated one per container per scroll-through, each
registering four routed pointer handlers and two owner subscriptions on the way
in and removing them on the way out.
The manager now takes its content element through Attach rather than only in the
constructor, so one instance can follow a container through its whole life while
the element it watches changes underneath. The four PointerEventHandler
instances move to the constructor: AddHandler and RemoveHandler match by delegate
identity, so they always had to be stable, and creating them once per manager
rather than once per attach costs nothing.
Detach now clears the selection and empties _items. That list holds the
selectable controls the selection was made of, and a manager that outlives its
content would otherwise keep them alive and highlight them again the next time it
was asked. It is also idempotent and leaves _root null, which the two detach
paths on the selector, unload and content change, both rely on. RebuildItems
guards against the detached state because SelectAll is public.
An active selection is therefore dropped when content detaches, where before it
was abandoned with the manager. Nothing observes the difference:
TextSelectionCoordinator holds a weak reference and SelectionChanged has no
subscribers.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
UnigramDev/Unigram/develop • 55e0be3 • 2 files, +16/-10
Wire up button click in text
UnigramDev/Unigram/develop • 1785402 • 1 files, +34/-1
crash-triage: diagnose why the value was wrong, not just that it was
Both rejected PRs this session shared a habit: reaching for a guard as soon as
the faulting value was identified, without establishing how it came to be that
way. "It was null" is where the investigation starts.
Requires tracing back to whatever should have set the value and being able to
name the state that produced it in one sentence, pointing at the code that
creates it. "Somehow it was null" means the diagnosis is unfinished.
Where that lands decides the fix, and the three outcomes want different things:
- the API legitimately returns null and the caller assumed otherwise, where a
guard at the call site is correct;
- something upstream is wired wrong, where a guard hides a permanent bug and
degrades silently instead;
- two things race and the state is merely not there yet, which needs
sequencing rather than a default or an early return.
All three occurred here within a day, so the table names the real examples.
Also notes that a guard shipped without knowing which case applies is still a
guess even when it demonstrably stops the crash — it costs the next person the
evidence, since the reports stop while the bug remains — and that the PR should
state the cause, because that is what a reviewer can actually check.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
#unigram
Post #20520
94
- 🫡 2