From 0589eabd9d23ef43bfcbfaa445147c2aef1aaf21 Mon Sep 17 00:00:00 2001 From: Ondrej Roztocil Date: Wed, 25 Jun 2025 22:12:59 +0200 Subject: [PATCH 1/5] Working WIP implementation --- .../src/RenderTree/RenderTreeDiffBuilder.cs | 17 +++++-- .../BlazorUnitedApp/Pages/Counter.razor | 33 ++++++++++++- .../src/Rendering/Events/EventDelegator.ts | 48 ++++++++++++++++--- 3 files changed, 86 insertions(+), 12 deletions(-) diff --git a/src/Components/Components/src/RenderTree/RenderTreeDiffBuilder.cs b/src/Components/Components/src/RenderTree/RenderTreeDiffBuilder.cs index a4c3ebbf2a6e..336d93605e11 100644 --- a/src/Components/Components/src/RenderTree/RenderTreeDiffBuilder.cs +++ b/src/Components/Components/src/RenderTree/RenderTreeDiffBuilder.cs @@ -38,7 +38,7 @@ public static RenderTreeDiff ComputeDiff( } public static void DisposeFrames(RenderBatchBuilder batchBuilder, int componentId, ArrayRange frames) - => DisposeFramesInRange(batchBuilder, componentId, frames.Array, 0, frames.Count); + => DisposeFramesInRange(batchBuilder, componentId, frames.Array, 0, frames.Count, 0); private static void AppendDiffEntriesForRange( ref DiffContext diffContext, @@ -867,7 +867,7 @@ private static void RemoveOldFrame(ref DiffContext diffContext, int oldFrameInde case RenderTreeFrameType.Element: { var endIndexExcl = oldFrameIndex + oldFrame.ElementSubtreeLengthField; - DisposeFramesInRange(diffContext.BatchBuilder, diffContext.ComponentId, oldTree, oldFrameIndex, endIndexExcl); + DisposeFramesInRange(diffContext.BatchBuilder, diffContext.ComponentId, oldTree, oldFrameIndex, endIndexExcl, diffContext.SiblingIndex); diffContext.Edits.Append(RenderTreeEdit.RemoveFrame(diffContext.SiblingIndex)); break; } @@ -1013,7 +1013,7 @@ private static void InitializeNewNamedEvent(ref DiffContext diffContext, int new diffContext.BatchBuilder.AddNamedEvent(diffContext.ComponentId, newTreeFrameIndex, ref diffContext.NewTree[newTreeFrameIndex]); } - private static void DisposeFramesInRange(RenderBatchBuilder batchBuilder, int componentId, RenderTreeFrame[] frames, int startIndex, int endIndexExcl) + private static void DisposeFramesInRange(RenderBatchBuilder batchBuilder, int componentId, RenderTreeFrame[] frames, int startIndex, int endIndexExcl, int siblingIndex) { for (var i = startIndex; i < endIndexExcl; i++) { @@ -1022,9 +1022,16 @@ private static void DisposeFramesInRange(RenderBatchBuilder batchBuilder, int co { batchBuilder.ComponentDisposalQueue.Enqueue(frame.ComponentIdField); } - else if (frame.FrameTypeField == RenderTreeFrameType.Attribute && frame.AttributeEventHandlerIdField > 0) + else if (frame.FrameTypeField == RenderTreeFrameType.Attribute) { - batchBuilder.DisposedEventHandlerIds.Append(frame.AttributeEventHandlerIdField); + if (frame.AttributeEventHandlerIdField > 0) + { + batchBuilder.DisposedEventHandlerIds.Append(frame.AttributeEventHandlerIdField); + } + else if (frame.AttributeValueField is bool boolValue && boolValue && frame.AttributeNameField.StartsWith("__internal_", StringComparison.Ordinal)) + { + batchBuilder.EditsBuffer.Append(RenderTreeEdit.RemoveAttribute(siblingIndex, frame.AttributeNameField)); + } } else if (frame.FrameTypeField == RenderTreeFrameType.NamedEvent) { diff --git a/src/Components/Samples/BlazorUnitedApp/Pages/Counter.razor b/src/Components/Samples/BlazorUnitedApp/Pages/Counter.razor index 0d2acac011ab..557c01c3b96b 100644 --- a/src/Components/Samples/BlazorUnitedApp/Pages/Counter.razor +++ b/src/Components/Samples/BlazorUnitedApp/Pages/Counter.razor @@ -1,18 +1,49 @@ @page "/counter" @rendermode InteractiveServer + Counter

Counter

Current count: @currentCount

+

showElements: @showElements

+

preventDefault: @preventDefault

+ +@if (showElements) +{ + +} - +

+ + +

@code { private int currentCount = 0; + private bool showElements = true; + private bool preventDefault = true; private void IncrementCount() { currentCount++; } + + void ToggleShow() + { + showElements = !showElements; + StateHasChanged(); + } + + void TogglePreventDefault() + { + preventDefault = !preventDefault; + StateHasChanged(); + } } diff --git a/src/Components/Web.JS/src/Rendering/Events/EventDelegator.ts b/src/Components/Web.JS/src/Rendering/Events/EventDelegator.ts index 0edd38880775..84d554c63f9d 100644 --- a/src/Components/Web.JS/src/Rendering/Events/EventDelegator.ts +++ b/src/Components/Web.JS/src/Rendering/Events/EventDelegator.ts @@ -121,6 +121,11 @@ export class EventDelegator { for (const handlerInfo of infosForElement.enumerateHandlers()) { this.eventInfoStore.remove(handlerInfo.eventHandlerId); } + + for (const eventName of infosForElement.enumeratedEventNamesForEnabledFlags()) { + this.eventInfoStore.decrementCountByEventName(eventName); + } + delete element[this.eventsCollectionKey]; } } @@ -135,12 +140,26 @@ export class EventDelegator { public setStopPropagation(element: Element, eventName: string, value: boolean): void { const infoForElement = this.getEventHandlerInfosForElement(element, true)!; + const currentValue = infoForElement.stopPropagation(eventName); infoForElement.stopPropagation(eventName, value); + + if (!currentValue && value) { + this.eventInfoStore.addGlobalListener(eventName); + } else if (currentValue && !value) { + this.eventInfoStore.decrementCountByEventName(eventName); + } } public setPreventDefault(element: Element, eventName: string, value: boolean): void { const infoForElement = this.getEventHandlerInfosForElement(element, true)!; + const currentValue = infoForElement.preventDefault(eventName); infoForElement.preventDefault(eventName, value); + + if (!currentValue && value) { + this.eventInfoStore.addGlobalListener(eventName); + } else if (currentValue && !value) { + this.eventInfoStore.decrementCountByEventName(eventName); + } } private onGlobalEvent(evt: Event) { @@ -298,16 +317,19 @@ class EventInfoStore { // If this event name is an alias, update the global listener for the corresponding browser event const eventName = getBrowserEventName(info.eventName); - - if (--this.countByEventName[eventName] === 0) { - delete this.countByEventName[eventName]; - document.removeEventListener(eventName, this.globalListener); - } + this.decrementCountByEventName(eventName); } return info; } + public decrementCountByEventName(eventName: string) { + if (--this.countByEventName[eventName] === 0) { + delete this.countByEventName[eventName]; + document.removeEventListener(eventName, this.globalListener); + } + } + private handleEventNameAliasAdded(aliasEventName, browserEventName) { // If an event name alias gets registered later, we need to update the global listener // registrations to match. This makes it equivalent to the alias having been registered @@ -338,7 +360,7 @@ class EventHandlerInfosForElement { private stopPropagationFlags: { [eventName: string]: boolean } | null = null; - public *enumerateHandlers() : IterableIterator { + public *enumerateHandlers(): IterableIterator { for (const eventName in this.handlers) { if (Object.prototype.hasOwnProperty.call(this.handlers, eventName)) { yield this.handlers[eventName]; @@ -346,6 +368,20 @@ class EventHandlerInfosForElement { } } + public *enumeratedEventNamesForEnabledFlags(): IterableIterator { + for (const eventName in this.preventDefaultFlags) { + if (this.preventDefaultFlags[eventName] === true) { + yield eventName; + } + } + + for (const eventName in this.stopPropagationFlags) { + if (this.stopPropagationFlags[eventName] === true) { + yield eventName; + } + } + } + public getHandler(eventName: string): EventHandlerInfo | null { return Object.prototype.hasOwnProperty.call(this.handlers, eventName) ? this.handlers[eventName] : null; } From e6178b7df28c377fc907f9bbe65f2c9a07f60b4f Mon Sep 17 00:00:00 2001 From: Ondrej Roztocil Date: Fri, 27 Jun 2025 13:34:04 +0200 Subject: [PATCH 2/5] Simplify internal attribute clean up --- .../src/RenderTree/RenderTreeDiffBuilder.cs | 17 +++++----------- .../src/Rendering/Events/EventDelegator.ts | 20 +------------------ 2 files changed, 6 insertions(+), 31 deletions(-) diff --git a/src/Components/Components/src/RenderTree/RenderTreeDiffBuilder.cs b/src/Components/Components/src/RenderTree/RenderTreeDiffBuilder.cs index 336d93605e11..a4c3ebbf2a6e 100644 --- a/src/Components/Components/src/RenderTree/RenderTreeDiffBuilder.cs +++ b/src/Components/Components/src/RenderTree/RenderTreeDiffBuilder.cs @@ -38,7 +38,7 @@ public static RenderTreeDiff ComputeDiff( } public static void DisposeFrames(RenderBatchBuilder batchBuilder, int componentId, ArrayRange frames) - => DisposeFramesInRange(batchBuilder, componentId, frames.Array, 0, frames.Count, 0); + => DisposeFramesInRange(batchBuilder, componentId, frames.Array, 0, frames.Count); private static void AppendDiffEntriesForRange( ref DiffContext diffContext, @@ -867,7 +867,7 @@ private static void RemoveOldFrame(ref DiffContext diffContext, int oldFrameInde case RenderTreeFrameType.Element: { var endIndexExcl = oldFrameIndex + oldFrame.ElementSubtreeLengthField; - DisposeFramesInRange(diffContext.BatchBuilder, diffContext.ComponentId, oldTree, oldFrameIndex, endIndexExcl, diffContext.SiblingIndex); + DisposeFramesInRange(diffContext.BatchBuilder, diffContext.ComponentId, oldTree, oldFrameIndex, endIndexExcl); diffContext.Edits.Append(RenderTreeEdit.RemoveFrame(diffContext.SiblingIndex)); break; } @@ -1013,7 +1013,7 @@ private static void InitializeNewNamedEvent(ref DiffContext diffContext, int new diffContext.BatchBuilder.AddNamedEvent(diffContext.ComponentId, newTreeFrameIndex, ref diffContext.NewTree[newTreeFrameIndex]); } - private static void DisposeFramesInRange(RenderBatchBuilder batchBuilder, int componentId, RenderTreeFrame[] frames, int startIndex, int endIndexExcl, int siblingIndex) + private static void DisposeFramesInRange(RenderBatchBuilder batchBuilder, int componentId, RenderTreeFrame[] frames, int startIndex, int endIndexExcl) { for (var i = startIndex; i < endIndexExcl; i++) { @@ -1022,16 +1022,9 @@ private static void DisposeFramesInRange(RenderBatchBuilder batchBuilder, int co { batchBuilder.ComponentDisposalQueue.Enqueue(frame.ComponentIdField); } - else if (frame.FrameTypeField == RenderTreeFrameType.Attribute) + else if (frame.FrameTypeField == RenderTreeFrameType.Attribute && frame.AttributeEventHandlerIdField > 0) { - if (frame.AttributeEventHandlerIdField > 0) - { - batchBuilder.DisposedEventHandlerIds.Append(frame.AttributeEventHandlerIdField); - } - else if (frame.AttributeValueField is bool boolValue && boolValue && frame.AttributeNameField.StartsWith("__internal_", StringComparison.Ordinal)) - { - batchBuilder.EditsBuffer.Append(RenderTreeEdit.RemoveAttribute(siblingIndex, frame.AttributeNameField)); - } + batchBuilder.DisposedEventHandlerIds.Append(frame.AttributeEventHandlerIdField); } else if (frame.FrameTypeField == RenderTreeFrameType.NamedEvent) { diff --git a/src/Components/Web.JS/src/Rendering/Events/EventDelegator.ts b/src/Components/Web.JS/src/Rendering/Events/EventDelegator.ts index 84d554c63f9d..ed0b653c6123 100644 --- a/src/Components/Web.JS/src/Rendering/Events/EventDelegator.ts +++ b/src/Components/Web.JS/src/Rendering/Events/EventDelegator.ts @@ -122,10 +122,6 @@ export class EventDelegator { this.eventInfoStore.remove(handlerInfo.eventHandlerId); } - for (const eventName of infosForElement.enumeratedEventNamesForEnabledFlags()) { - this.eventInfoStore.decrementCountByEventName(eventName); - } - delete element[this.eventsCollectionKey]; } } @@ -360,7 +356,7 @@ class EventHandlerInfosForElement { private stopPropagationFlags: { [eventName: string]: boolean } | null = null; - public *enumerateHandlers(): IterableIterator { + public *enumerateHandlers() : IterableIterator { for (const eventName in this.handlers) { if (Object.prototype.hasOwnProperty.call(this.handlers, eventName)) { yield this.handlers[eventName]; @@ -368,20 +364,6 @@ class EventHandlerInfosForElement { } } - public *enumeratedEventNamesForEnabledFlags(): IterableIterator { - for (const eventName in this.preventDefaultFlags) { - if (this.preventDefaultFlags[eventName] === true) { - yield eventName; - } - } - - for (const eventName in this.stopPropagationFlags) { - if (this.stopPropagationFlags[eventName] === true) { - yield eventName; - } - } - } - public getHandler(eventName: string): EventHandlerInfo | null { return Object.prototype.hasOwnProperty.call(this.handlers, eventName) ? this.handlers[eventName] : null; } From 946c0a215e793b5386e19e2071c32ef40b920a05 Mon Sep 17 00:00:00 2001 From: Ondrej Roztocil Date: Fri, 27 Jun 2025 14:30:29 +0200 Subject: [PATCH 3/5] Use active event listener when using preventDefault for wheel and touch events --- .../BlazorUnitedApp/Pages/Counter.razor | 6 ++++- .../src/Rendering/Events/EventDelegator.ts | 25 ++++++++++++++++++- 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/src/Components/Samples/BlazorUnitedApp/Pages/Counter.razor b/src/Components/Samples/BlazorUnitedApp/Pages/Counter.razor index 557c01c3b96b..89353e87a8b2 100644 --- a/src/Components/Samples/BlazorUnitedApp/Pages/Counter.razor +++ b/src/Components/Samples/BlazorUnitedApp/Pages/Counter.razor @@ -11,12 +11,16 @@ @if (showElements) { +
+ Scroll here +
+ } -

+

diff --git a/src/Components/Web.JS/src/Rendering/Events/EventDelegator.ts b/src/Components/Web.JS/src/Rendering/Events/EventDelegator.ts index ed0b653c6123..b0fd5e7fe793 100644 --- a/src/Components/Web.JS/src/Rendering/Events/EventDelegator.ts +++ b/src/Components/Web.JS/src/Rendering/Events/EventDelegator.ts @@ -152,7 +152,11 @@ export class EventDelegator { infoForElement.preventDefault(eventName, value); if (!currentValue && value) { - this.eventInfoStore.addGlobalListener(eventName); + // To ensure that preventDefault works for wheel and touch events,, + // we need to register a listener with the passive mode explicitly disabled. + // Note that this does not change behavior for other events as those + // use active mode by default. + this.eventInfoStore.addActiveGlobalListener(eventName); } else if (currentValue && !value) { this.eventInfoStore.decrementCountByEventName(eventName); } @@ -293,6 +297,25 @@ class EventInfoStore { } } + public addActiveGlobalListener(eventName: string) { + // If this event name is an alias, update the global listener for the corresponding browser event + eventName = getBrowserEventName(eventName); + + // If the listener for this event is already registered, we recreate it to ensure + // that it is using the active mode. + if (Object.prototype.hasOwnProperty.call(this.countByEventName, eventName)) { + this.countByEventName[eventName]++; + document.removeEventListener(eventName, this.globalListener); + } else { + this.countByEventName[eventName] = 1; + } + + // To make delegation work with non-bubbling events, register a 'capture' listener. + // We preserve the non-bubbling behavior by only dispatching such events to the targeted element. + const useCapture = Object.prototype.hasOwnProperty.call(nonBubblingEvents, eventName); + document.addEventListener(eventName, this.globalListener, { capture: useCapture, passive: false }); + } + public update(oldEventHandlerId: number, newEventHandlerId: number) { if (Object.prototype.hasOwnProperty.call(this.infosByEventHandlerId, newEventHandlerId)) { // Should never happen, but we want to know if it does From 150152c973b4211ff7df34b75420c1e8591a061e Mon Sep 17 00:00:00 2001 From: Ondrej Roztocil Date: Tue, 1 Jul 2025 19:27:27 +0200 Subject: [PATCH 4/5] Add E2E tests --- .../test/E2ETest/Tests/EventFlagsTest.cs | 149 ++++++++++++++++++ .../BasicTestApp/EventFlagsComponent.razor | 117 ++++++++++++++ .../test/testassets/BasicTestApp/Index.razor | 3 +- 3 files changed, 268 insertions(+), 1 deletion(-) create mode 100644 src/Components/test/E2ETest/Tests/EventFlagsTest.cs create mode 100644 src/Components/test/testassets/BasicTestApp/EventFlagsComponent.razor diff --git a/src/Components/test/E2ETest/Tests/EventFlagsTest.cs b/src/Components/test/E2ETest/Tests/EventFlagsTest.cs new file mode 100644 index 000000000000..08099a2c85e4 --- /dev/null +++ b/src/Components/test/E2ETest/Tests/EventFlagsTest.cs @@ -0,0 +1,149 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Globalization; +using BasicTestApp; +using Microsoft.AspNetCore.Components.E2ETest.Infrastructure; +using Microsoft.AspNetCore.Components.E2ETest.Infrastructure.ServerFixtures; +using Microsoft.AspNetCore.E2ETesting; +using OpenQA.Selenium; +using OpenQA.Selenium.Interactions; +using Xunit.Abstractions; + +namespace Microsoft.AspNetCore.Components.E2ETest.Tests; + +public class EventFlagsTest : ServerTestBase> +{ + public EventFlagsTest( + BrowserFixture browserFixture, + ToggleExecutionModeServerFixture serverFixture, + ITestOutputHelper output) + : base(browserFixture, serverFixture, output) + { + } + + protected override void InitializeAsyncCore() + { + Navigate(ServerPathBase); + Browser.MountTestComponent(); + } + + [Theory] + [InlineData(true)] + [InlineData(false)] + public void OnMouseDown_WithPreventDefaultEnabled_DoesNotFocusButton(bool handlersEnabled) + { + if (!handlersEnabled) + { + // Disable onmousedown handlers + var toggleHandlers = Browser.Exists(By.Id("toggle-handlers")); + toggleHandlers.Click(); + } + + var button = Browser.Exists(By.Id("mousedown-test-button")); + button.Click(); + + // Check that the button has not gained focus (should not be yellow) + var afterClickBackgroundColor = button.GetCssValue("background-color"); + Assert.DoesNotContain("255, 255, 0", afterClickBackgroundColor); + } + + [Theory] + [InlineData(true)] + [InlineData(false)] + public void OnMouseDown_WithPreventDefaultDisabled_DoesFocusButton(bool handlersEnabled) + { + if (!handlersEnabled) + { + // Disable onmousedown handlers + var toggleHandlers = Browser.Exists(By.Id("toggle-handlers")); + toggleHandlers.Click(); + } + + // Disable preventDefault + var togglePreventDefault = Browser.Exists(By.Id("toggle-prevent-default")); + togglePreventDefault.Click(); + + var button = Browser.Exists(By.Id("mousedown-test-button")); + + // Get the initial background color and check that it is no yellow + var initialBackgroundColor = button.GetCssValue("background-color"); + Assert.DoesNotContain("255, 255, 0", initialBackgroundColor); + + button.Click(); + + // Check that the button has gained focus (yellow background) + var afterClickBackgroundColor = button.GetCssValue("background-color"); + Assert.Contains("255, 255, 0", afterClickBackgroundColor); + } + + [Fact] + public void OnClick_WithStopPropagationEnabled_DoesNotPropagateToParent() + { + var button = Browser.Exists(By.Id("stop-propagation-test-button")); + button.Click(); + + var eventLog = Browser.Exists(By.Id("event-log")); + Assert.Contains("mousedown handler called on child", eventLog.Text); + Assert.DoesNotContain("mousedown handler called on parent", eventLog.Text); + } + + [Fact] + public void OnClick_WithStopPropagationDisabled_PropagatesToParent() + { + // Disable stopPropagation + var toggleStopPropagation = Browser.Exists(By.Id("toggle-stop-propagation")); + toggleStopPropagation.Click(); + + var button = Browser.Exists(By.Id("stop-propagation-test-button")); + button.Click(); + + var eventLog = Browser.Exists(By.Id("event-log")); + Assert.Contains("mousedown handler called on child", eventLog.Text); + Assert.Contains("mousedown handler called on parent", eventLog.Text); + } + + [Fact] + public void OnWheel_WithPreventDefaultEnabled_DoesNotScrollDiv() + { + var scrollableDiv = Browser.Exists(By.Id("wheel-test-area")); + + // Simulate a wheel scroll action + var scrollOrigin = new WheelInputDevice.ScrollOrigin + { + Element = scrollableDiv, + }; + new Actions(Browser) + .ScrollFromOrigin(scrollOrigin, 0, 200) + .Perform(); + + // The Selenium scrolling action always changes the scrollTop property even when the event is prevented. + // For this reason, we do not check for equality with zero. + var newScrollTop = int.Parse(scrollableDiv.GetDomProperty("scrollTop"), CultureInfo.InvariantCulture); + Assert.True(newScrollTop < 3); + } + + [Fact] + public void OnWheel_WithPreventDefaultDisabled_DoesScrollDiv() + { + // Disable preventDefault + var togglePreventDefault = Browser.Exists(By.Id("toggle-prevent-default")); + togglePreventDefault.Click(); + + var scrollableDiv = Browser.Exists(By.Id("wheel-test-area")); + + // Simulate a wheel scroll action + var scrollOrigin = new WheelInputDevice.ScrollOrigin + { + Element = scrollableDiv, + }; + new Actions(Browser) + .ScrollFromOrigin(scrollOrigin, 0, 200) + .Perform(); + + // The Selenium scrolling action is not precise and changes the scrollTop property to e.g. 202 instead of 200. + // For this reason, we do not check for equality with specific value. + var newScrollTop = int.Parse(scrollableDiv.GetDomProperty("scrollTop"), CultureInfo.InvariantCulture); + Assert.True(newScrollTop >= 200); + } +} diff --git a/src/Components/test/testassets/BasicTestApp/EventFlagsComponent.razor b/src/Components/test/testassets/BasicTestApp/EventFlagsComponent.razor new file mode 100644 index 000000000000..0ddba430c567 --- /dev/null +++ b/src/Components/test/testassets/BasicTestApp/EventFlagsComponent.razor @@ -0,0 +1,117 @@ + + +

Event flags

+ +
+

Test Controls

+ + + +
+ +@if (eventHandlersEnabled) +{ +

OnMouseDown handler present

+

OnWheel handler present

+} +else +{ +

OnMouseDown handler not present

+

OnWheel handler not present

+} + +
+

Test Scenarios

+ +
+

Scenario 1: onmousedown:preventDefault

+ +
+ +
+

Scenario 2: onclick:stopPropagation

+
+

Parent container

+ +
+
+ +
+

Scenario 3: wheel preventDefault (passive vs active)

+
+

Try scrolling with mouse wheel in this area.

+

If preventDefault is true, scrolling should be blocked.

+

If preventDefault is false, scrolling should work normally.

+
+

This content makes the area scrollable

+

More

+

More

+
+
+
+
+ +
@eventLog
+ + +@code { + private bool preventDefaultEnabled = true; + private bool stopPropagationEnabled = true; + private bool eventHandlersEnabled = true; + + private string eventLog = string.Empty; + + private void TogglePreventDefault() + { + preventDefaultEnabled = !preventDefaultEnabled; + StateHasChanged(); + } + + private void ToggleStopPropagation() + { + stopPropagationEnabled = !stopPropagationEnabled; + StateHasChanged(); + } + + private void ToggleEventHandlers() + { + eventHandlersEnabled = !eventHandlersEnabled; + StateHasChanged(); + } + + void LogEvent(string message) + { + if (eventLog != string.Empty) + { + eventLog += Environment.NewLine; + } + + eventLog += message; + } + + private void OnChildMouseDown() + { + LogEvent("mousedown handler called on child"); + } + + private void OnParentMouseDown() + { + LogEvent("mousedown handler called on parent"); + } +} diff --git a/src/Components/test/testassets/BasicTestApp/Index.razor b/src/Components/test/testassets/BasicTestApp/Index.razor index 65a22ade2513..6e8d20b391a2 100644 --- a/src/Components/test/testassets/BasicTestApp/Index.razor +++ b/src/Components/test/testassets/BasicTestApp/Index.razor @@ -36,7 +36,8 @@ - + + From 1ddcb925dbeb5cf838b8045081fd06c4f2172d38 Mon Sep 17 00:00:00 2001 From: Ondrej Roztocil Date: Tue, 1 Jul 2025 19:44:50 +0200 Subject: [PATCH 5/5] Rollback manual testing sample --- .../BlazorUnitedApp/Pages/Counter.razor | 37 +------------------ 1 file changed, 1 insertion(+), 36 deletions(-) diff --git a/src/Components/Samples/BlazorUnitedApp/Pages/Counter.razor b/src/Components/Samples/BlazorUnitedApp/Pages/Counter.razor index 89353e87a8b2..0d2acac011ab 100644 --- a/src/Components/Samples/BlazorUnitedApp/Pages/Counter.razor +++ b/src/Components/Samples/BlazorUnitedApp/Pages/Counter.razor @@ -1,53 +1,18 @@ @page "/counter" @rendermode InteractiveServer - Counter

Counter

Current count: @currentCount

-

showElements: @showElements

-

preventDefault: @preventDefault

- -@if (showElements) -{ -
- Scroll here -
- -} - -

- - -

+ @code { private int currentCount = 0; - private bool showElements = true; - private bool preventDefault = true; private void IncrementCount() { currentCount++; } - - void ToggleShow() - { - showElements = !showElements; - StateHasChanged(); - } - - void TogglePreventDefault() - { - preventDefault = !preventDefault; - StateHasChanged(); - } }