Microsoft-ui-xaml: Ein flexiblerer ScrollViewer

Erstellt am 19. Dez. 2018  ·  61Kommentare  ·  Quelle: microsoft/microsoft-ui-xaml

Dies ist eine Vorlage für neue Feature- oder API-Vorschläge. Sie können dies beispielsweise verwenden, um eine neue API für einen vorhandenen Typ oder eine Idee für ein neues UI-Steuerelement vorzuschlagen. Es ist in Ordnung, wenn Sie nicht alle Details haben: Sie können mit der Zusammenfassung und der Begründung beginnen. Dieser Link beschreibt den WinUI-Feature-/API-Vorschlagsprozess: https://github.com/Microsoft/microsoft-ui-xaml-specs/blob/master/docs/feature_proposal_process.md Fügen Sie einen Titel für Ihren Feature- oder API-Vorschlag hinzu. Bitte seien Sie kurz und beschreibend

Vorschlag: ScrollViewer

Zusammenfassung

tl:dr; Stellen Sie ein flexibles und dennoch benutzerfreundliches Scroll- und Zoom-Steuerelement in XAML bereit, das weiterhin genutzt werden kann, wenn Sie auf niedrigere Versionen von Win10 abzielen.

Das ScrollViewer-Steuerelement spielt in jeder Benutzeroberfläche eine entscheidende Rolle, da das Scrollen für Anwendungen und Steuerelemente (Plattform und Nicht-Plattform gleichermaßen) grundlegend ist. Das Steuerelement bietet Schwenk- und Zoomfunktionen zusammen mit Standardrichtlinien und UX (z. B. bewusste Bildlaufleisten, Fokus-/Tastaturinteraktion, Zugänglichkeit, Standardbildlaufanimation usw.). Es muss auch flexibel genug sein, um alltägliche App-Szenarien einfach zu machen und eine Schlüsselkomponente in scrollbasierten Steuerelementen zu sein und sehr fortschrittliche Anwendungsfälle zu bedienen. Die aktuelle Steuerung bietet dieses Maß an Flexibilität nicht.

Begründung

Bitte beschreiben Sie, WARUM die Funktion für alle Entwickler und Benutzer zu WinUI hinzugefügt werden sollte. Gegebenenfalls können Sie auch beschreiben, wie es sich an der aktuellen WinUI-Roadmap und den Prioritäten ausrichtet: https://github.com/Microsoft/microsoft-ui-xaml-specs/blob/master/docs/roadmap.md

Das ScrollViewer-Steuerelement so in das Repository zu bringen, dass es über die öffentlichen APIs der Kernplattform gelegt wird, ist ein wichtiges Sprungbrett, das:

  1. ermöglicht mehr Kontrolle in das Repo (erhöhte Agilität),
  2. gibt Entwicklern eine einfach zu bedienende Steuerung, die die Flexibilität der untergeordneten Plattformfunktionen kombiniert mit den Vorteilen der übergeordneten Framework-Dienste (z. B. Zugänglichkeit) zeigt, und
  3. ermöglicht, dass neuere bildlaufbezogene Funktionen in XAML in früheren Versionen von Win10 aufleuchten.

Das vorhandene Steuerelement wurde in Win8 basierend auf den DirectManipulation-APIs erstellt, die 1) nicht für die direkte Verwendung in UWP verfügbar sind, 2) nicht den Anpassungsgrad zulassen, den Entwickler erwarten, um einzigartige Bildlauferlebnisse zu schaffen, und 3) überholt werden durch die neueren InteractionTracker-APIs von UWP.

Das Extrahieren des vorhandenen ScrollViewer-Steuerelements wie es ist, wäre kein Starter. Das Steuerelement muss stattdessen eine Neuimplementierung mit einer nahezu identischen API-Oberfläche sein, die auf den neueren (und bereits verfügbaren) Funktionen von InteractionTracker basiert.

High-Level-Plan

Der vorhandene ScrollViewer im Namespace _Windows_.UI.Xaml.Controls bleibt unberührt (außer der Behebung kritischer Fehler).

Der neue ScrollViewer wird im Namespace _Microsoft_.UI.Xaml.Controls leben. Seine API wird größtenteils mit der _Windows_-Version identisch sein. Wir werden gezielte Anpassungen an der API des Steuerelements vornehmen, wenn es einen klaren Vorteil gibt (ein gemeinsames Szenario vereinfachen, neue Funktionen einführen usw.).

In Kombination mit dem neuen ScrollViewer werden wir einen neuen Typ, Scroller, einführen, der im Microsoft.UI.Xaml.Controls._Primitives_-Namespace leben wird. Der Scroller stellt die Kernfunktionalität zum Scrollen und Zoomen in XAML basierend auf den Fähigkeiten von InteractionTracker bereit.

Das ursprüngliche Ziel beider Kontrollen wird darin bestehen, die Kernfunktionalität in die Auslieferungsqualität zu bringen, um Teil der nächsten offiziellen Veröffentlichung zu sein. Nicht finalisierte APIs verbleiben in der "Vorschau" und sind nur als Teil der Vorabversionspakete verfügbar.

-------------------- Die folgenden Abschnitte sind optional, wenn Sie eine Idee oder einen Vorschlag einreichen. Alle Abschnitte sind erforderlich, bevor wir eine PR akzeptieren, um sie zu meistern, aber nicht notwendig, um die Diskussion zu beginnen. ----------------------

Funktionale Anforderungen


| # | Funktion | | Priorität |
|:-:|:--|-|:-:|
| 1 | Bietet eine _nicht versiegelte_, Schwenk- und Zoomsteuerung mit einer Standard-UX, die dem vorhandenen ScrollViewer entspricht. || Muss |
| 2 | Demonstriert die Plattformfähigkeiten, indem es sich ausschließlich auf öffentliche, plattformunterstützte APIs verlässt. || Muss |
| 3 | Integriert in XAML-Dienste auf Framework-Ebene.
Zum Beispiel:
- Rendert Systemfokus-Recte korrekt
- bringt fokussierte Elemente automatisch ins Blickfeld (Tastatur, GamePad, Screenreader)
- beteiligt sich an effektiven Ansichtsfensteränderungen
- unterstützt Scrollverankerung || Muss|
| 4 | Kann eingabegesteuerte Animationen ausführen || Muss |
| 5 | Kann in Kombination mit bereits im Repository vorhandenen scrollabhängigen Controls verwendet werden (zB ParallaxView, RefreshContainer, SwipeControl). || Muss |
| 6 | Kann die Kurve für Trägheitsansichtsänderungen steuern (dh benutzerdefiniertes animiertes Scrollen oder Zoomen). || Muss |
| 7 | Kann die Ansicht basierend auf absoluten oder relativen Offsets ändern (zB zu einem Point of Interest scrollen) || Muss |
| 8 | Kann die Ansicht aufgrund eines Impulses / einer zusätzlichen Geschwindigkeit ändern (zB automatisches sanftes Scrollen beim Drag-and-Drop oder Mehrfachauswahl über ein Mausauswahlrechteck) || Muss |
| 9 | Kann Überschreitung erkennen und um wie viel || Muss |
| 10 | Kann Änderungen des Scrolling-Zustands beobachten und darauf reagieren || Muss |
| 11 | Unterstützung für das Scrollen und Zoomen von Fangpunkten. || Sollte |
| 12 | Kann ein benutzerdefiniertes "Bildlaufleisten"-Steuerelement verwenden, um das Scrollen zu steuern (zB Fotos-Timeline-Scrubber). || Sollte |
| 13 | Kann die Steuerung einfach so konfigurieren, dass bestimmte Eingabearten ignoriert werden (z. B. auf Berührung oder Stift reagieren, aber Mausradeingaben ignorieren). || Sollte |
| 14 | Kann die Scrollposition speichern und wiederherstellen (zB in einer Virtualisierungsliste) || Sollte |
| 15 | Unterstützung für klebrige Header / Elemente. || Sollte |
| 16 | Unterstützung für beschleunigtes Scrollen, wenn ein Benutzer in schneller Folge wiederholte Gesten ausführt. || Sollte |
| 17 | Stellen Sie eine Standard-UX bereit, um einen mittleren Mausklick und ein Scrollen zu unterstützen. |mousewheel panning | Sollte |
| 18 | Unterstützen Sie einen Modus zum Klicken und Verschieben mit der Maus (zB Verschieben von Inhalten in einem PDF-Viewer). |mouse hand cursor for panning | Sollte |
| 19 | Kann ein benutzerdefiniertes Steuerelement verwenden, um das Zoomen zu steuern (zB einen Zoom-Schieberegler). || Sollte |
| 20 | Kann Inhalte drucken, die im scrollbaren Bereich enthalten sind. || Sollte |
| 21 | Unterstützen Sie Rotationsgesten. || Könnte |
| 22 | Kann zwei oder mehr Bereiche mit flimmer- und ruckelfreiem Scrollen synchronisieren (zB ein Textdiff-Szenario). || Könnte |
| 23 | Kann die Animationskurve für eingabegesteuerte Ansichtsänderungen anpassen (dh Definieren von Fingerabwärtsverhalten wie Schwerkraftquellen). || Könnte |
| 24 | Unterstützen Sie eine Geste zum Scrollen nach oben oder unten . || Könnte |
| 25 | Kann Overpanning deaktivieren . || Könnte |
| 26 | Kann Inhalte im ScrollViewer basierend auf der ManipulationMode-Eigenschaft eines UIElement selektiv bearbeiten . || Könnte |
| 27 | Kann die Trägheit ausschalten und/oder von der Trägheit abprallen. || Könnte|
| 28 | Kann das Abschneiden des Inhalts deaktivieren (dh CanContentRenderOutsideBounds ). || Könnte |
| 29 | Kann den Abschlussgrund am Ende einer Ansichtsänderung ermitteln. || Könnte |

Terminologie

  • _Overpan_ ist, wenn der Benutzer versucht, über die Größe des Inhalts hinaus zu schwenken oder zu zoomen, was zu einem Gummibandeffekt führt.
  • _Railing_ ist, wenn der Scroller die Bewegung basierend auf der Richtung der ersten Geste automatisch auf eine "bevorzugte" Achse sperrt.
  • _Chaining_ ist, wenn eine scrollbare Oberfläche ineinander verschachtelt ist und wenn die
  • _Fangpunkte_ sind Stellen innerhalb des scrollbaren Inhalts, an denen das Ansichtsfenster am Ende des Trägheits-Scrollens zur Ruhe kommt (dh ein animiertes Scrollen, nachdem der Benutzer seinen Finger gehoben hat). Fangpunkte sind für ein Steuerelement wie FlipView erforderlich.
  • Bei der _Scroll-Ankerung_ wird das Ansichtsfenster automatisch
  • _Schwerkraftquellen_ sind Stellen innerhalb des scrollbaren Inhalts, die das

Anwendungsbeispiele

Bitte fügen Sie ein oder mehrere Beispiele bei, die zeigen, wie Sie die Funktion verwenden würden. Sie können Codebeispiele oder Screenshots einfügen, wenn das hilft

Vorwort

Standardmäßig unterstützt der ScrollViewer das Schwenken über seinen Inhalt, wenn die Größe des Inhalts größer als sein Ansichtsfenster ist. Die Größe des Inhalts wird durch das Layoutsystem von XAML bestimmt.

Die Beispiele hier sollen den wichtigsten API-Unterschied zwischen dem aktuellen ScrollViewer und dem neuen ScrollViewer hervorheben.

Vertikales Scrollen (kein Unterschied)

Die Breite des Inhalts wird automatisch auf die des Ansichtsfensters beschränkt. Die Höhe ist uneingeschränkt. Überschreitet es die Höhe des Ansichtsfensters, kann der Benutzer über verschiedene Eingabemodalitäten schwenken.

<ScrollViewer Width="500" Height="400">
    <ItemsRepeater ItemsSource="{x:Bind ViewModel.Items}" ItemTemplate="{StaticResource MyTemplate}"/>
</ScrollViewer>

Horizontales Scrollen

Dies ist eine absichtliche Abweichung vom vorhandenen ScrollViewer, für den zuvor eine Änderung der HorizontalScrollBarVisibility erforderlich war. Es hat viele Entwickler verwirrt.

<ScrollViewer Width="500" Height="400" ContentOrientation="Horizontal">
    <StackPanel Orientation="Horizontal">
        <!-- ... -->
    </StackPanel>
</ScrollViewer>

Nur horizontales Scrollen wird durch Festlegen der _ContentOrientation_- Eigenschaft

Scrollen eines großen Bildes

Eine ContentOrientation von _Both_ bedeutet, dass der Inhalt sowohl horizontal als auch vertikal uneingeschränkt ist.

<ScrollViewer Width="500" Height="400" ContentOrientation="Both">
    <Image Source="Assets/LargeEiffelTower.png"/>
</ScrollViewer>

Ändern der ScrollBar-Sichtbarkeit

In diesem Beispiel werden immer beide Bildlaufleisten ausgeblendet. Der Benutzer kann den Inhalt weiterhin in beide Richtungen verschieben.

<ScrollViewer Width="500" Height="400"
              ContentOrientation="Both"
              HorizontalScrollBarVisibility="Hidden"
              VerticalScrollBarVisibility="Hidden">
    <Image Source="Assets/LargeEiffelTower.png"/>
</ScrollViewer>

Deaktivieren der integrierten Unterstützung für bestimmte Eingabearten

In diesem Beispiel erstellt ein Entwickler eine Canvas-basierte App, die eine benutzerdefinierte Verarbeitung bei Mausradeingaben durchführt und eine Lasso-Auswahl über den Stift unterstützt. Es kann den ScrollViewer so konfigurieren, dass diese Eingabearten ignoriert werden, während andere, wie z. B. Touch, weiterhin akzeptiert werden.

<ScrollViewer IgnoredInputKind="MouseWheel,Pen"
              Width="500" Height="400"
              ContentOrientation="Both" >
    <SwapChainPanel x:Name="swapChainPanel" Width="40000" Height="40000">
        ...
    </SwapChainPanel>
</ScrollViewer>

Passen Sie die Animation eines programmatischen Bildlaufs an

Der Entwickler lauscht auf das ValueChanged-Ereignis eines Slider und animiert das VerticalOffset eines ScrollViewers mit einer benutzerdefinierten Dauer für die Standardanimation.

private void VerticalOffsetSlider_ValueChanged(
    object sender,
    RangeBaseValueChangedEventArgs e)
{
    double verticalOffsetDelta = GetOffsetDelta();
    TimeSpan animationDuration = GetCustomAnimationDuration();

    // Initiate the scroll and enqueue the ScrollInfo we'll use to identify related events
    ScrollInfo scrollInfo = _scrollViewer.ScrollBy(0.0, verticalOffsetDelta);
    _myScrollRequests.Add(new MyScrollRequest(scrollInfo, animationDuration));
}

// Listen to the ScrollViewer's ScrollAnimationStarting event and customize 
// the default animation
private void ScrollViewer_ScrollAnimationStarting(
    ScrollViewer scrollViewer,
    ScrollAnimationStartingEventArgs e)
{
    MyScrollRequest myScrollRequest = _myScrollRequests.FindRequest(e.ScrollInfo);
    e.Animation.Duration = myScrollRequest.AnimationDuration;
}

// Dequeue the ScrollInfo once the action completes
private void ScrollViewer_ScrollCompleted(
    ScrollViewer scrollViewer,
    ScrollCompletedEventArgs e)
{
    _myScrollRequests.RemoveRequest(e.ScrollInfo);
}

Detailliertes Feature-Design

Bitte geben Sie alle wichtigen Konstruktionsdetails an. Dies kann einen oder mehrere der folgenden Punkte umfassen: - einen API-Vorschlag (jede unterstützte Sprache oder jeder Pseudocode ist in Ordnung) - Entwurf von Modellen für eine neue Benutzererfahrung - Details zur Einhaltung der Barrierefreiheit für neue Benutzeroberflächen - andere Implementierungshinweise

Scrollen mit hohen und niedrigen Richtlinien

Scroller (niedrige Richtlinien)

Der Scroller ist ein chromloser Low-Level-Baustein, der die gesamte wesentliche Schwenk- und Zoomlogik bietet. Es umschließt den InteractionTracker der Plattform mit noch niedrigeren Richtlinien als XAML-Markup-freundliches Element.
Im wahrsten Sinne des Wortes ist der Scroller "der Viewport" für ScrollViewer und ersetzt den ScrollContentPresenter. Der Scroller macht jedoch im Gegensatz zum ScrollContentPresenter viel mehr, als nur seinen Inhalt zu beschneiden.

Scroller bietet die Flexibilität, InteractionTracker direkt zu verwenden, zusammen mit den folgenden Vorteilen:

  • Unterstützung für Barrierefreiheit
  • Markup-freundliche Syntax und benutzerfreundliche API
  • Integration in das Layoutsystem und die Virtualisierungsfunktionen von XAML

ScrollViewer (hohe Richtlinien)

Der neue ScrollViewer umschließt den Scroller und legt seine Eigenschaften auf gemeinsame Werte fest. Ein <ScrollViewer/> konfiguriert beispielsweise seinen Scroller so, dass er sowohl horizontale als auch vertikale Scroll-Interaktionen unterstützt, aber die Breite seines Inhalts so einschränkt, dass die Standardbenutzererfahrung nur vertikales Scrollen zu sein scheint (der übliche Fall).

ScrollViewer bietet die folgenden Vorteile gegenüber der Verwendung eines Scrollers:

  • Eine Standard-UX (z. B. der Scroll-Indikator, bewusste Scrollbars für die Maus, eine Standard-Animationskurve)
  • Standardunterstützung für UI-Thread-gebundene Eingaben, die nicht von Scroller/InteractionTracker verarbeitet werden (dh Tastatur und GamePad)
  • Standard-Fokusbewegung für GamePad (Seite nach oben/unten und automatischer Fokus als Reaktion auf die Auslöser)
  • Standardmäßige Kenntnis der Systemeinstellungen des Benutzers (z. B. automatisches Ausblenden von Bildlaufleisten in Windows)
  • (Zukünftig) Einfache Konfigurationsmöglichkeiten für Fangpunkte
  • (Zukünftig) Unterstützung für mehr Maus-Panning-Modi (z. B. Click-and-Drag-Inhalte mit einer Hand zum Öffnen/Schließen, Maus-Panning über das Mausrad / Klick mit der mittleren Taste zeigt einen "Kompass"-Cursor)

Welches zu verwenden?

Die Standardauswahl für Apps und viele Steuerelementautoren sollte die Verwendung des ScrollViewer sein. Es bietet eine größere Benutzerfreundlichkeit und eine Standard-UX, die mit der Plattform konsistent ist. Der Scroller ist geeignet, wenn die Standard-UX / -Richtlinien nicht erforderlich sind - zum Beispiel beim Erstellen eines verbesserten FlipView-Steuerelements oder einer chromlosen Scrolloberfläche.

Nur ScrollViewer-APIs

HorizontalScrollBarVisibility / VerticalScrollBarVisibility

Der Standardwert für horizontale und vertikale Bildlaufleisten ist _Auto_. Sie werden automatisch ein- oder ausgeblendet, je nachdem, ob der Inhalt breiter/höher als das Ansichtsfenster ist oder nicht.

Die Option 'Deaktiviert' wird in den für den neuen ScrollViewer verfügbaren Aufzählungsoptionen nicht vorhanden sein. Stattdessen basiert die Konfiguration des Steuerelements für die Reaktion auf Benutzerinteraktionen, die horizontal oder vertikal geschwenkt werden, ausschließlich auf den Eigenschaften _HorizontalScrollMode_ und _VerticalScrollMode_.

namespace Microsoft.UI.Xaml.Controls
{
    public enum ScrollBarVisibility
    {
        Auto = 0,    // Only visible when the ZoomFactor * content size > viewport
        Visible = 1, // Always visible
        Hidden = 2   // Always hidden
    }
}

Im Bild unten befindet sich der Mauszeiger über der vertikalen Bildlaufleiste. Es ist das einzige sichtbare, da der Inhalt dieselbe Breite wie das Ansichtsfenster hat.

Wenn der Inhalt in beiden Dimensionen größer als das Ansichtsfenster ist, sind beide bewussten Bildlaufleisten sowie deren Trenner in der unteren rechten Ecke zu sehen.

Nur Scroller-APIs

HorizontalScrollController / VerticalScrollController

Der Scroller kann mit einem interaktiven "Widget" verbunden werden, das das Scrollen steuert, indem sein _HorizontalScrollController_ und _VerticalScrollController_ auf einen Typ gesetzt werden, der eine _IScrollController_-Schnittstelle implementiert. ScrollBars sind bekannte Beispiele für solche Widgets. Der ScrollViewer liefert seinem Scroller zwei solcher Widgets aus. Ein Entwickler könnte beispielsweise eine benutzerdefinierte IScrollController-Implementierung erstellen, die auf einem Composition.Visual für UI-Thread-unabhängige Eingaben basiert.

_scroller.HorizontalScrollController = new Acme.Slider(orientation: Orientation.Horizontal);
_scroller.VerticalScrollController = new Acme.Slider(orientation: Orientation.Vertical);

Downlevel-Einschränkungen von ScrollViewer / Scroller

Das Framework sollte ab dem Windows 10. April 2018 Update über alle erforderlichen Hooks verfügen, um ein benutzerdefiniertes Scroll-Steuerelement zu erstellen. Bei der Ausrichtung auf frühere Versionen kann es Einschränkungen geben:
| Freigabe | Einschränkung | Grund |
|:-:|:--|:-:|
| Windows 10 Fall Creators Update (Build 16299) und früher | Elemente werden nicht automatisch angezeigt, wenn sie den Fokus erhalten. | Das BringIntoViewRequested-Ereignis von UIElement ist nicht verfügbar |
| | Das Steuerelement kann nicht an EffectiveViewportChanged-Ereignissen teilnehmen. Vom System gerenderte Fokusrechte werden nicht auf die Grenzen des Ansichtsfensters abgeschnitten. | RegisterAsScrollPort von UIElement ist nicht verfügbar |

Vorgeschlagene API

ScrollViewer

```C#
öffentliche Klasse Microsoft.UI.Xaml.Controls.ScrollViewer : Control
{
ScrollViewer();

// Default Value: non-null instance
Windows.UI.Composition.CompositionPropertySet ExpressionAnimationSources { get; }

/*

  • Layoutorientierte Eigenschaften
    */
    // Standardwert: null
    UIElement-Inhalt { get; einstellen; };
// Default Value: Vertical
Microsoft.UI.Xaml.Controls.ContentOrientation ContentOrientation { get; set; };

// Default Value: 0.0
Double HorizontalOffset { get; };

// Default Value: 0.0
Double VerticalOffset { get; };

// Default Value: 1.0
Single ZoomFactor { get; };

// Default Value: 0.0
Double ExtentWidth { get; };

// Default Value: 0.0
Double ExtentHeight { get; };

// Default Value: 0.0
Double ViewportWidth { get; };

// Default Value: 0.0
Double ViewportHeight { get; };

// Default Value: 0.0
Double ScrollableWidth { get; };

// Default Value: 0.0
Double ScrollableHeight { get; };

// Default Value: Auto
M.UI.Xaml.Controls.ScrollBarVisibility HorizontalScrollBarVisibility {get;set;};

// Default Value: Auto
M.UI.Xaml.Controls.ScrollBarVisibility VerticalScrollBarVisibility {get;set;};

// Default Value: Collapsed
// Used for template binding the Visibility property of the horizontal
// ScrollBar in the control template
Visibility ComputedHorizontalScrollBarVisibility{ get; };

// Default Value: Collapsed
// Used for template binding the Visibility property of the vertical
// ScrollBar in the control template
Visibility ComputedVerticalScrollBarVisibility{ get; };

/*

  • Benutzerinteraktionsorientierte Eigenschaften
    */
    // Standardwert: Aktiviert
    Microsoft.UI.Xaml.Controls.ScrollMode HorizontalScrollMode { get; einstellen; };
// Default Value: Enabled
Microsoft.UI.Xaml.Controls.ScrollMode VerticalScrollMode { get; set; };

// Default Value: Disabled
Microsoft.UI.Xaml.Controls.ZoomMode ZoomMode { get; set; };

// Default Value: All
Microsoft.UI.Xaml.Controls.InputKind IgnoredInputKind { get; set; };

// Default Value: Idle
Microsoft.UI.Xaml.Controls.InteractionState State { get; };

// Default Value: Auto
Microsoft.UI.Xaml.Controls.ChainingMode HorizontalScrollChainingMode { get; set; };

// Default Value: Auto
Microsoft.UI.Xaml.Controls.ChainingMode VerticalScrollChainingMode { get; set; };

// Default Value: True
boolean IsHorizontalRailEnabled { get; set; };

// Default Value: True
boolean IsVerticalRailEnabled { get; set; };

// Default Value: Auto
Microsoft.UI.Xaml.Controls.ChainingMode ZoomChainingMode { get; set; };

// Default Value: None
M.UI.Xaml.Controls.SnapPointsType HorizontalSnapPointsType { get; set; };

// Default Value: None
M.UI.Xaml.Controls.SnapPointsType VerticalSnapPointsType { get; set; };

// Default Value: Near
M.UI.Xaml.C.Primitives.SnapPointsAlignment HorizontalSnapPointsAlignment { g;s; };

// Default Value: Near
M.UI.Xaml.C.Primitives.SnapPointsAlignment VerticalSnapPointsAlignment { g;s; };

// Default Value: 0.95, 0.95
Windows.Foundation.Numerics.Vector2 ScrollInertiaDecayRate { get; set; }; 

// Default Value: 0.95
Single ZoomInertiaDecayRate { get; set; }; 

// Default Value: 0.1
Double MinZoomFactor { get; set; };

// Default Value: 10.0
Double MaxZoomFactor { get; set; };

// Default Value: 0.0
Double HorizontalAnchorRatio { get; set; };

// Default Value: 0.0
Double VerticalAnchorRatio { get; set; };

// Forwarded to inner Scroller’s IScrollAnchorProvider implementation
// Default Value: null
Windows.UI.Xaml.UIElement CurrentAnchor { get; };

/*

  • Methoden
    */
    // Scrollt asynchron zu den angegebenen Offsets. Ermöglicht Animationen,
    // respektiert Fangpunkte. Gibt eine ScrollInfo-Struktur zurück.
    Microsoft.UI.Xaml.Controls.ScrollInfo ScrollTo(
    doppelter horizontaler Versatz,
    doppelter vertikaler Offset);
// Asynchronously scrolls to specified offsets with optional animation,
// with optional snap points respecting. Returns a ScrollInfo struct.
Microsoft.UI.Xaml.Controls.ScrollInfo ScrollTo(
    double horizontalOffset,
    double verticalOffset,
    Microsoft.UI.Xaml.Controls.ScrollOptions options);

// Asynchronously scrolls by the provided delta amount.
// Allows animation, respects snap points. Returns a ScrollInfo struct.
Microsoft.UI.Xaml.Controls.ScrollInfo ScrollBy(
    double horizontalOffsetDelta,
    double verticalOffsetDelta);

// Asynchronously scrolls by the provided delta amount with
// optional animation, with optional snap points respecting.
// Returns a ScrollInfo struct.
Microsoft.UI.Xaml.Controls.ScrollInfo ScrollBy(
    double horizontalOffsetDelta,
    double verticalOffsetDelta,
    Microsoft.UI.Xaml.Controls.ScrollOptions options);

// Asynchronously adds scrolling inertia. Returns a ScrollInfo struct.
Microsoft.UI.Xaml.Controls.ScrollInfo ScrollFrom(
    Vector2 offsetsVelocity,
    Nullable<Vector2> inertiaDecayRate);

// Asynchronously zooms to specified zoom factor. Allows animation
// (respects snap points in v2). Returns a ZoomInfo struct.
Microsoft.UI.Xaml.Controls.ZoomInfo ZoomTo(
    float zoomFactor,
    Nullable<Vector2> centerPoint);

// Asynchronously zooms to specified offsets with optional animation
// (with optional snap points respecting in v2). Returns a ZoomInfo struct.
Microsoft.UI.Xaml.Controls.ZoomInfo ZoomTo(
    float zoomFactor,
    Nullable<Vector2> centerPoint,
    Microsoft.UI.Xaml.Controls.ZoomOptions options);

// Asynchronously zooms by the provided delta amount. Allows animation
// (respects snap points in v2). Returns a ZoomInfo struct.
Microsoft.UI.Xaml.Controls.ZoomInfo ZoomBy(
    float zoomFactorDelta,
    Nullable<Vector2> centerPoint);

// Asynchronously zooms by the provided delta amount with optional animation
// (with optional snap points respecting in v2). Returns an ZoomInfo struct.
Microsoft.UI.Xaml.Controls.ZoomInfo ZoomBy(
    float zoomFactorDelta,
    Nullable<Vector2> centerPoint,
    Microsoft.UI.Xaml.Controls.ZoomOptions options);

// Asynchronously adds zooming inertia. Returns a ZoomInfo struct.
Microsoft.UI.Xaml.Controls.ZoomInfo ZoomFrom(
    float zoomFactorVelocity,
    Nullable<Vector2> centerPoint,
    Nullable<float> inertiaDecayRate);

/*

  • An die IScrollAnchorProvider-Implementierung von inner Scroller weitergeleitet
    */
    void RegisterAnchorCandidate(UIElement-Element);
    void UnregisterAnchorCandidate(UIElement-Element);

/*

  • Veranstaltungen
    */
    // Wird ausgelöst, wenn einer von HorizontalOffset, VerticalOffset und ZoomFactor
    // Abhängigkeitseigenschaft geändert.
    Ereignis TypedEventHandlerAnsichtGeändert;
// Raised when any of the ExtentWidth and ExtentHeight dependency property changed.
event TypedEventHandler<ScrollViewer, Object> ExtentChanged;

// Raised when the State dependency property changed.
event TypedEventHandler<ScrollViewer, Object> StateChanged;

// Raised when a ScrollTo or ScrollBy call triggers an animation.
// Allows customization of that animation.
event TypedEventHandler<ScrollViewer, Microsoft.UI.Xaml.Controls.ScrollAnimationStartingEventArgs>
    ScrollAnimationStarting;

// Raised when a ZoomTo or ZoomBy call triggers an animation.
// Allows customization of that animation.
event TypedEventHandler
    <ScrollViewer, Microsoft.UI.Xaml.Controls.ZoomAnimationStartingEventArgs>
    ZoomAnimationStarting;

// Raised at the end of a ScrollTo, ScrollBy, or ScrollFrom asynchronous
// operation. Provides the original ScrollInfo struct.
event TypedEventHandler
    <ScrollViewer, Microsoft.UI.Xaml.Controls.ScrollCompletedEventArgs>
    ScrollCompleted;

// Raised at the end of a ZoomTo, ZoomBy, or ZoomFrom asynchronous operation.
// Provides the original ZoomInfo struct.
event TypedEventHandler
    <ScrollViewer, Microsoft.UI.Xaml.Controls.ZoomCompletedEventArgs>
    ZoomCompleted;

// Raised at the beginning of a bring-into-view-request participation.
// Allows customization of that participation. 
event TypedEventHandler
    <ScrollViewer, Microsoft.UI.Xaml.Controls.BringingIntoViewEventArgs>
    BringingIntoView;

// Raised to allow the listener to pick an anchor element, when anchoring
// is turned on.
event TypedEventHandler
    <ScrollViewer, Microsoft.UI.Xaml.Controls.AnchorRequestedEventArgs>
    AnchorRequested;

/*

  • Abhängigkeitseigenschaften
    */
    static DependencyProperty ContentProperty { get; };
    static DependencyProperty ContentOrientationProperty { get; };
    static DependencyProperty ComputedHorizontalScrollBarVisibilityProperty { get; };
    static DependencyProperty ComputedVerticalScrollBarVisibilityProperty { get; };
    static DependencyProperty HorizontalScrollBarVisibilityProperty { get; };
    static DependencyProperty VerticalScrollBarVisibilityProperty { get; };
static DependencyProperty IgnoredInputKindProperty { get; };
static DependencyProperty HorizontalScrollModeProperty { get; };
static DependencyProperty VerticalScrollModeProperty { get; };
static DependencyProperty ZoomModeProperty { get; };
static DependencyProperty HorizontalScrollChainingModeProperty {g};
static DependencyProperty VerticalScrollChainingModeProperty {g};
static DependencyProperty IsHorizontalRailEnabledProperty {g};
static DependencyProperty IsVerticalRailEnabledProperty {g};
static DependencyProperty ZoomChainingModeProperty { get; };
static DependencyProperty MinZoomFactorProperty { get; };
static DependencyProperty MaxZoomFactorProperty { get; };
static DependencyProperty HorizontalAnchorRatioProperty { get; };
static DependencyProperty VerticalAnchorRatioProperty { get; };

}
```

Offene Fragen

  • Würde eine ContentOrientation-Eigenschaft (oder eine mit einem anderen Namen), die sich darauf auswirkt, wie Layouteinschränkungen auf den Inhalt angewendet werden, die Dinge komplizierter oder einfacher machen?
  • Sollten die Zoom-bezogenen APIs in ein abgeleitetes Steuerelement (z. B. ZoomViewer) unterteilt werden, so dass es bei ScrollViewer ausschließlich um das Scrollen geht?
Epic area-Scrolling feature proposal proposal-NewControl team-Controls

Hilfreichster Kommentar

Korrekt. Wir haben uns 3 Situationen vorgestellt:

  1. Es ist mir egal, was meine aktuelle Position ist. Ich möchte zu einem bestimmten Ziel scrollen/zoomen.
  2. Meine aktuelle Position ist mir wichtig und ich möchte um einen bestimmten Betrag relativ zu dieser Position scrollen/zoomen.
  3. Es ist mir egal, was das endgültige Ziel ist. Ich möchte nur von meiner aktuellen Position scrollen/zoomen.

Ein Szenario für letzteres könnte so etwas wie das Mausrad-Klicken zum Schwenken sein. Abhängig von der Position des Cursors relativ zu dem Zeitpunkt, an dem darauf geklickt wurde, wird eine gewisse Trägheit eingefügt, um von der aktuellen Position (was auch immer das ist) zu scrollen.

Alle 61 Kommentare

Meiner Meinung nach ist die Notwendigkeit von Inhalten, die gescrollt werden können, und Inhalten, die gezoomt werden können, sehr unterschiedlich. Ich verstehe, dass beim Zoomen von Inhalten oft auch gescrollt werden muss, aber ich bin gespannt, ob es in Erwägung gezogen wurde, diese separaten Steuerelemente zu erstellen? Möglicherweise mit einem zoombaren Steuerelement, das sich von einem scrollenden erstreckt.
Meine Bedenken sind: 1) Der ScrollViewer wird übermäßig komplex, indem Zoomfunktionen hinzugefügt werden, die von den meisten nicht benötigt werden; 2) Es ist für jemanden, der nach einem Steuerelement zum Zoomen von Inhalten sucht, nicht offensichtlich, dass der ScrollViewer dies unterstützt.


Darüber hinaus würde ich im Angebot gerne die Möglichkeit sehen, zu einem bestimmten Element im Scroll-Viewer zu scrollen. Theoretisch könnte dies von einem Entwickler getan werden, indem er alle Elemente davor misst und dann zum entsprechenden Offset scrollt, aber dies kann mit virtualisierten Listen schwierig sein und ist (meiner Meinung nach) ein häufig genug Szenario, dass viele Apps ( und Entwickler) würde davon profitieren, dass dies integriert ist.
Überlegen Sie, wo ein Artikel zu einer "Liste" hinzugefügt wird und der Entwickler sicherstellen möchte, dass dieser Artikel sichtbar ist. Oder betrachten Sie eine Seite mit einer Master-/Detailansicht, bei der die Seite bei einem Detailelement weiter unten in der Liste geöffnet wird, der Entwickler jedoch sicherstellen möchte, dass das ausgewählte Element in der Masterliste angezeigt wird, sodass es Kontext für das bietet, was in der . angezeigt wird Detailansicht.

In ähnlicher Weise wäre es auch nützlich, sicherzustellen, dass ein Element im sichtbaren Bereich bleibt, während andere Elemente innerhalb der scrollbaren Bereiche aus dem visuellen Baum entfernt (oder zu ihm hinzugefügt) werden. Ich bin mir nicht sicher, wie dies am besten wäre, aber es ist sehr schlecht, wenn sich das ausgewählte Element innerhalb eines scrollbaren Bereichs bewegt, weil eine Hintergrundaktion (oder ein Thread außerhalb der Benutzeroberfläche) andere Elemente entfernt oder dem scrollbaren Bereich hinzufügt.
Wenn sich ein Element beim Klicken/Tippen bewegt, führt dies zu einer schrecklichen Benutzerfreundlichkeit. Auch das Verschieben von fokussierten/ausgewählten Elementen aus dem sichtbaren Bereich kann zu Problemen bei Eingabehilfen und Bildschirmleseprogrammen führen.
Ich bin mir bewusst, dass es potenzielle Probleme gibt, wenn Sie versuchen, ein Element an derselben Position zu halten, während sich die Umstehenden bewegen (insbesondere wenn dieses Element an anderer Stelle gelöscht wird), aber nichts zu tun scheint nicht gut genug zu sein.

Danke @mrlacey. Ich kann sehen, dass die Zoomfunktionalität im vorhandenen ScrollViewer sowie in diesem Vorschlag weniger auffindbar wäre. Ich habe dies als offene Frage zur Diskussion hinzugefügt, da dies ein weiterer Ausgangspunkt für den bestehenden UWP ScrollViewer wäre (vielleicht zum Besseren?).

Die Virtualisierung macht die Sache knifflig, da das jeweilige Element möglicherweise zuerst erstellt und durch das Layoutsystem laufen muss, um eine Position zu erhalten, zu der Sie dann scrollen können. Aus diesem Grund hatten in der Vergangenheit bestimmte Steuerelemente (zB ListView) ihre eigene ScrollIntoView-Methode , die das oben StartBringIntoView-Methode , die verwendet werden kann, um sehr einfach zu einem Element zu scrollen, und verfügt über eine Reihe von Optionen , um eine fein abgestufte Kontrolle darüber bereitzustellen, wo es im Ansichtsfenster landet, wenn es angezeigt wird. Der StartBringIntoView-Ansatz funktioniert sogar in Szenarien mit verschachtelten Bildlaufoberflächen, da er eine Anforderung generiert, die für jedes Bildlaufsteuerelement aufspringt, um zu antworten. Dies geschieht im Wesentlichen, wenn ein Element den Fokus auf Tastatur/GamePad/Sprecher erhält. Voraussetzung ist natürlich, dass Sie zunächst über ein UIElement verfügen, das Sie in einem Virtualisierungsszenario nicht ohne eine Möglichkeit zur expliziten Auslösung eines zu realisierenden Elements verwenden dürfen. Wäre es sinnvoll, die Realisierung eines Elements explizit auszulösen? Unter anderem könnte man damit dann einen StartBringIntoView auslösen.

Betreff: Die Position eines Elements beibehalten, wenn andere Inhalte hinzugefügt/entfernt werden oder sich in der Größe ändern... Stimme voll und ganz zu, dass Nichtstun nicht gut genug ist. Genau aus diesem Grund gibt es die Funktion zur Scrollverankerung . :) Es ist eine wenig bekannte Funktion, die in der Vergangenheit in die virtualisierenden Panels für ListView/GridView integriert wurde. In den letzten Versionen haben wir uns ausdrücklich bemüht, solche Dinge von der Verfügbarkeit nur in ListView zu entkoppeln.

Wenn die Idee eines erweiterten ScrollViewers untersucht werden soll, können die Fluent Design-Teams Sie vielleicht zum Umgang mit Parallaxe und Elementen mit standardmäßig eingestellten Z-Tiefenwerten beraten.

Wenn XAML in 3D-Darstellungen für MR-Apps übergeht und wenn Tiefe und Schatten zu 2D-XAML kommen – wie das Scrollen Elemente mit unterschiedlichen Tiefenwerten verschieben würde, wie die Schatten über oder hinter den Scroll-Indikatoren gerendert werden können und andere Probleme, die auftreten können in den 3D-Experimenten des XAML-Teams - könnte in den neuen Standard integriert werden, da die Windows-UI-Bibliothek langsam zum neuen Standard wird.

Meiner Meinung nach ist die Notwendigkeit von Inhalten, die gescrollt werden können, und Inhalten, die gezoomt werden können, sehr unterschiedlich.

Außer in Webbrowsern, Grafikdesign-Apps, Office-Apps, PDF-Viewern..... alles, was ein Inhaltsdokument anzeigt.

Stimmen Sie @mrlacey zu, dass es wichtig ist, ein bestimmtes Element in die Ansicht zu bringen und anzugeben, wo es in der Ansicht angezeigt wird (oben, mittig, unten usw.). Es muss auch eine Möglichkeit geben, zu erkennen, ob das Element vollständig sichtbar oder abgeschnitten ist. Auf diese Weise muss ich nicht in der Ansicht scrollen, um ein Element anzuzeigen, wenn ich weiß, dass das Element bereits ganz oder teilweise sichtbar ist.

Danke an alle! Wir haben einige Telemetriedaten zu den Eigenschaften gesammelt, die Apps in ihrem Markup festlegen, und der ZoomMode wird direkt nach dem *ScrollMode und *ScrollBarVisibility angezeigt. Meistens ändern Apps keine Eigenschaften. Was ich beim Festlegen der Eigenschaften ScrollMode und ScrollBarVisibility beobachtet habe, ist, dass häufig ein horizontales Scrollen des Inhalts aktiviert wird. Die Einführung der ContentOrientation-Eigenschaft soll dies erleichtern. Nach dem horizontalen Scrollen ist das Zoomen das zweithäufigste Szenario.

Anstatt ein separates (abgeleitetes) Steuerelement einzuführen, um die Auffindbarkeit des Zoomens zu verbessern, glaube ich, dass die richtige Dokumentation / Beispiele effektiver sein könnten.

Wie wäre es mit dem Hinzufügen einer Verhaltens- oder Kontextaufzählung?

ScrollViewer.ScrollBehaviour = ScrollBehaviour.Zoom;
ScrollViewer.ScrollBehaviour = ScrollBehaviour.Scroll;
ScrollViewer.ScrollBehaviour = ScrollBehaviour.ParallaxScroll;

ScrollViewer.ScrollBehaviour = ScrollBehaviour.Zoom; ist jedoch sehr verwirrend. Ich denke, ZoomMode sollte so bleiben, wie es ist.

ScrollViewer.ScrollBehaviour = ScrollBehaviour.Zoom; ist jedoch sehr verwirrend. Ich denke, ZoomMode sollte so bleiben, wie es ist.

Ich hätte den Vorschlag wahrscheinlich voranstellen sollen, um Kommentare zu adressieren, die der Meinung sind, dass es ein abgeleitetes Steuerelement für das Zoomen von Inhalten geben sollte, anstatt für das Scrollen

Für mich ist es tatsächlich sinnvoll, die Zoom-Funktionalität mit ScrollViewer eingebaut zu haben, insbesondere auf Touch-Geräten. Es gibt derzeit keine einfache Möglichkeit, ein Bild/ein Steuerelement in UWP frei zu schwenken/zoomen/drehen, und viele verwandte Fragen wurden auf StackOverflow und GitHub gestellt (z. B. Add draggable content control ).

@micahl , ich nehme an mit Zoomen und

Unterstützen Sie Rotationsgesten

würde dieses Szenario in Zukunft nativ unterstützt werden?

Für mich ist es tatsächlich sinnvoll, die Zoom-Funktionalität mit ScrollViewer eingebaut zu haben, insbesondere auf Touch-Geräten. Es gibt derzeit keine einfache Möglichkeit, ein Bild/ein Steuerelement in UWP frei zu schwenken/zoomen/drehen, und viele verwandte Fragen wurden auf StackOverflow und GitHub gestellt (z. B. Add draggable content control ).

Wenn Sie mehr Kontrolle über Zoomen und Scrollen haben möchten...

ScrollViewer.ScrollBehaviour = ScrollBehaviour.ZoomAndScroll;

Auf Touch-Geräten fühlt es sich jedoch natürlich an, das Einklemmen und Gleiten der Finger zuzulassen. Beim Zoomen ohne Berührung müssen jedoch die Tasten [ + ] und [ − ] angezeigt werden. Oder wenn es nur Zoom war, würde das Ziehen des Scrollbar-Daumens hinein- und herauszoomen.

Wenn Sie sich die Microsoft Word-Benutzeroberfläche ansehen, befindet sich in der Statusleiste ein Zoom-Steuerelement. Und Bildlaufleisten für den Dokumentbereich.

Ist die Mauszoomunterstützung etwas, das in das neue ScrollViewer-Steuerelement integriert werden sollte? Wenn also ZoomMode aktiviert ist oder eine Verhaltenseigenschaft Zoom zulässt - erscheinen dann Plus- und Minus-Schaltflächen?

@JustinXinLiu Die Unterstützung von Rotationsgesten würde wahrscheinlich die Unterstützung von InteractionTracker (@likuba) erfordern.

@mdtauk Der neue ScrollViewer würde das Zoomen mit dem Mausrad über ein Strg + Mausrad ähnlich dem vorhandenen ScrollViewer unterstützen. Mir ist unklar, ob das Steuerelement bei aktiviertem Zoom standardmäßig über eine Plus-/Minus-Schaltfläche verfügen soll. Mein derzeitiger Eindruck ist, dass die Arten von Apps, die normalerweise das Zoomen ermöglichen (z. B. eine Inhaltsdokument-App), diese Schaltflächen auf unterschiedliche Weise in ihre App-Erfahrung integrieren. Zum Beispiel ein - / + in einer Statusleiste, die durch einen Schieberegler getrennt ist (zB Office) oder einfach ein -/+, das vertikal unter anderen Befehlen (zB Maps) erscheint.

@micahl Ich verstehe nicht, warum ScrollFrom so heißt. Ist es nicht wie ScrollBy, aber mit einem Velocity-Parameter?

@adrientetar fragen Sie, warum nicht eine weitere Überladung von ScrollBy mit einem anderen Satz von Parametern verwendet wird, anstatt sie ScrollFrom zu benennen?

Ja, denke ich 😃 aber ich stelle mir vor, dass das Konzept hinter ScrollFrom darin besteht, sich mit einer bestimmten Geschwindigkeit in eine Richtung zu bewegen? im Gegensatz zu ScrollBy, das nur zu einem bestimmten Punkt bewegt wird.

Korrekt. Wir haben uns 3 Situationen vorgestellt:

  1. Es ist mir egal, was meine aktuelle Position ist. Ich möchte zu einem bestimmten Ziel scrollen/zoomen.
  2. Meine aktuelle Position ist mir wichtig und ich möchte um einen bestimmten Betrag relativ zu dieser Position scrollen/zoomen.
  3. Es ist mir egal, was das endgültige Ziel ist. Ich möchte nur von meiner aktuellen Position scrollen/zoomen.

Ein Szenario für letzteres könnte so etwas wie das Mausrad-Klicken zum Schwenken sein. Abhängig von der Position des Cursors relativ zu dem Zeitpunkt, an dem darauf geklickt wurde, wird eine gewisse Trägheit eingefügt, um von der aktuellen Position (was auch immer das ist) zu scrollen.

Danke, das klärt die Sache. Ich denke, ich möchte ScrollBy eher für mein eigenes Mausrad-Klick-Erlebnis verwenden, aber ich kann sehen, dass ScrollFrom in bestimmten Fällen nützlich ist.

Im aktuellen ScrollViewer-Steuerelement ist es möglich, an die Eigenschaften ViewportWidth und ViewportHeight zu binden, aber dies scheint derzeit im neuen ScrollViewer-Steuerelement nicht möglich zu sein. Wird das hinzugefügt?

@lhak , an was würden Sie diese Werte binden? Sie hinzuzufügen wäre keine große Veränderung. Abhängig vom Kontext für Ihr Szenario kann es sein, dass wir einen anderen Ansatz empfehlen als verbindlich. Wir möchten zwar sensibel für Unterschiede sein, die den Übergang von einem zum anderen erschweren, aber wir möchten auch Alternativen fördern, wenn sie besser sind.

@micahl Ich bin mir ziemlich sicher, dass ich diese Werte in der Vergangenheit auch für einige Berechnungen verwendet habe. Ich bin mir nicht sicher, ob ich an sie gebunden bin.

@michael-hawker Um das klarzustellen, werden die Eigenschaften im ScrollViewer verfügbar sein. In der vorgeschlagenen API werden sie jedoch als reguläre Eigenschaften und nicht als DependencyProperties bereitgestellt. Dieselben Werte sind als Teil der ExpressionAnimationSources-Eigenschaft für Situationen verfügbar, in denen jemand eingabegesteuerte Animationen basierend auf Komposition erstellt.

Ich verwende derzeit einen Code ähnlich dem folgenden in meiner Anwendung:

<ScrollViewer x:Name="outputScrollViewer">
  <Viewbox MaxWidth="{x:Bind outputScrollViewer.ViewportWidth, Mode=OneWay}" MaxHeight="{x:Bind outputScrollViewer.ViewportHeight, Mode=OneWay}">
    <TheXamlElement Width=X Height=Y/>
  </Viewbox>
</ScrollViewer>

Dies ermöglicht es, das innere xaml-Element (das eine feste Größe hat) zu scrollen/zu zoomen, während das Seitenverhältnis beibehalten wird. Das Verhalten ist ähnlich wie bei der Foto-App, die ein Bild anzeigt, mit der Ausnahme, dass das xaml-Element nie kleiner ist als das Ansichtsfenster des Scrollviewers.

@lhak , gutes Szenario! Ich denke laut darüber nach, wie dieses Szenario im aktuellen Vorschlag berücksichtigt werden könnte ... Ich

  • Keine = Keine Vorzugsorientierung. Geben Sie dem Inhalt unendliche verfügbare Größe in beide Richtungen.
  • Horizontal = Geben Sie dem Inhalt nur horizontal eine unendliche verfügbare Größe und beschränken Sie die Höhe während des Layouts auf das Ansichtsfenster.
  • Vertikal = Horizontales transponieren

Eine vierte Option wäre, sowohl die Höhe als auch die Breite während des Layouts auf die Größe des Ansichtsfensters zu beschränken. Im Moment nenne ich dies eine "Viewport" -Orientierung, obwohl ich gemischte Reaktionen darauf habe, sie als solche zu benennen.
Zumindest im (häufigeren?) Fall eines Bildes würde es meiner Meinung nach die Viewbox und Bindungen überflüssig machen, da "das Richtige" nur als Teil des Layoutprozesses passieren sollte.

<ScrollViewer ContentOrientation="Viewport">
  <Image Stretch="Uniform" .../>
</ScrollViewer>

Bei komplexeren Inhalten können Sie diese in eine Viewbox einschließen und trotzdem die Bindungen überspringen.

<ScrollViewer ContentOrientation="Viewport">
  <Viewbox>
    <TheXamlElement Width=X Height=Y/>
  </Viewbox>
</ScrollViewer>

@micahl Habe eine andere Frage: Ich möchte die Handhabung des Mausrads von Scroller ändern, um den Zoom schneller zu machen (größere Schritte) und die Glättungsanimation zu entfernen. Es scheint, als ob es keine API gibt, um das Zoomen des Rads zu optimieren. Muss ich das Mausrad-Ereignis manuell verarbeiten?

Möglicherweise müssen Sie das Mausrad manuell bedienen, aber es wäre bedauerlich, wenn sich herausstellt, dass Sie die Funktion des Steuerelements erneut implementieren müssen. Wir glauben, dass es einen Weg geben könnte, das zu erreichen, wonach Sie suchen. Der Kern davon wäre, die ZoomInertiaDecayRate auf einen Wert nahe 1,0 zu setzen und dann einen wiederholten Zoom-Fangpunkt zu definieren. Es ist etwas, das Sie ausprobieren sollten, sobald wir die ZoomInertiaDecayRate-Eigenschaft hinzugefügt und einige Probleme im Zusammenhang mit obligatorischen Fangpunkten behoben haben.

Wenn das nicht funktioniert, können Sie versuchen, es selbst zu handhaben, indem Sie IgnoredInputKind="Mousewheel" festlegen und dann entweder den Scroller in eine Unterklasse überschreiben, um OnPointerWheelChanged zu überschreiben, oder einen Ereignishandler für das PointerWheelChanged-Ereignis auf Scroller hinzufügen.

@micahl Danke! Ich bin mir nicht sicher, für welches Szenario Sie das Mausradverhalten kalibriert haben, persönlich gefällt mir die Art und Weise, wie es z. Scroller-Mausrad-Zoom-Animation fühlt sich etwas träge an und hat imo wirklich kleine Zoom-Schritte.

@adrientetar , gutes Feedback. Wir können prüfen, ob wir es anpassen.

Jede Art von Variable, die Inkremente und Werte steuert - könnte zu überschreibbaren Eigenschaften gemacht werden

Rechts. Eine Herausforderung für uns hier besteht darin, dass unter Win10 Version 1809 und höher die Steuerung die Mausradeingabe an den zugrunde liegenden InteractionTracker übergibt, damit sie für flüssigere Bewegungen vom UI-Thread verarbeitet werden kann. Diese überschreibbaren Eigenschaften müssten zuerst auf der unteren Ebene verfügbar gemacht werden. Für Versionen von Win10 vor 1809 fügen wir Logik hinzu, damit der Steuerungsprozess Mausradeingaben auf dem UI-Thread hat.

Wir könnten ein Verhalten in Betracht ziehen, bei dem wir einige überschreibbare Eigenschaften bereitstellen und wenn explizit festgelegt werden, dann auf das Mausrad des Steuerungsprozesses im UI-Thread zurückgreifen. Wenn diese Eigenschaften auf der unteren Ebene vorhanden sind, können wir uns auf sie verlassen und sie wieder an den Compositor übergeben. Scrollen wäre wahrscheinlich nicht so glatt für das Mausrad. Vielleicht ist das hier in Ordnung?

Das aktuelle Zoomverhalten ist also in InteractionTracker integriert, ohne dass es überschrieben werden kann? Und ich denke, jetzt gibt es keine Möglichkeit, es zu ändern, weil es die Abwärtskompatibilität brechen würde 🤔 cc @likuba

Ich denke, es gibt einige Optionen auf InteractionTracker, die hier helfen könnten 😊. Insbesondere haben wir Funktionen wie PointerWheelConfig und DeltaScaleModifier entwickelt , um diese Arten von Anpassungen zu ermöglichen. Wir werden eine Synchronisierung durchführen und sehen, ob die Verwendung dieser Elemente innerhalb des Steuerelements hier ohne die oben genannten Probleme/Risiken passieren kann.

@micahl Ich habe eine interessante Situation bei einem Projekt, an dem ich arbeite und musste meinen eigenen Scrollviewer für den PoC schreiben - aber ich würde gerne wissen, ob Sie Pläne haben (oder ob das Steuerelement dies bereits unterstützt) für folgendes Szenario:
Angenommen, Sie haben eine riesige Leinwand, 10000 x 5000. Um sich darauf zu bewegen, kapseln Sie sie in einen Scrollviewer.
Jetzt haben Sie auf der Leinwand 2 InkCanvases (oder mehr) und möchten auf beiden (oder mehr) schreiben, mit verschiedenen Fingern oder mit 1 Finger und 1 Mauszeiger. Wie würden Sie das mit dieser Steuerung erreichen (oder ist das überhaupt möglich)? :)
Was ich gesehen habe, ist das Standardverhalten, sobald Sie beim Zeichnen auf einer InkCanvas etwas anderes berühren, feuert diese bestimmte InkCanvas "PointerLost" und das war's - nichts anderes zu tun.
Offensichtlich ist mein Scrollviewer alles andere als perfekt, da ich ihn selbst geschrieben habe - also versuche ich zu sehen, ob dies mit diesem Steuerelement möglich ist?

Dankesehr !

Hallo @stefangavrilasengage , interessantes Szenario. :) Was ist von Ihrem PoC aus zu erwarten, wenn ein Finger auf eine InkCanvas fällt und sich dann zu bewegen beginnt? Zieht oder schwenkt es?

Hallo @micahl - danke für die Antwort! Ich nehme an, Sie haben inzwischen erraten, dass es sich um eine digitale Whiteboard-App handelt.
Jetzt präsentiere ich, was aktuell passiert:

  • ScrollViewer (Standard): Ein Fingerzeichnen auf einer InkCanvas ist in Ordnung. 2. Finger führt dazu, dass die 1. InkCanvas Eingabe verliert.
  • ScrollViewerEx (benutzerdefiniertes Steuerelement): Verwenden Sie so viele Finger und so viele InkCanvases zum Zeichnen und es funktioniert.

Hilft das? :)
Dankeschön !

@stefangavrilasengage Ich habe gefragt, was

@micahl Entschuldigung - vergessen zu erwähnen, wie ich den Konflikt gelöst habe.
Die Objekte, die wir auf der Leinwand haben, haben ihre Tinte in einem Win2D-Container. Nur wenn Sie für jedes Objekt einen Bearbeitungsmodus aktivieren, wird oben eine InkCanvas zur Bearbeitung angezeigt (mit benutzerdefinierter Trocknung).
Daher sollte in meiner Situation (nicht sicher, ob dies auf andere zutrifft), wenn Sie eine InkCanvas aktiv "drawable" haben, nichts zum ScrollViewer hochgehen.
Mich würde ein Anwendungsfall interessieren, bei dem dies Ihrer Meinung nach nicht zutrifft, wenn überhaupt?

Vielen Dank !

Kaum zu glauben, dass @micahl und ich zum ersten Mal in eine Github-Ausgabe geraten sind!

Kaum zu glauben, dass @micahl und ich zum ersten Mal in eine Github-Ausgabe geraten sind!

Das tut mir leid ! Bearbeitet!

@micahgodbolt Es ist vielleicht nicht das letzte Mal. ;)
@stefangavrilasengage danke! Das beantwortet meine Frage. Mir ist aufgefallen, dass das Austauschen eines ScrollViewer mit etwas anderem wie einem Border als übergeordnetes Element eines Canvas mit mehreren InkCanvas-Steuerelementen nicht das gleiche Problem hat. Ich habe mich also intern an einige Leute gewandt, um zu verstehen, was dazu führen kann, dass die Multi-Input / Multi-InkCanvas-Funktionalität zusammenbricht, wenn dies in einem ScrollViewer passiert.

@stefangavrilasengage , herauszufinden, warum es nicht funktioniert, wird einige Zeit / Untersuchung dauern. Lassen Sie uns das getrennt von diesem Vorschlag verfolgen. Eröffnen Sie ein Thema dafür?

@micahl Ich habe ein Problem mit Scroller, bei dem das Scrollen und Zoomen um meinen Inhalt in OnControlLoaded mich in eine falsche Position bringt. Wenn ich nur scrolle, lande ich an der richtigen Position, aber wenn ich direkt nach dem Scrollen zoome, befinde ich mich in einer völlig falschen Position, obwohl ich centerPoint=null angegeben habe, sodass es standardmäßig in der Mitte des Ansichtsfensters angezeigt wird (vom Betrachten des Codes, weil es noch keine Dokumentation). Mit diesem Code .

Danke fürs Ausprobieren, @adrientetar! Lassen Sie uns diesen Thread auf den Vorschlag konzentrieren. Können Sie für das, was Sie sehen, ein separates Problem öffnen? Je nachdem, wo wir in dieser Diskussion ankommen, möchten wir vielleicht zu diesem Thread zurückkehren, um zu diskutieren, ob Änderungen am Vorschlag erforderlich sind.

@micahl Warum haben ExtentChanged/StateChanged/ViewChanged-Ereignisse ein Objekt als Argument und nicht zB StateChangedEventArgs mit einem State-Member? Da InteractionTracker in einem anderen Thread ausgeführt wird, wird das Nachrichtenübergabemuster (Ereignis mit einem Argument) nicht dem Abfragen der Steuerelementeigenschaft im Ereignishandler vorgezogen?

https://github.com/XeorgeXeorge/Extended-Image-Viewer

Keine große Sache, aber der erste Teil dieses Repos zeigt, wie man das Zoomen implementiert, auch wenn die horizontalen / vertikalen Bildlaufleisten gesperrt sind (deaktiviert).

In einfacheren Worten:
Ermöglicht das Schwenken eines eingezoomten Inhalts, während die Anpassung immer noch erzwungen wird
effektives vertikales/horizontales Ansichtsfenster.

Zum Zeitpunkt der Veröffentlichung ist es zwingend erforderlich, die HorizontalScrollbarVisibility-Eigenschaft in einem ScrollViewer zu aktivieren, um tatsächlich einen funktionsfähigen Zoom-Vorgang zu erhalten genug.

@micahl Ich sehe, dass Scroller keine StateChanged-Ereignisse sendet, wenn ein nicht animierter Zoom ausgeführt wird, ist das beabsichtigt?
Ich stelle meine CanvasVirtualControl-Skalierung ein, wenn Scroller inaktiv wird, wie Sie in https://github.com/microsoft/microsoft-ui-xaml/issues/541#issuecomment -488749469 vorgeschlagen haben, damit das Steuerelement nicht zu groß gerastert wird Teile der Leinwand relativ zum Zoomfaktor. Aber bei einem nicht animierten Zoom muss ich das tun, wenn ich die ZoomTo-Methode aufrufe, obwohl die Zoomänderung nicht (afaikt) realisiert wurde.

@adrientetar , das Erstellen von Ereignisargumenten, die zwischen dem Framework und der App hin und her

Ja, das aktuelle Design besteht darin, dass StateChanged in einem nicht animierten Zoom, den Sie programmgesteuert aufrufen, nicht ausgelöst wird. Die ZoomCompleted- und ScrollCompleted-Ereignisse würden als Reaktion auf programmgesteuerte Änderungen ausgelöst. IIRC werden sie nicht durch Änderungen des Benutzers ausgelöst. Sie könnten eines davon verwenden, vielleicht in Kombination mit StateChanged. Zu Ihrer Information wird das ViewChanged-Ereignis immer ausgelöst, wenn sich die Ansicht ändert (Benutzer oder programmgesteuert), was es zu einem sehr leistungsempfindlichen Codepfad macht und nicht das ist, was Sie verwenden möchten.

Wir hören immer noch auf Feedback. Wenn die Dinge stumpf erscheinen, lassen Sie es uns wissen.

Ja, das aktuelle Design besteht darin, dass StateChanged in einem nicht animierten Zoom, den Sie programmgesteuert aufrufen, nicht ausgelöst wird.

Ah okay, jetzt verstehe ich. Vielleicht könnte das Ereignis immer ausgelöst werden und einen Ursprungsparameter wie SetFocus enthalten, aber vielleicht ist das mit etwas Aufwand verbunden.

Die ZoomCompleted- und ScrollCompleted-Ereignisse würden als Reaktion auf programmgesteuerte Änderungen ausgelöst. IIRC werden sie nicht durch Änderungen des Benutzers ausgelöst.

Okay, für meinen Anwendungsfall muss ich also ZoomCompleted und StateChanged behandeln, wenn State == Idle, je nachdem, ob die Änderung programmgesteuert ist oder nicht. Ist das nicht seltsam? Ich meine, verschiedene Events mit unterschiedlichen Namen für die gleiche Sache zu haben, hat nur einen anderen Weg ausgelöst 🤔

@RBrid und ich hatten ein kurzes Gespräch über die Einführung eines neuen Zustands "Übergang" und einige kleinere Umbenennungen. Lassen Sie uns wissen, ob dies für Ihren Anwendungsfall sinnvoller wäre.

Die diskutierte Idee war, dass wir das StateChanged-Ereignis auslösen und den aktuellen Status als Transitioning melden, wenn eine Änderung an der Scroll-/Zoom-Position durchgeführt werden soll (ob vom Benutzer initiiert oder programmgesteuert). So würde die Sequenz für ein programmatisches Scrollen (animiert und nicht animiert) aussehen:

// Programmatische Anfrage, animiert
myScrollInfo = ScrollTo(100, animate=true);
// ein paar Zecken
StateChanged ausgelöst (Scroller.State == Transitioning)
// ein paar Zecken
StateChanged ausgelöst (Scroller.State == Animation)
// viele Zecken
StateChanged ausgelöst (Scroller.State == Idling)

// Programmatische Anfrage, keine Animation
myScrollInfo = ScrollTo(100, animate=false);
// ein paar Zecken
StateChanged ausgelöst (Scroller.State == Transitioning)
// ein paar Zecken
StateChanged ausgelöst (Scroller.State == Idling)

Wir würden wahrscheinlich die InteractionState-Enumeration in etwas wie ScrollState umbenennen wollen, da sie mehr als nur die Interaktionen darstellen würde.

enum ScrollState
{
    Idling = 0,
    Transitioning = 1,
    Interacting = 2,
    Inertial = 3,
    Animating = 4,
};

@micahl Ja, das sieht sehr nach dem aus, was ich erwarten würde! Jemand, der nur animierte Änderungen verarbeiten möchte, kann den Animating-Status abfangen. Für die Namen würde ich Idle not Idling ("Scroller is empty"/"Scroller is animating"), Transitioning → Stirring? (Übergänge sind sehr verwirrend, ich möchte lieber vermitteln, dass es am Anfang der Bewegung ist, so dass Imo-Rühren besser funktionieren könnte ), Trägheit könnte Drifting sein 😛 aber ich denke, API Review wird auch einspringen.

Beim Rühren dachte ich anfangs ans Mischen. :) API-Review wird abwägen wollen, wenn wir Namen finalisieren und neigt dazu, nach Präzedenzfällen zu suchen. Es ist immer gut, einige Optionen zu haben. Andere Alternativen könnten Unbekannt oder Ausstehend sein. Es gibt einen Präzedenzfall in bestehenden APIs für beide zusammen mit Idle, was bedeutet, dass wir Idling wahrscheinlich nicht machen würden.

Cool Cool. Pending sgtm, imo Unknown ist noch verwirrender als Transitioning.

@micahl -- Funktionale Anforderung Nummer 3 enthält diesen Unterpunkt:

nimmt an effektiven Ansichtsfensteränderungen teil (Muss)

Dieser Unterpunkt bezieht sich auf das bereits vorhandene Ereignis FrameworkElement.EffectiveViewportChanged . Reicht dieser Unterpunkt aus, um (indirekt) zu sagen, dass das asynchrone teilweise Laden von Inhalten bei Bedarf auch eine Anforderung/Priorität ist? Ich meine zum Beispiel das Äquivalent dazu, wie der ScrollViewer funktioniert, wenn MS Edge eine vergrößerte Seite eines PDF-Dokuments (oder SVG oder eines anderen komplexen Dokuments) anzeigt. Wenn der Zoom beispielsweise 900 % beträgt, wird die gesamte PDF-Seite aus folgenden 2 Gründen nicht mit 900 % vorgerendert:

  • Diese Rendering-Aufgabe (bei hohem Zoom-Prozentsatz) benötigt je nach Komplexität des Dokuments (Anzahl der Vektorelemente, Effekte usw.), Dokumentgröße und Zoom-Prozentsatz ungefähr 3 .. 20 Sekunden. Diese Verzögerung ist für Endbenutzer zu groß, um sie zu akzeptieren.
  • Ein gerendertes Bild (Bitmap) der gesamten PDF-Seite kann bei einem hohen Zoom-Prozentsatz Hunderte von Megabyte RAM verbrauchen, da dies dem Rendern mit einer sehr hohen DPI entspricht.

MS Edge rendert Teile der vergrößerten PDF-Seite bei Bedarf, dh wenn der Benutzer diese Teile in die Ansicht scrollt. Diese Technik vermeidet die lange Verzögerung, bevor die Seite angezeigt wird. Ich schlage vor, dass die funktionalen Anforderungen dieses Szenario explizit erwähnen, aber auch mit indirekter Unterstützung für async Task . Wenn ein nicht gerenderter (oder anderweitig nicht sofort verfügbarer) Teil in die Ansicht gescrollt wird, kann ScrollViewer diesen Platz vorübergehend mit einem konfigurierbaren Brush füllen und dann ein Ereignis auslösen, und der Ereignishandler kann ein async Task starten um das Teil zu rendern (oder anderweitig abzurufen/zu laden). Später, wenn Task abgeschlossen ist, wird der gerenderte/abgerufene/geladene Teil im ScrollViewer angezeigt und deckt den Platz ab, der vorübergehend mit Brush gefüllt wurde.

Bei diesem Problem geht es nicht nur um die hohen Kosten für das Rendern bei einem hohen Zoom. Sie gilt auch für Inhalte, die bei Bedarf abgerufen werden. Stellen Sie sich beispielsweise eine Karte oder ein Satellitenbild vor, die in ScrollViewer angezeigt werden. Teile der Karte werden nur dann vom Server heruntergeladen, wenn der Benutzer sie in die Ansicht scrollt.

Sollten die Zoom-bezogenen APIs in ein abgeleitetes Steuerelement (z. B. ZoomViewer) unterteilt werden, so dass es bei ScrollViewer ausschließlich um das Scrollen geht?

Obwohl ich das Hinzufügen von ScrollViewer.ZoomFactor sehr geschätzt habe, war ich überrascht zu sehen, dass es direkt zu ScrollViewer hinzugefügt wurde. Ich nahm an, dass es einfacher und zuverlässiger wäre, Zoom in eine separate Klasse (nicht unbedingt eine abgeleitete Klasse) zu legen. Mindestens 3 Wege sind möglich:

  1. Eine Klasse namens vielleicht ZoomViewer , die ScrollViewer NICHT erbt, sondern eine ScrollViewer -Instanz als untergeordnetes Element verwendet (in ihrer ControlTemplate ).
  2. Eine Klasse namens ZoomableScrollViewer , die ScrollViewer erbt.
  3. Direkte Unterstützung des Zooms innerhalb von ScrollViewer , wenn es nicht übermäßig kompliziert oder unordentlich ist.

17 Stellen Sie eine Standard-UX bereit, um einen mittleren Mausklick und ein Scrollen zu unterstützen. (Sollen)
18 Unterstützen Sie einen Modus zum Klicken und Verschieben mit der Maus (z. B. Verschieben von Inhalten in einem PDF-Viewer). (Sollen)

Ich schlage vor, darüber nachzudenken, ob die Unterstützung für 17 aufgehoben werden soll, da 18 viel besser funktioniert als 17 und kaum jemand 17 in der Praxis verwendet. Zugegeben, ich denke vielleicht, dass 17 etwas anderes bedeutet als Ihre beabsichtigte Bedeutung (die Beschreibung von 17 ist nur ein Satz und ich bin mir nicht 100% sicher, ob es das bedeutet, was ich denke). Ist es nicht richtig zu sagen, dass 18 sehr benutzerfreundlich und einfach zu verwenden ist, während 17 eine umständliche Sache ist, die jeder nur schwer verwenden kann und vermeidet?
(Dieses Problem ändert sich, wenn 17 aus Gründen der Zugänglichkeit erforderlich ist, aber bisher habe ich noch nie jemanden sagen hören, dass 17 ein Zugänglichkeitsproblem ist.)

4 Kann eingabegesteuerte Animationen ausführen

Nummer 4 ist ein Problem im Zusammenhang mit der Barrierefreiheit. Ich möchte darum bitten, dass ScrollViewer (und alle anderen Steuerelemente in WinUI) die Eingabehilfeeinstellungen respektieren:

Windows 10 -> Start -> Einstellungen -> Benutzerfreundlichkeit -> Anzeige -> Animationen in Windows anzeigen (Ein oder Aus).

Leider sind mir im Laufe der Jahre viele Beispiele aufgefallen, bei denen Microsoft-Apps die Eingabehilfen von Windows ignorieren. Animationen sind ausgeschaltet, aber Microsoft-Apps zeigen trotzdem Animationen an. Dies verursacht echte Schwierigkeiten für die Benutzer, die sich auf diese Zugänglichkeitseinstellungen verlassen. Nicht jeder hat die Möglichkeit, Animationen zu genießen, ohne negative Nebenwirkungen zu erleiden. Benutzer, die keine Schwierigkeiten beim Anzeigen von Animationen usw. haben, können die Bedeutung der Eingabehilfeeinstellungen in Windows nur schwer verstehen.

Hallo @verelpode , @predavid wird die Arbeit rund um den neuen ScrollViewer vorantreiben, also überlasse ich sie ihr.

17 Stellen Sie eine Standard-UX bereit, um einen mittleren Mausklick und ein Scrollen zu unterstützen. (Sollen)
18 Unterstützen Sie einen Modus zum Klicken und Verschieben mit der Maus (z. B. Verschieben von Inhalten in einem PDF-Viewer). (Sollen)

Ich schlage vor, darüber nachzudenken, ob die Unterstützung für 17 aufgehoben werden soll, da 18 viel besser funktioniert als 17 und kaum jemand 17 in der Praxis verwendet. Zugegeben, ich denke vielleicht, dass 17 etwas anderes bedeutet als Ihre beabsichtigte Bedeutung (die Beschreibung von 17 ist nur ein Satz und ich bin mir nicht 100% sicher, ob es das bedeutet, was ich denke). Ist es nicht richtig zu sagen, dass 18 sehr benutzerfreundlich und einfach zu verwenden ist, während 17 eine umständliche Sache ist, die jeder nur schwer verwenden kann und vermeidet?
(Dieses Problem ändert sich, wenn 17 aus Gründen der Zugänglichkeit erforderlich ist, aber bisher habe ich noch nie jemanden sagen hören, dass 17 ein Zugänglichkeitsproblem ist.)

@verelpode Ich denke, Sie verstehen 17 richtig und ich stimme zu, dass 18 wichtiger und normalerweise intuitiver ist als 17. Aber es kann Szenarien geben, in denen "Linksklick und Ziehen" bereits für andere Zwecke verwendet wird, z . Für solche Szenarien wäre es gut, wenn die App das Scrollen durch Mittelklick ermöglichen könnte (17).

Ich persönlich verwende von Zeit zu Zeit das Scrollen mit einem mittleren Klick in Browsern, bei dem Linksklick + Ziehen entweder eine Textauswahl oder Drag + Drop von Bildern bewirkt. Bei einem UWP-Browser wären 18 deaktiviert und 17 aktiviert. Beide sollten über separate Eigenschaften aktiviert werden.

@lukasf

Ich persönlich verwende von Zeit zu Zeit das Scrollen mit einem mittleren Klick in Browsern, bei dem Linksklick + Ziehen entweder eine Textauswahl oder Drag + Drop von Bildern bewirkt.

Ein guter Punkt in Bezug auf die Notwendigkeit, zu vermeiden, dass die Textauswahl usw. nicht mehr funktioniert. Was halten Sie von dieser möglichen Lösung: Lassen Sie mit einem Mittelklick den mausbasierten Schwenkmodus (18) starten, anstatt den umständlichen 17-Modus zu starten.

Wenn ich mir anschaue, was andere Apps tun, können Sie bei einigen Apps das mausbasierte Schwenken starten, indem Sie die Leertaste gedrückt halten, während Sie mit der linken Maustaste in den scrollbaren Inhaltsbereich klicken. Diese Lösung ermöglicht es, dass Linksklick innerhalb des scrollbaren Inhaltsbereichs normal funktioniert, da der Panning-Modus nur über Leertaste + Klick gestartet wird. Schwenken per Leertaste+Klick finde ich sehr komfortabel und bequem und schnell.

Diese Leertaste+Klick-Lösung ist jedoch einfacher in Apps zu implementieren, die keine bearbeitbaren Textfelder innerhalb des scrollbaren Inhaltsbereichs anzeigen müssen. Wenn im scrollbaren Inhaltsbereich bearbeitbare Textfelder vorhanden sind, wäre es ein Problem, dass die Panning-Funktion Benutzer nicht in die Lage versetzt, Leerzeichen in Textfelder einzugeben. Daher sollte diese Funktion, wie Sie bereits sagten, über eine Eigenschaft aktiviert werden. Verwenden Sie alternativ nicht die Leertaste, sondern starten Sie mit einem mittleren Klick den mausbasierten Schwenkmodus (18), wodurch das Problem beseitigt wird, dass Benutzer keine Leerzeichen in Textfelder eingeben können.

@verelpode
Bei allen Browsern und auch einer Reihe anderer Anwendungen (Word, Adobe Reader, Outlook,...), die den Modus 17 unterstützen, würde ich dies immer noch finden. Nur weil Sie es persönlich unangenehm finden, heißt das nicht, dass es für andere nicht nützlich ist. Beide Modi sollten natürlich aktiviert sein, dann können die Entwickler entscheiden, was in ihrer App verwendet werden soll. Dies würde auch Ihr Leertaste+Klick-Verhalten ermöglichen, wenn es für eine App sinnvoll ist: Modus 18 bei Leertaste unten aktivieren, bei Leertaste oben wieder deaktivieren.

@lukasf – OK, hört sich gut an. Ich dachte, Sie meinen, wenn der Schwenkmodus (18) die Textauswahl oder das Ziehen und Ablegen von Bildern usw. nicht verhindern würde, würden Sie den Modus 17 nicht mehr verwenden und zu 18 wechseln, aber jetzt sehe ich, dass Sie beide Modi bevorzugen unterstützt werden.

Vielen Dank für Ihr Feedback @verelpode und @lukasf , ich stimme Ihnen zu, dass wir letztendlich wollen, dass öffentliche Knöpfe am Scroller-Steuerelement die Nummern 17 und 18 ein- und ausschalten. Nennen wir sie 17 = mausbasiertes Konstantgeschwindigkeits-Panning und 18=Mausbasiertes Schwenken.

Ich habe gerade eine PR https://github.com/microsoft/microsoft-ui-xaml/pull/1472 verschickt, um einige meiner Recherchearbeiten hinzuzufügen. Ich wollte sehen, wie nah ich mit dem heutigen Scroller sowohl 17 als auch 18 unterstützen kann.

Beim 18 = mausbasierten Schwenken lief es ziemlich gut, obwohl die Lösung im Gegensatz zu den berührungsbasierten oder Mausrad-basierten Erfahrungen zu 100 % UI-Thread-gebunden ist. Ich habe die ScrollTo-Methode verwendet, während ich das PointerMoved-Ereignis der Maus abgehört habe. Letztendlich möchten wir, dass die zugrunde liegende InteractionTracker-Komponente Mausbewegungen wie Fingerbewegungen behandelt.

Die Dinge sind viel schwieriger für 17 = Maus-basiertes Schwenken mit konstanter Geschwindigkeit (eine Erfahrung, die ich persönlich nicht mag). Der Prototyp ist alles andere als ideal und ich habe nicht versucht, alle Probleme anzugehen, aber zwei sind besonders besorgniserregend:

  • Während eines Pannings mit konstanter Geschwindigkeit (dh 0-Velocity-Decay-Panning) glaube ich nicht, dass es mit dem aktuellen Scroller eine Möglichkeit gibt, die Bewegung zu stoppen, ohne zu einer älteren Position zurückzukehren (mit ScrollBy(0, 0)) . Es ist einfach nicht zuverlässig möglich zu wissen, wie weit der Kompositionsthread dem UI-Thread voraus ist. Daher wäre eine neue öffentliche Scroller-API erforderlich, um die Geschwindigkeit störungsfrei zu stoppen.
  • Ich konnte die Mauserfassung nach dem PointerReleased-Ereignis der Maus nicht beibehalten. Es scheint, dass dafür ein neues Xaml-Framework-Feature erforderlich wäre.
    Wie auch immer, dies kann ein weiterer Fall sein, in dem wir möchten, dass der zugrunde liegende InteractionTracker einen Teil der Erfahrung direkt verarbeitet.
    Ich werde diese unbedingt im Hinterkopf behalten, wenn ich zukünftige Scroller/InteractionTracker-Funktionen bespreche.

@RBrid

Für 18=mausbasiertes Schwenken lief es ziemlich gut, …...
Die Dinge sind viel schwieriger für 17 = Maus-basiertes Schwenken mit konstanter Geschwindigkeit (eine Erfahrung, die ich persönlich nicht mag).

Interessante Ergebnisse! Angesichts der Schwierigkeiten mit 17 = konstanter Geschwindigkeit und der Tatsache, dass 18 auf eine Weise implementiert werden kann, die die normale Verwendung von Linksklick nicht verhindert, denke ich, dass der Vorschlag meiner persönlichen Meinung nach wahrscheinlich aktualisiert werden sollte geben Sie 17 auf und unterstützen Sie stattdessen 18, aber zugegebenermaßen weiß ich nicht, wie viele Benutzer sich beschweren würden, wenn 17=constant-velocity aufgegeben wird.

Danke @RBrid für diese Untersuchungen. Schön zu hören, dass Modus 18 bereits funktioniert! Ich stimme zu, dass es idealerweise von InteractionTracker gehandhabt werden sollte, um einen reibungslosen Betrieb auch während des Ladens des UI-Threads zu ermöglichen.

@verelpode Beide Modi sind als "Sollte" eingestellt. Wenn also der Aufwand zu hoch ist, um Modus 17 zu realisieren, könnte er einfach weggelassen (und ggf. später hinzugefügt werden). Aber vielleicht findet jemand einen Weg, dies ohne zu viele Änderungen zu realisieren.

Ich hoffe, der neue ScrollViewer kann Zoom mit der Taste "Strg" deaktivieren oder anpassen.

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen