Microsoft-ui-xaml: ScrollViewer yang lebih fleksibel

Dibuat pada 19 Des 2018  ·  61Komentar  ·  Sumber: microsoft/microsoft-ui-xaml

Ini adalah template untuk fitur baru atau proposal API. Misalnya, Anda dapat menggunakan ini untuk mengusulkan API baru pada tipe yang sudah ada, atau ide untuk kontrol UI baru. Tidak apa-apa jika Anda tidak memiliki semua detailnya: Anda dapat memulai dengan Ringkasan dan Dasar Pemikiran. Tautan ini menjelaskan fitur WinUI/proses proposal API: https://github.com/Microsoft/microsoft-ui-xaml-specs/blob/master/docs/feature_proposal_process.md Tambahkan judul untuk fitur atau proposal API Anda. Harap singkat dan deskriptif

Proposal: ScrollViewer

Ringkasan

tl:dr; Menyediakan kontrol scrolling dan zooming yang fleksibel, namun mudah digunakan, di XAML yang masih dapat dimanfaatkan saat menargetkan rilis tingkat bawah Win10.

Kontrol ScrollViewer memainkan peran penting dalam UI apa pun karena pengguliran mendasar untuk aplikasi dan kontrol (platform dan non-platform sama). Kontrol menyediakan kemampuan panning dan zooming bersama dengan kebijakan default dan UX (misalnya scroll bar sadar, interaksi fokus/keyboard, aksesibilitas, animasi scroll default, dll). Itu juga harus cukup fleksibel sehingga dapat beralih dari membuat skenario aplikasi sehari-hari menjadi mudah menjadi komponen kunci dalam kontrol berbasis gulir dan melayani kasus penggunaan yang sangat canggih. Kontrol saat ini tidak memberikan tingkat fleksibilitas ini.

Alasan

Jelaskan MENGAPA fitur harus ditambahkan ke WinUI untuk semua pengembang dan pengguna. Jika berlaku, Anda juga dapat menjelaskan cara menyelaraskannya dengan peta jalan dan prioritas WinUI saat ini: https://github.com/Microsoft/microsoft-ui-xaml-specs/blob/master/docs/roadmap.md

Membawa kontrol ScrollViewer ke repo dengan cara berlapis di atas API publik platform inti adalah batu loncatan penting yang:

  1. memungkinkan mengangkat lebih banyak kontrol ke dalam repo (peningkatan kelincahan),
  2. memberi pengembang kontrol yang mudah digunakan yang memunculkan fleksibilitas kemampuan platform tingkat rendah yang dikombinasikan dengan manfaat layanan kerangka kerja tingkat tinggi (misalnya aksesibilitas), dan
  3. memungkinkan fitur terkait pengguliran yang lebih baru di XAML untuk menyala di versi Win10 sebelumnya.

Kontrol yang ada dibuat di Win8 berdasarkan API DirectManipulation yang 1) tidak tersedia untuk digunakan secara langsung dalam UWP, 2) tidak mengizinkan tingkat penyesuaian yang diharapkan pengembang untuk menciptakan pengalaman pengguliran yang unik, dan 3) digantikan oleh API InteractionTracker UWP yang lebih baru.

Mengekstrak kontrol ScrollViewer yang ada apa adanya akan menjadi non-starter. Kontrol harus berupa implementasi ulang dengan permukaan API yang hampir identik berdasarkan kemampuan InteractionTracker yang lebih baru (dan sudah tersedia).

Paket tingkat tinggi

ScrollViewer yang ada di ruang nama _Windows_.UI.Xaml.Controls akan tetap tidak tersentuh (selain memperbaiki bug kritis).

ScrollViewer baru akan hidup di namespace _Microsoft_.UI.Xaml.Controls. API-nya sebagian besar akan identik dengan versi _Windows_. Kami akan membuat penyesuaian yang ditargetkan ke API kontrol di mana ada manfaat yang jelas (menyederhanakan skenario umum, memperkenalkan kemampuan baru, dll).

Dalam kombinasi dengan ScrollViewer baru kami akan memperkenalkan tipe baru, Scroller, yang akan hidup di namespace Microsoft.UI.Xaml.Controls._Primitives_. Scroller akan menyediakan fungsionalitas inti untuk menggulir dan memperbesar XAML berdasarkan kemampuan InteractionTracker .

Tujuan awal untuk kedua kontrol adalah mendapatkan fungsionalitas inti untuk mengirimkan kualitas untuk menjadi bagian dari rilis resmi berikutnya. API yang belum selesai akan tetap dalam 'pratinjau' dan hanya tersedia sebagai bagian dari paket pra-rilis.

-------------------- Bagian di bawah ini opsional saat mengirimkan ide atau proposal. Semua bagian diperlukan sebelum kami menerima PR untuk dikuasai, tetapi tidak perlu untuk memulai diskusi. -----------------------

Persyaratan Fungsional


| # | Fitur | | Prioritas |
|:-:|:--|-|:-:|
| 1 | Menyediakan kontrol _non-sealed_, panning dan zooming dengan UX default yang cocok dengan ScrollViewer yang ada. || Harus |
| 2 | Mendemonstrasikan kapabilitas platform dengan hanya mengandalkan API publik yang didukung platform. || Harus |
| 3 | Terintegrasi dengan layanan XAML tingkat kerangka kerja.
Sebagai contoh:
- benar membuat rects fokus sistem
- secara otomatis menampilkan elemen yang difokuskan (keyboard, GamePad, pembaca layar)
- berpartisipasi dalam perubahan viewport yang efektif
- mendukung penahan gulir || Harus|
| 4 | Mampu melakukan animasi berbasis input || Harus |
| 5 | Dapat digunakan dalam kombinasi dengan kontrol scroll-dependent yang sudah ada di repo (yaitu ParallaxView, RefreshContainer, SwipeControl). || Harus |
| 6 | Mampu mengontrol kurva untuk perubahan tampilan inersia (yaitu pengguliran atau pembesaran animasi kustom). || Harus |
| 7 | Mampu mengubah tampilan berdasarkan offset absolut atau relatif (mis. gulir ke tempat menarik) || Harus |
| 8 | Mampu mengubah tampilan berdasarkan impuls/kecepatan tambahan (misalnya pengguliran halus otomatis selama drag-and-drop atau multi-pilih melalui persegi panjang pemilihan mouse) || Harus |
| 9 | Mampu mendeteksi overpan dan seberapa banyak || Harus |
| 10 | Mampu mengamati dan bereaksi terhadap perubahan status scroll || Harus |
| 11 | Dukungan untuk menggulir dan memperbesar titik jepret. || Harus |
| 12 | Mampu menggunakan kontrol "scroll bar" khusus untuk mendorong pengguliran (mis. penggosok garis waktu foto). || Harus |
| 13 | Dapat dengan mudah mengonfigurasi kontrol untuk mengabaikan jenis input tertentu (misalnya merespons sentuhan atau pena, tetapi mengabaikan input roda mouse). || Harus |
| 14 | Mampu menyimpan dan mengembalikan posisi gulir (misalnya dalam daftar virtualisasi) || Harus |
| 15 | Dukungan untuk header / elemen lengket. || Harus |
| 16 | Dukungan untuk pengguliran yang dipercepat saat pengguna membuat gerakan berulang secara berurutan. || Harus |
| 17 | Berikan UX default untuk mendukung klik dan gulir tengah mouse . |mousewheel panning | Harus |
| 18 | Mendukung mode untuk mengklik dan menggeser melalui mouse (misalnya memindahkan konten di dalam penampil PDF). |mouse hand cursor for panning | Harus |
| 19 | Mampu menggunakan kontrol kustom untuk mendorong zoom (misalnya slider zoom). || Harus |
| 20 | Mampu mencetak konten yang terdapat di area scrollable. || Harus |
| 21 | Mendukung gerakan rotasi. || Bisa |
| 22 | Mampu menyinkronkan dua atau lebih area dengan pengguliran bebas flicker dan jank (misalnya skenario perbedaan teks). || Bisa |
| 23 | Mampu menyesuaikan kurva animasi untuk perubahan tampilan yang digerakkan oleh input (yaitu menentukan perilaku jari ke bawah seperti sumur gravitasi). || Bisa |
| 24 | Mendukung gerakan gulir ke atas atau bawah . || Bisa |
| 25 | Mampu menonaktifkan overpanning . || Bisa |
| 26 | Mampu memanipulasi konten secara selektif dalam ScrollViewer berdasarkan properti ManipulationMode UIElement . || Bisa |
| 27 | Mampu mematikan inersia dan/atau memantul dari inersia. || Bisa|
| 28 | Mampu menonaktifkan kliping konten (yaitu CanContentRenderOutsideBounds ). || Bisa |
| 29 | Mampu menentukan alasan penyelesaian di akhir perubahan tampilan. || Bisa |

Terminologi

  • _Overpan_ adalah saat pengguna mencoba menggeser atau memperbesar ukuran konten dan menghasilkan efek karet gelang.
  • _Railing_ adalah saat scroller secara otomatis mengunci gerakan ke sumbu "pilihan" berdasarkan arah gerakan awal.
  • _Chaining_ adalah ketika ada permukaan batasnya, itu dipromosikan untuk melanjutkan di bagian luar.
  • _Titik jepret_ adalah lokasi dalam konten yang dapat digulir di mana area pandang akan berhenti pada akhir pengguliran inersia (yaitu gulir animasi setelah pengguna mengangkat jari mereka). Titik jepret diperlukan untuk kontrol seperti FlipView.
  • _Scroll anchoring_ adalah tempat viewport secara otomatis bergeser untuk mempertahankan posisi relatif dari konten yang terlihat. Ini mencegah pengguna terkena dampak perubahan mendadak dalam posisi atau ukuran konten karena tata letak (yaitu pengguna sedang membaca artikel dan beberapa saat kemudian semuanya melompat turun karena gambar/iklan di bagian atas artikel akhirnya dimuat) . Penahan gulir adalah kebutuhan untuk virtualisasi UI ketika berhadapan dengan konten berukuran variabel.
  • _Sumur gravitasi_ adalah lokasi dalam konten yang dapat digulir yang memengaruhi perilaku pengguliran saat pengguna memanipulasi konten (yaitu jari pengguna di bawah). Misalnya, sumur gravitasi dapat digunakan untuk mengubah gesekan yang dirasakan saat menggulir di mana gerakan tampak melambat atau dipercepat saat pengguna secara aktif menggeser atau memperbesar.

Contoh penggunaan

Harap sertakan satu atau beberapa contoh yang menunjukkan bagaimana Anda akan menggunakan fitur tersebut. Anda dapat menyertakan contoh kode atau tangkapan layar jika itu membantu

Kata pengantar

Secara default, ScrollViewer mendukung menggeser kontennya saat ukuran konten lebih besar dari area pandangnya. Ukuran konten ditentukan oleh sistem tata letak XAML.

Contoh di sini dimaksudkan untuk menyoroti perbedaan API utama antara ScrollViewer saat ini dan ScrollViewer baru.

Pengguliran Vertikal (Tidak ada perbedaan)

Lebar konten secara otomatis dibatasi agar sama dengan viewport. Ketinggian tidak dibatasi. Jika melebihi ketinggian viewport maka pengguna dapat menggeser melalui berbagai modalitas input.

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

Pengguliran Horisontal

Ini adalah keberangkatan yang disengaja dari ScrollViewer yang ada yang sebelumnya mengharuskan perubahan HorizontalScrollBarVisibility. Ini telah membingungkan banyak pengembang.

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

Pengguliran horizontal saja diaktifkan dengan menyetel properti _ContentOrientation_ . Ini menentukan batasan apa yang digunakan pada konten selama tata letak. Nilai Horizontal menyiratkan bahwa konten tidak dibatasi secara horizontal (ukuran tak terbatas yang diizinkan) dan dibatasi secara vertikal agar sesuai dengan area pandang. Demikian pula, Vertikal (default) menyiratkan tidak dibatasi secara vertikal dan dibatasi secara horizontal.

Menggulir Gambar Besar

Orientasi Konten _Both_ menyiratkan konten tidak dibatasi baik secara horizontal maupun vertikal.

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

Mengubah Visibilitas ScrollBar

Contoh ini selalu menyembunyikan kedua scrollbar. Pengguna masih dapat menggeser konten ke kedua arah.

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

Mematikan dukungan bawaan untuk jenis input tertentu

Dalam contoh ini, pengembang membuat aplikasi berbasis kanvas yang akan melakukan pemrosesan khusus pada input roda mouse dan mendukung pengalaman pemilihan laso melalui Pena. Itu dapat mengonfigurasi ScrollViewer untuk mengabaikan jenis input tersebut sambil tetap menerima yang lain seperti Touch.

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

Sesuaikan animasi gulir terprogram

Pengembang mendengarkan acara ValueChanged Slider dan menganimasikan VerticalOffset ScrollViewer menggunakan durasi khusus pada animasi default.

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);
}

Desain Fitur Rinci

Harap sertakan detail desain yang penting. Ini dapat mencakup satu atau lebih dari: - proposal API (bahasa atau kode semu yang didukung boleh saja) - maket desain untuk pengalaman pengguna baru - detail tentang kepatuhan aksesibilitas untuk UI baru - catatan implementasi lainnya

Pengguliran kebijakan tinggi dan kebijakan rendah

Scroller (kebijakan rendah)

Scroller adalah blok bangunan tingkat rendah tanpa krom yang menyediakan semua logika panning dan zooming yang penting. Ini membungkus InteractionTracker dengan kebijakan yang lebih rendah dari platform sebagai elemen ramah markup XAML.
Secara harfiah, Scroller adalah "area pandang" untuk ScrollViewer dan menggantikan ScrollContentPresenter. Namun, Scroller, tidak seperti ScrollContentPresenter, melakukan lebih dari sekadar memotong kontennya.

Scroller memberikan fleksibilitas menggunakan InteractionTracker secara langsung dengan keuntungan sebagai berikut:

  • Dukungan aksesibilitas
  • Sintaks yang ramah markup dan API yang mudah digunakan
  • Integrasi dengan sistem tata letak XAML dan kemampuan virtualisasi

ScrollViewer (kebijakan tinggi)

ScrollViewer baru membungkus Scroller dan menyetel propertinya ke nilai umum. Misalnya, <ScrollViewer/> mengonfigurasi Penggulirnya untuk mendukung interaksi pengguliran horizontal dan vertikal, tetapi membatasi lebar kontennya sehingga pengalaman pengguna default tampaknya hanya pengguliran vertikal (kasus umum).

ScrollViewer memberikan keuntungan berikut dibandingkan menggunakan Scroller:

  • UX default (misalnya indikator gulir, bilah gulir sadar untuk mouse, kurva animasi default)
  • Dukungan default untuk input UI-thread terikat tidak ditangani oleh Scroller/InteractionTracker (yaitu keyboard dan GamePad)
  • Gerakan fokus default untuk GamePad (halaman atas/bawah dan secara otomatis mengatur fokus sebagai respons terhadap pemicu)
  • Kesadaran default dari pengaturan sistem pengguna (misalnya secara otomatis menyembunyikan bilah gulir di Windows)
  • (Masa Depan) Opsi konfigurasi yang mudah untuk titik jepret
  • (Masa Depan) Dukungan untuk lebih banyak mode mouse panning (misalnya konten klik-dan-tarik dengan tangan terbuka/tutup, mouse panning melalui roda mouse/klik tombol tengah menunjukkan kursor "kompas")

Yang mana yang harus digunakan?

Pilihan default untuk aplikasi dan banyak penulis kontrol adalah menggunakan ScrollViewer. Ini memberikan kemudahan penggunaan yang lebih besar dan UX default yang konsisten dengan platform. Scroller sesuai ketika UX / kebijakan default tidak diperlukan - misalnya, membuat kontrol FlipView yang ditingkatkan atau permukaan gulir tanpa krom.

API khusus ScrollViewer

HorizontalScrollBarVisibility / VerticalScrollBarVisibility

Nilai default untuk bilah gulir horizontal dan vertikal adalah _Auto_. Mereka secara otomatis ditampilkan atau disembunyikan berdasarkan apakah konten lebih lebar/tinggi dari viewport atau tidak.

Opsi 'Nonaktif' tidak akan ada di opsi enum yang tersedia untuk ScrollViewer baru. Alih-alih, mengonfigurasi kontrol untuk merespons interaksi pengguna yang menggeser secara horizontal atau vertikal hanya akan didasarkan pada properti _HorizontalScrollMode_ dan _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
    }
}

Pada gambar di bawah kursor mouse berada di atas bilah gulir vertikal. Ini adalah satu-satunya yang terlihat karena kontennya sama lebarnya dengan viewport.

Ketika konten lebih besar dari area pandang di kedua dimensi maka kedua bilah gulir sadar dapat dilihat serta pemisahnya di sudut kanan bawah.

API khusus scroller

HorizontalScrollController / VerticalScrollController

Scroller dapat dihubungkan ke "widget" interaktif yang mengontrol pengguliran dengan menyetel _HorizontalScrollController_ dan _VerticalScrollController_ ke tipe yang mengimplementasikan antarmuka _IScrollController_. ScrollBars adalah contoh umum dari widget semacam itu. ScrollViewer memasok Scroller dengan dua widget tersebut. Misalnya, pengembang dapat membuat implementasi IScrollController kustom yang bergantung pada Composition.Visual untuk input independen thread UI.

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

Batasan Downlevel ScrollViewer / Scroller

Kerangka kerja harus memiliki semua kait yang diperlukan untuk membangun kontrol pengguliran khusus pada Pembaruan Windows 10 April 2018. Saat menargetkan rilis sebelumnya mungkin ada batasan:
| Rilis | Batasan | Alasan |
|:-:|:--|:-:|
| Windows 10 Fall Creators Update (Build 16299) dan versi sebelumnya | Elemen tidak akan secara otomatis ditampilkan setelah menerima fokus. | Acara BringIntoViewRequested UIElement tidak tersedia |
| | Kontrol tidak dapat berpartisipasi dalam acara EffectiveViewportChanged. Persegi fokus yang dirender sistem tidak akan terpotong ke batas area pandang. | RegisterAsScrollPort UIElement tidak tersedia |

API yang Diusulkan

ScrollViewer

```C#
kelas publik Microsoft.UI.Xaml.Controls.ScrollViewer : Control
{
ScrollViewer();

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

/*

  • Properti yang berpusat pada tata letak
    */
    // Nilai Default: null
    Konten UIElement { dapatkan; mengatur; };
// 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; };

/*

  • Properti yang berpusat pada Interaksi Pengguna
    */
    // Nilai Default: Diaktifkan
    Microsoft.UI.Xaml.Controls.ScrollMode HorizontalScrollMode { dapatkan; mengatur; };
// 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; };

/*

  • Metode
    */
    // Menggulir secara asinkron ke offset yang ditentukan. Memungkinkan animasi,
    // menghormati titik jepret. Mengembalikan struct ScrollInfo.
    Microsoft.UI.Xaml.Controls.ScrollInfo ScrollTo(
    offset horisontal ganda,
    ganda vertikalOffset);
// 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);

/*

  • Diteruskan ke implementasi ISScrollAnchorProvider Scroller dalam
    */
    void RegisterAnchorCandidate (elemen UIElement);
    void UnregisterAnchorCandidate(elemen UIElement);

/*

  • Acara
    */
    // Dibesarkan setiap kali ada HorizontalOffset, VerticalOffset dan ZoomFactor
    // properti ketergantungan diubah.
    event TypedEventHandlerTampilanBerubah;
// 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;

/*

  • Properti Ketergantungan
    */
    static DependencyProperty ContentProperty { dapatkan; };
    static DependencyProperty ContentOrientationProperty { dapatkan; };
    static DependencyProperty ComputedHorizontalScrollBarVisibilityProperty { dapatkan; };
    static DependencyProperty ComputedVerticalScrollBarVisibilityProperty { dapatkan; };
    static DependencyProperty HorizontalScrollBarVisibilityProperty { dapatkan; };
    static DependencyProperty VerticalScrollBarVisibilityProperty { dapatkan; };
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; };

}
```

Pertanyaan-pertanyaan terbuka

  • Apakah memiliki properti ContentOrientation (atau satu dengan nama berbeda) yang memengaruhi bagaimana batasan tata letak diterapkan pada konten membuat segalanya lebih rumit atau lebih mudah?
  • Haruskah API terkait pembesaran dipisahkan menjadi kontrol turunan (misalnya ZoomViewer) sehingga ScrollViewer benar-benar tentang pengguliran?
Epic area-Scrolling feature proposal proposal-NewControl team-Controls

Komentar yang paling membantu

Betul sekali. Kami memiliki 3 situasi dalam pikiran:

  1. Saya tidak peduli apa posisi saya saat ini. Saya ingin menggulir/memperbesar KE tujuan tertentu.
  2. Saya peduli apa posisi saya saat ini dan saya ingin menggulir/memperbesar BY jumlah tertentu relatif terhadap posisi itu.
  3. Saya tidak peduli apa tujuan akhirnya. Saya hanya ingin menggulir/memperbesar DARI posisi saya saat ini.

Skenario untuk yang terakhir mungkin seperti pengalaman klik roda mouse untuk menggeser. Bergantung pada posisi kursor relatif terhadap saat diklik, beberapa inersia disisipkan gulir dari posisi saat ini (apa pun itu).

Semua 61 komentar

Dalam pikiran saya, kebutuhan untuk memiliki konten yang dapat di-scroll dan konten yang dapat di-zoom sangat berbeda. Saya mengerti bahwa ketika konten diperbesar, seringkali juga perlu digulir, tetapi saya ingin tahu apakah ada pertimbangan untuk membuat kontrol terpisah ini? Mungkin dengan kontrol yang dapat diperbesar memanjang dari yang bergulir.
Kekhawatiran saya adalah: 1) ScrollViewer dibuat terlalu rumit dengan menambahkan fungsi terkait zoom yang tidak akan dibutuhkan oleh kebanyakan orang; 2) tidak jelas bagi seseorang yang mencari kontrol untuk memperbesar konten yang didukung ScrollViewer ini.


Selain itu, dalam proposal, saya ingin melihat kemampuan untuk menggulir ke elemen tertentu dalam penampil gulir. Secara teori, ini bisa dilakukan oleh pengembang dengan mengukur semua item sebelumnya dan kemudian menggulir ke offset yang sesuai, tetapi ini bisa sulit dilakukan dengan daftar virtual dan (menurut saya) skenario yang cukup umum bahwa banyak aplikasi ( dan pengembang) akan mendapat manfaat dari built-in ini.
Pertimbangkan di mana item ditambahkan ke "daftar" dan pengembang ingin memastikan item tersebut terlihat. Atau pertimbangkan halaman dengan tampilan master/detail di mana halaman dibuka pada item detail jauh di bawah daftar, tetapi pengembang ingin memastikan item yang dipilih dalam daftar master ditampilkan, sehingga menyediakan konteks untuk apa yang ditampilkan di tampilan detail.

Demikian pula, akan berguna juga untuk memastikan bahwa item tetap berada di area yang terlihat sementara item lain di dalam area yang dapat digulir dihapus dari (atau ditambahkan ke) pohon visual. Saya tidak yakin apa cara terbaik untuk melakukan ini, tetapi sangat buruk ketika item yang dipilih dalam area yang dapat digulir bergerak karena tindakan latar belakang (atau utas di luar UI) menghapus atau menambahkan item lain ke area yang dapat digulir.
Memindahkan item saat Anda mengklik/mengetuknya mengarah ke pengalaman kegunaan yang mengerikan. Memindahkan item yang difokuskan/dipilih dari area yang terlihat juga dapat menyebabkan masalah bagi alat aksesibilitas dan pembaca layar.
Saya sadar ada potensi masalah dengan mencoba menyimpan item di posisi yang sama sementara orang-orang di sekitarnya bergerak (terutama jika item itu dihapus dari tempat lain) tetapi tidak melakukan apa pun sepertinya tidak cukup baik.

Terima kasih @mrlacey. Saya dapat melihat bagaimana fungsi pembesaran akan kurang dapat ditemukan di ScrollViewer yang ada serta proposal ini. Saya telah menambahkan ini sebagai pertanyaan terbuka untuk diskusi karena ini akan menjadi titik awal lain dari UWP ScrollViewer yang ada (mungkin menjadi lebih baik?).

Virtualisasi membuat segalanya menjadi rumit karena pertama-tama elemen tertentu mungkin perlu dibuat dan dijalankan melalui sistem tata letak untuk memiliki posisi yang kemudian dapat Anda gulir. Inilah sebabnya mengapa di masa lalu kontrol tertentu (yaitu ListView) memiliki metode ScrollIntoView sendiri yang menangani hal di atas untuk memudahkannya. Apakah itu jenis metode yang Anda bayangkan? Sebagai alternatif, setiap UIElement memiliki metode StartBringIntoView yang dapat digunakan untuk menggulir ke item dengan sangat mudah dan memiliki sejumlah opsi untuk memberikan kontrol terperinci atas tempat di area pandang yang terlihat saat ditampilkan. Pendekatan StartBringIntoView bekerja bahkan dalam skenario dengan permukaan gulir bersarang karena menghasilkan permintaan yang menggelembung untuk setiap kontrol gulir untuk merespons. Ini pada dasarnya apa yang terjadi ketika sebuah item menerima fokus keyboard/GamePad/Narrator. Tentu saja, Anda harus terlebih dahulu memiliki UIElement yang mungkin tidak Anda miliki dalam skenario virtualisasi tanpa cara untuk secara eksplisit memicu elemen untuk direalisasikan. Apakah berguna untuk memiliki cara untuk secara eksplisit memicu realisasi suatu elemen? Antara lain, Anda kemudian dapat menggunakannya untuk memicu StartBringIntoView.

Re: mempertahankan posisi suatu item saat konten lain ditambahkan/dihapus atau diubah ukurannya... Sangat setuju bahwa tidak melakukan apa pun tidak cukup baik. Inilah tepatnya mengapa fitur penahan gulir ada. :) Ini adalah kemampuan yang sedikit diketahui yang di masa lalu telah terpasang di Panel virtualisasi untuk ListView/GridView. Dalam rilis terbaru kami telah melakukan upaya eksplisit untuk memisahkan hal-hal seperti ini dari hanya tersedia di ListView.

Jika ide dari ScrollViewer yang diperluas ingin dieksplorasi, mungkin tim Desain Lancar dapat memberi tahu Anda tentang penanganan paralaks dan item dengan nilai kedalaman z yang ditetapkan secara default.

Saat XAML berpindah ke representasi 3D untuk aplikasi MR, dan saat Kedalaman dan Bayangan menjadi XAML 2D - bagaimana pengguliran akan memindahkan item dengan nilai kedalaman yang berbeda, bagaimana bayangan dapat dirender di atas atau di belakang indikator gulir, dan masalah lain yang mungkin muncul dalam eksperimen 3D tim XAML - dapat dibangun ke dalam apa yang bisa menjadi default baru, karena Perpustakaan UI Windows perlahan menjadi default baru.

Dalam pikiran saya, kebutuhan untuk memiliki konten yang dapat di-scroll dan konten yang dapat di-zoom sangat berbeda.

Kecuali di browser web, aplikasi desain grafis, aplikasi kantor, penampil PDF..... apa pun yang menampilkan dokumen konten.

Setuju dengan @mrlacey bahwa membawa elemen tertentu ke tampilan itu penting serta menentukan di mana dalam tampilan itu ditampilkan (atas, tengah, bawah, dll ...). Juga perlu ada cara untuk mendeteksi apakah elemen sepenuhnya terlihat atau terpotong. Dengan cara ini saya tidak perlu menggulir tampilan untuk menampilkan elemen jika saya tahu elemen tersebut sudah seluruhnya atau bahkan sebagian terlihat.

Terima kasih semuanya! Kami mengumpulkan beberapa telemetri mengenai properti mana yang cenderung disetel oleh aplikasi dalam markupnya dan ZoomMode muncul tepat setelah *ScrollMode dan *ScrollBarVisibility. Sebagian besar waktu aplikasi tidak mengubah properti apa pun. Apa yang saya amati ketika properti ScrollMode dan ScrollBarVisibility sedang disetel adalah bahwa sering kali untuk mengaktifkan pengguliran horizontal pada konten. Pengenalan properti ContentOrientation dimaksudkan untuk membuatnya lebih mudah. Setelah pengguliran horizontal, skenario paling umum berikutnya adalah pembesaran.

Daripada memperkenalkan kontrol (turunan) terpisah untuk mengatasi kemampuan zoom yang dapat ditemukan, saya yakin dokumentasi/sampel yang tepat bisa lebih efektif.

Bagaimana dengan menambahkan Perilaku atau Konteks Enum?

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

ScrollViewer.ScrollBehaviour = ScrollBehaviour.Zoom; sangat membingungkan. Saya pikir ZoomMode harus tetap seperti itu.

ScrollViewer.ScrollBehaviour = ScrollBehaviour.Zoom; sangat membingungkan. Saya pikir ZoomMode harus tetap seperti itu.

Saya mungkin harus mengawali saran sebagai menangani komentar yang berpikir harus ada kontrol turunan untuk konten Zooming, daripada Menggulir

Bagi saya sebenarnya masuk akal untuk memiliki fungsi zoom bawaan dengan ScrollViewer , terutama pada perangkat sentuh. Saat ini tidak ada cara mudah untuk melakukan panning/zooming/rotating gaya bebas pada gambar/kontrol di UWP, dan banyak pertanyaan terkait telah diajukan di StackOverflow dan GitHub (mis. Add draggable content control ).

@micahl , saya berasumsi dengan memperbesar dan

Mendukung gerakan rotasi

skenario ini akan didukung secara native di masa mendatang?

Bagi saya sebenarnya masuk akal untuk memiliki fungsi zoom bawaan dengan ScrollViewer , terutama pada perangkat sentuh. Saat ini tidak ada cara mudah untuk melakukan panning/zooming/rotating gaya bebas pada gambar/kontrol di UWP, dan banyak pertanyaan terkait telah diajukan di StackOverflow dan GitHub (mis. Add draggable content control ).

Jika ada kebutuhan untuk memiliki kontrol lebih pada Zooming dan Scrolling...

ScrollViewer.ScrollBehaviour = ScrollBehaviour.ZoomAndScroll;

Namun pada perangkat sentuh, terasa wajar jika jari dijepit dan digeser. Zoom tanpa sentuhan akan membutuhkan tombol [ + ] dan [ ] untuk muncul. Atau mungkin jika itu hanya Zoom, maka seret ibu jari scrollbar akan memperbesar dan memperkecil.

Jika Anda melihat UI Microsoft Word, ada kontrol Zoom di Status Bar. Dan scrollbar untuk area dokumen.

Apakah zoom mouse mendukung sesuatu yang harus dibangun ke dalam kontrol ScrollViewer baru? Jadi ketika ZoomMode aktif, atau Properti Perilaku memungkinkan Zoom - lalu tombol Plus dan Minus muncul?

@JustinXinLiu Mendukung gerakan rotasi kemungkinan akan membutuhkan dukungan dari InteractionTracker (@likuba).

@mdtauk ScrollViewer baru akan mendukung zoom roda mouse melalui Ctrl + roda mouse mirip dengan ScrollViewer yang ada. Tidak jelas bagi saya apakah kontrol harus memiliki tombol plus/minus default saat zoom diaktifkan. Kesan saya saat ini adalah bahwa jenis aplikasi yang biasanya mengaktifkan pembesaran (misalnya aplikasi dokumen konten) memilih untuk memasukkan tombol-tombol itu ke dalam pengalaman aplikasi mereka dengan berbagai cara. Misalnya, a - / + di bilah status yang dipisahkan oleh penggeser (mis. Office) atau hanya sebagai -/+ sederhana yang muncul secara vertikal di bawah perintah lain (mis. Peta).

@micahl Saya tidak mengerti mengapa ScrollFrom disebut seperti itu. Bukankah itu seperti ScrollBy tetapi dengan parameter kecepatan?

@adrientetar apakah Anda bertanya mengapa tidak memiliki ScrollBy yang berlebihan dengan set parameter yang berbeda alih-alih menamainya ScrollFrom?

Ya saya kira tapi saya membayangkan konsep di balik ScrollFrom adalah bergerak ke arah dengan kecepatan tertentu? sebagai lawan ScrollBy yang hanya pindah ke titik tertentu.

Betul sekali. Kami memiliki 3 situasi dalam pikiran:

  1. Saya tidak peduli apa posisi saya saat ini. Saya ingin menggulir/memperbesar KE tujuan tertentu.
  2. Saya peduli apa posisi saya saat ini dan saya ingin menggulir/memperbesar BY jumlah tertentu relatif terhadap posisi itu.
  3. Saya tidak peduli apa tujuan akhirnya. Saya hanya ingin menggulir/memperbesar DARI posisi saya saat ini.

Skenario untuk yang terakhir mungkin seperti pengalaman klik roda mouse untuk menggeser. Bergantung pada posisi kursor relatif terhadap saat diklik, beberapa inersia disisipkan gulir dari posisi saat ini (apa pun itu).

Terima kasih, itu menjernihkan segalanya. Saya pikir saya lebih ingin menggunakan ScrollBy untuk pengalaman klik roda mouse saya sendiri, tetapi saya dapat melihat ScrollFrom berguna dalam kasus tertentu.

Dalam kontrol ScrollViewer saat ini, dimungkinkan untuk mengikat ke properti ViewportWidth dan ViewportHeight, tetapi hal ini tampaknya saat ini tidak mungkin dilakukan dalam kontrol ScrollViewer baru. Apakah ini akan ditambahkan?

@lhak , untuk apa Anda mengikat nilai-nilai itu? Menambahkannya tidak akan menjadi perubahan besar. Bergantung pada konteks skenario Anda, mungkin ada pendekatan berbeda yang kami sarankan daripada mengikat. Sementara kami ingin peka terhadap perbedaan yang membuat sulit untuk berpindah dari satu ke yang lain, kami juga ingin mempromosikan alternatif jika mereka lebih baik.

@micahl Saya cukup yakin saya telah menggunakan nilai-nilai itu di masa lalu juga untuk beberapa perhitungan. Tidak yakin apakah saya sudah terikat dengan mereka.

@michael-hawker menjadi jelas, properti akan tersedia di ScrollViewer. Namun, dalam API yang diusulkan mereka diekspos sebagai properti biasa daripada sebagai DependencyProperties. Nilai yang sama ini akan tersedia sebagai bagian dari properti ExpressionAnimationSources untuk situasi di mana seseorang membuat animasi berbasis input berdasarkan Komposisi.

Saat ini saya menggunakan beberapa kode yang mirip dengan yang berikut di aplikasi saya:

<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>

Ini memungkinkan untuk menggulir/memperbesar elemen xaml bagian dalam (yang memiliki ukuran tetap) sambil menjaga rasio aspeknya. Perilakunya mirip dengan aplikasi foto yang menampilkan gambar, dengan pengecualian bahwa elemen xaml tidak pernah lebih kecil dari area pandang scrollviewer.

@lhak , skenario yang bagus! Berpikir keras tentang bagaimana skenario ini dapat diakomodasi dalam proposal saat ini... Saya pikir kita bisa menambahkan opsi lain untuk properti ContentOrientation. Opsi saat ini dalam proposal:

  • Tidak ada = Tidak ada orientasi yang disukai. Berikan konten ukuran yang tersedia tak terbatas di kedua arah.
  • Horizontal = Berikan konten ukuran tak terbatas yang tersedia hanya secara horizontal dan batasi ketinggian ke viewport selama tata letak.
  • Vertikal = Transpose horizontal

Opsi keempat adalah membatasi tinggi dan lebar selama tata letak ke ukuran area pandang. Untuk saat ini saya akan menyebutnya sebagai orientasi "Viewport", meskipun saya memiliki reaksi yang beragam tentang penamaan seperti itu.
Setidaknya dalam kasus gambar (lebih umum?) Saya percaya itu akan membuat Viewbox dan binding tidak diperlukan karena "hal yang benar" seharusnya terjadi sebagai bagian dari proses tata letak.

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

Untuk konten yang lebih kompleks, Anda dapat membungkusnya dalam Viewbox dan tetap melewati binding.

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

@micahl Punya pertanyaan lain: Saya ingin mengubah penanganan roda mouse Scroller untuk membuat zoom lebih cepat (kenaikan lebih besar) dan menghapus animasi penghalusan. Sepertinya tidak ada API untuk mengubah zoom roda, apakah saya perlu menangani acara roda mouse secara manual?

Anda mungkin harus menangani roda mouse secara manual, tetapi akan sangat disayangkan jika ternyata Anda harus mengimplementasikan kembali apa yang dilakukan kontrol. Kami pikir mungkin ada cara untuk mencapai apa yang Anda cari. Intinya adalah mengatur ZoomInertiaDecayRate ke beberapa nilai mendekati 1,0 dan kemudian menentukan titik jepret zoom berulang. Ini adalah sesuatu untuk dicoba setelah kami menambahkan properti ZoomInertiaDecayRate dan memperbaiki beberapa masalah yang terkait dengan titik jepret wajib.

Jika itu tidak berhasil, maka Anda dapat kembali mencoba menanganinya sendiri dengan mengatur IgnoredInputKind="Mousewheel" dan kemudian mensubklasifikasikan Scroller untuk menimpa OnPointerWheelChanged, atau menambahkan event handler untuk acara PointerWheelChanged di Scroller.

@micahl Terima kasih! Saya tidak yakin dengan skenario apa Anda mengkalibrasi perilaku roda mouse, secara pribadi saya suka cara itu misalnya di Adobe XD: tampaknya ada sedikit animasi yang dipercepat tetapi tajam dan memiliki peningkatan zoom yang cukup besar. Animasi zoom roda mouse scroller terasa agak lamban dan memiliki peningkatan zoom yang sangat kecil.

@adrientetar , umpan balik yang bagus. Kita bisa melihat ke dalam menyesuaikannya.

Segala jenis variabel yang mengontrol kenaikan dan nilai - dapat dibuat menjadi properti yang dapat ditimpa

Benar. Satu tantangan bagi kami di sini adalah bahwa pada Win10 versi 1809 dan yang lebih baru, kontrol menyerahkan input roda mouse ke InteractionTracker yang mendasarinya untuk membiarkannya diproses dari UI-thread untuk gerakan yang lebih halus. Properti yang dapat ditimpa itu harus terlebih dahulu diekspos di tingkat yang lebih rendah. Untuk versi Win10 sebelum 1809 kami menambahkan logika agar proses kontrol input roda mouse pada utas UI.

Kami dapat mempertimbangkan untuk memiliki beberapa perilaku di mana kami mengekspos beberapa properti yang dapat ditimpa dan jika ada yang diatur secara eksplisit maka kami kembali memiliki roda mouse proses kontrol di utas UI. Jika/Ketika properti itu ada di tingkat yang lebih rendah maka kita dapat beralih untuk mengandalkannya dan mengembalikannya ke compositor. Menggulir mungkin tidak akan semulus roda mouse. Mungkin tidak apa-apa di sini?

Jadi perilaku pembesaran saat ini dimasukkan ke dalam InteractionTracker tanpa ada cara untuk mengesampingkannya? Dan saya kira sekarang tidak ada cara untuk mengubahnya karena akan merusak kompatibilitas ke belakang cc @likuba

Saya pikir ada beberapa opsi di InteractionTracker yang bisa membantu di sini 😊. Secara khusus, kami membangun fitur seperti PointerWheelConfig dan DeltaScaleModifier untuk mengaktifkan jenis penyesuaian ini. Kami akan menyinkronkan dan melihat apakah menggunakan ini dalam kontrol dapat memungkinkan sesuatu terjadi di sini tanpa masalah/risiko yang Anda sebutkan di atas.

@ micahl Saya memiliki situasi yang menarik pada proyek yang sedang saya kerjakan dan saya harus menulis scrollviewer saya sendiri untuk PoC - tetapi saya ingin tahu apakah Anda punya rencana (atau apakah kontrol ini sudah mendukung ini) untuk skenario berikut:
Katakanlah Anda memiliki kanvas raksasa, 10000x5000 sehingga untuk bergerak di sekitarnya, Anda merangkumnya dalam scrollviewer.
Sekarang di kanvas Anda memiliki 2 InkCanvases (atau lebih) dan Anda ingin menulis di keduanya (atau lebih), dengan jari yang berbeda atau dengan 1 jari dan 1 penunjuk mouse. Bagaimana Anda mencapai itu (atau bahkan mungkin) dengan kontrol ini? :)
Apa yang saya lihat perilaku defaultnya adalah segera setelah Anda menyentuh apa pun saat menggambar di satu InkCanvas, InkCanvas tertentu akan mengaktifkan "PointerLost" dan hanya itu - tidak ada lagi yang bisa dilakukan.
Jelas scrollviewer saya jauh jauh dari sempurna karena saya menulisnya sendiri - jadi saya ingin melihat apakah ini bisa dilakukan dengan kontrol ini?

Terima kasih!

Hai @stefangavrilasengage , skenario yang menarik. :) Dari PoC Anda, apa perilaku yang diharapkan ketika satu jari turun di InkCanvas dan kemudian mulai bergerak? Apakah itu menggambar atau menggeser?

Hai @micahl - terima kasih telah membalas! Saya berasumsi sekarang Anda sudah menebaknya seperti aplikasi papan tulis digital.
Sekarang saya akan menyajikan apa yang terjadi saat ini:

  • ScrollViewer (default): satu jari menggambar pada InkCanvas baik-baik saja. Jari ke-2 membuat InkCanvas ke-1 kehilangan input.
  • ScrollViewerEx (kontrol khusus): gunakan sebanyak mungkin jari dan sebanyak mungkin InkCanvases untuk menggambar dan berhasil.

Apakah ini membantu? :)
Terima kasih !

@stefangavrilasengage Saya bertanya apa yang membedakan antara apakah gerakan satu sentuhan menggeser (perilaku default untuk ScrollViewer) atau menggambar tinta. Ada konflik yang melekat di sana. Bagaimana Anda mengatasinya? Perlu dua jari untuk menggulir seperti peta? Gunakan tombol edit untuk masuk/keluar dari mode edit? Dll...

@micahl Permintaan maaf saya - lupa menyebutkan bagaimana saya menyelesaikan konflik.
Objek yang kita miliki di kanvas memiliki tinta di dalam wadah Win2D. Hanya jika Anda memasuki mode edit untuk setiap objek, InkCanvas akan ditampilkan di bagian atas untuk diedit (dengan pengeringan khusus).
Oleh karena itu dalam situasi saya (tidak yakin apakah ini berlaku untuk orang lain), jika Anda memiliki "drawable" aktif InkCanvas, maka tidak ada yang naik ke ScrollViewer.
Saya ingin tahu tentang kasus penggunaan di mana menurut Anda ini tidak berlaku, jika ada?

Terima kasih !

Sulit dipercaya ini adalah pertama kalinya @micahl dan saya terlibat dalam masalah github!

Sulit dipercaya ini adalah pertama kalinya @micahl dan saya terlibat dalam masalah github!

Maaf tentang itu! Diedit!

@micahgodbolt mungkin bukan yang terakhir. ;)
@stefangavrilasengage terima kasih! Itu menjawab pertanyaan saya. Saya perhatikan bahwa menukar ScrollViewer dengan sesuatu yang lain seperti Border sebagai induk dari Canvas yang berisi beberapa kontrol InkCanvas tidak memiliki masalah yang sama. Jadi, saya telah menghubungi beberapa orang secara internal untuk memahami apa yang mungkin menyebabkan fungsionalitas multi-input/multi-InkCanvas rusak ketika itu terjadi di dalam ScrollViewer.

@stefangavrilasengage , mencari tahu mengapa itu tidak berhasil akan membutuhkan waktu/penyelidikan. Mari kita lacak itu secara terpisah dari proposal ini. Apakah Anda akan membuka masalah untuk itu?

@micahl Saya memiliki masalah dengan Scroller di mana menggulir dan memperbesar konten saya di OnControlLoaded menempatkan saya di posisi yang salah. Jika saya hanya menggulir, saya berakhir di posisi yang tepat, tetapi jika saya memperbesar tepat setelah menggulir saya berada dalam posisi yang benar-benar tidak aktif, meskipun saya menentukan centerPoint=null jadi defaultnya adalah viewport center (dari melihat kode karena ada belum ada dokumentasi afaict). Dengan kode ini .

Terima kasih telah mencoba berbagai hal, @adrientetar! Mari kita jaga agar thread ini tetap fokus pada proposal. Bisakah Anda membuka edisi terpisah untuk apa yang Anda lihat? Tergantung di mana kita membahas diskusi itu, kita mungkin ingin kembali ke utas ini untuk membahas apakah itu memerlukan perubahan pada proposal.

@micahl Mengapa acara ExtentChanged/StateChanged/ViewChanged memiliki objek sebagai argumennya dan bukan misalnya StateChangedEventArgs dengan anggota Negara? Mengingat bahwa InteractionTracker berjalan pada utas yang berbeda, bukankah pola penyampaian pesan (peristiwa dengan argumen) lebih disukai daripada menanyakan properti kontrol di pengendali peristiwa?

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

Bukan masalah besar, tetapi bagian pertama dari repo ini menunjukkan bagaimana menerapkan pembesaran bahkan ketika Bilah Gulir Horizontal/Vertikal dikunci (Dinonaktifkan),

Dengan kata yang lebih sederhana:
Memungkinkan untuk menggeser konten yang diperbesar sambil tetap memaksa menyesuaikan ke
Viewport Vertikal/Horizontal yang efektif.

Pada saat memposting ini, wajib untuk mengaktifkan properti HorizontalScrollbarVisibility di ScrollViewer untuk benar-benar mendapatkan operasi Zoom yang fungsional, dan meskipun mungkin ada cara yang lebih baik untuk mengatasi ini, saya pikir solusi scrollviewer ganda yang saya hapus bersama mungkin cukup cukup.

@micahl Saya melihat bahwa Scroller tidak mengirim acara StateChanged saat melakukan zoom non-animasi, apakah itu karena desain?
Saya mengatur penskalaan CanvasVirtualControl saya ketika Scroller menjadi Idle, seperti yang Anda sarankan di https://github.com/microsoft/microsoft-ui-xaml/issues/541#issuecomment -488749469, sehingga kontrol tidak berakhir dengan rasterisasi terlalu besar bagian kanvas relatif terhadap faktor zoom. Tetapi dengan zoom non-animasi, saya perlu melakukan itu pada saat saya memanggil metode ZoomTo, meskipun perubahan zoom belum terwujud (afaic).

@adrientetar , ada beberapa overhead untuk membuat argumen acara untuk bolak-balik antara kerangka kerja dan aplikasi. Karena acara arg hanya akan memberikan salinan properti yang diekspos oleh pengirim, desain kami saat ini adalah tidak memiliki acara arg.

Ya, desain saat ini adalah bahwa dalam zoom non-animasi Anda memanggil secara terprogram StateChanged tidak menyala. Acara ZoomCompleted dan ScrollCompleted akan dimunculkan sebagai respons terhadap perubahan terprogram. IIRC mereka tidak dipicu oleh perubahan dari pengguna. Anda bisa menggunakan salah satunya, mungkin dalam kombinasi dengan StateChanged. Sebagai fyi, acara ViewChanged dimunculkan kapan saja tampilan berubah (pengguna atau terprogram) yang menjadikannya jalur kode yang sangat sensitif dan bukan yang ingin Anda gunakan.

Kami masih mendengarkan umpan balik, jadi jika ada hal-hal yang tampak tumpul, beri tahu kami.

Ya, desain saat ini adalah bahwa dalam zoom non-animasi Anda memanggil secara terprogram StateChanged tidak menyala.

Ah oke, aku mengerti sekarang. Mungkin acara dapat selalu menyala dan berisi parameter Origin, seperti SetFocus, tetapi mungkin ada beberapa biaya tambahan untuk melakukan itu.

Acara ZoomCompleted dan ScrollCompleted akan dimunculkan sebagai respons terhadap perubahan terprogram. IIRC mereka tidak dipicu oleh perubahan dari pengguna.

Oke, jadi untuk kasus penggunaan saya, saya harus menangani ZoomCompleted dan StateChanged iff State == Idle, tergantung apakah perubahannya terprogram atau tidak. Bukankah itu aneh? Maksud saya, memiliki acara yang berbeda dengan nama yang berbeda untuk hal yang sama hanya memicu cara yang berbeda

@RBrid dan saya mengobrol singkat tentang memperkenalkan status baru "Transisi" dan membuat beberapa penggantian nama kecil. Beri tahu kami jika ini lebih masuk akal untuk kasus penggunaan Anda.

Gagasan yang dibahas adalah bahwa ketika perubahan pada posisi gulir/perbesar akan dilayani (apakah yang dimulai oleh pengguna atau terprogram), kami akan meningkatkan acara StateChanged dan melaporkan status saat ini sebagai Transisi. Berikut adalah urutan tampilan untuk gulungan terprogram (animasi dan bukan animasi):

// permintaan terprogram, animasi
myScrollInfo = ScrollTo(100, animate=true);
// beberapa tanda centang
StateChanged dinaikkan (Scroller.State == Transisi)
// beberapa tanda centang
StateChanged dinaikkan (Scroller.State == Animating)
// banyak tanda centang
StateChanged dinaikkan (Scroller.State == Idling)

// permintaan terprogram, tanpa animasi
myScrollInfo = ScrollTo(100, animate=false);
// beberapa tanda centang
StateChanged dinaikkan (Scroller.State == Transisi)
// beberapa tanda centang
StateChanged dinaikkan (Scroller.State == Idling)

Kami mungkin ingin mengganti nama InteractionState enum menjadi sesuatu seperti ScrollState karena ini akan mewakili lebih dari sekadar interaksi.

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

@micahl Ya, itu sangat mirip dengan yang saya harapkan! Seseorang yang hanya ingin menangani perubahan animasi dapat mencegat status Animasi. Untuk nama, saya akan menjaga Idle not Idling ("Scroller is idle"/"Scroller is animating"), Transitioning → Stirring? (Transisi sangat membingungkan, saya lebih suka kami menyampaikan bahwa itu di awal gerakan sehingga pengadukan imo mungkin bekerja lebih baik ), Inersia bisa Melayang tapi saya kira Tinjauan API akan berbunyi juga.

Mengaduk awalnya membuat saya berpikir untuk memadukan. :) Tinjauan API akan ingin mempertimbangkan ketika kami menyelesaikan nama dan cenderung mencari preseden. Itu selalu baik untuk memiliki beberapa pilihan. Alternatif lain bisa Unknown atau Pending. Ada preseden dalam API yang ada untuk keduanya bersama dengan Idle yang berarti kami mungkin tidak akan melakukan Idling.

Keren keren. Sgtm tertunda, imo Unknown bahkan lebih membingungkan daripada Transisi.

@micahl -- Persyaratan Fungsional nomor 3 termasuk subpoin ini:

berpartisipasi dalam perubahan viewport yang efektif (Harus)

Subpoin itu merujuk pada acara yang sudah ada sebelumnya FrameworkElement.EffectiveViewportChanged . Apakah subpoin itu cukup untuk mengatakan (secara tidak langsung) bahwa pemuatan sebagian konten asinkron sesuai permintaan juga merupakan persyaratan/prioritas? Maksud saya, misalnya, setara dengan bagaimana ScrollViewer beroperasi ketika MS Edge menampilkan halaman yang diperbesar dari dokumen PDF (atau SVG atau dokumen kompleks lainnya). Ketika zoom 900% (misalnya), itu tidak melakukan pra-render seluruh halaman PDF pada ukuran 900%, karena 2 alasan berikut:

  • Tugas rendering ini (pada persentase zoom tinggi) membutuhkan sekitar 3 .. 20 detik, tergantung pada kompleksitas dokumen (jumlah elemen vektor, efek, dll), ukuran dokumen, dan persentase zoom. Penundaan ini terlalu banyak untuk diterima oleh pengguna akhir.
  • Gambar yang dirender (bitmap) dari seluruh halaman PDF dapat menghabiskan ratusan megabyte RAM saat persentase zoom tinggi, karena setara dengan rendering pada DPI yang sangat tinggi.

MS Edge merender bagian dari halaman PDF yang diperbesar sesuai permintaan, artinya ketika pengguna menggulir bagian-bagian itu ke tampilan. Teknik ini menghindari penundaan yang lama sebelum halaman ditampilkan. Saya menyarankan agar Persyaratan Fungsional secara eksplisit menyebutkan skenario ini, tetapi juga dengan dukungan tidak langsung untuk async Task . Ketika bagian yang tidak dirender (atau tidak segera tersedia) di-scroll ke tampilan, ScrollViewer dapat mengisi ruang itu untuk sementara dengan Brush dapat dikonfigurasi dan kemudian memicu suatu peristiwa, dan pengendali peristiwa dapat memulai async Task untuk membuat (atau mengambil/memuat) bagian tersebut. Kemudian, ketika Task selesai, bagian yang dirender/diambil/dimuat ditampilkan di ScrollViewer, menutupi ruang yang sementara diisi dengan Brush .

Masalah ini bukan hanya tentang tingginya biaya rendering pada zoom tinggi. Ini juga berlaku untuk konten yang diambil sesuai permintaan. Misalnya, bayangkan peta atau citra satelit ditampilkan di ScrollViewer. Bagian dari peta hanya diunduh dari server saat pengguna menggulirnya ke tampilan.

Haruskah API terkait pembesaran dipisahkan menjadi kontrol turunan (misalnya ZoomViewer) sehingga ScrollViewer benar-benar tentang pengguliran?

Meskipun saya sangat menghargai penambahan ScrollViewer.ZoomFactor , saya terkejut melihat bahwa itu ditambahkan langsung ke ScrollViewer. Saya berasumsi bahwa akan lebih sederhana dan lebih dapat diandalkan untuk menempatkan zoom di kelas yang terpisah (tidak harus kelas turunan). Setidaknya 3 cara yang mungkin:

  1. Kelas bernama mungkin ZoomViewer yang TIDAK mewarisi ScrollViewer , tetapi menggunakan instance ScrollViewer sebagai elemen anak (dalam ControlTemplate ).
  2. Kelas bernama mungkin ZoomableScrollViewer yang mewarisi ScrollViewer .
  3. Langsung mendukung zoom dalam ScrollViewer , jika tidak terlalu rumit atau berantakan.

17 Menyediakan UX default untuk mendukung klik dan gulir tengah mouse. (Sebaiknya)
18 Mendukung mode untuk mengklik dan menggeser melalui mouse (misalnya memindahkan konten di dalam penampil PDF). (Sebaiknya)

Saya sarankan mempertimbangkan apakah akan menghapus dukungan untuk 17, karena 18 bekerja jauh lebih baik daripada 17, dan hampir tidak ada yang menggunakan 17 dalam praktiknya. Memang saya mungkin berpikir bahwa 17 berarti sesuatu yang lain dari maksud Anda (deskripsi 17 hanya satu kalimat dan saya tidak 100% yakin bahwa itu berarti apa yang saya pikir artinya). Bukankah benar untuk mengatakan bahwa 18 sangat user-friendly dan mudah digunakan, sedangkan 17 adalah hal yang canggung yang semua orang berjuang untuk menggunakan dan menghindari penggunaan?
(Masalah ini berubah jika 17 diperlukan untuk alasan aksesibilitas, tetapi sejauh ini saya belum pernah mendengar ada yang mengatakan bahwa 17 adalah masalah aksesibilitas.)

4 Mampu melakukan animasi berbasis input

Nomor 4 adalah masalah terkait aksesibilitas. Saya ingin meminta agar ScrollViewer (dan semua Kontrol lainnya di WinUI) menghormati pengaturan aksesibilitas:

Windows 10 -> Mulai -> Pengaturan -> Kemudahan Akses -> Tampilan -> Tampilkan animasi di Windows (Aktif atau Mati).

Sayangnya, selama bertahun-tahun, saya telah melihat banyak contoh di mana aplikasi Microsoft mengabaikan pengaturan aksesibilitas Windows. Animasi dimatikan tetapi aplikasi Microsoft tetap menampilkan animasi. Ini menyebabkan kesulitan nyata bagi pengguna yang mengandalkan pengaturan aksesibilitas ini. Tidak semua orang memiliki kemampuan untuk menikmati animasi tanpa mengalami efek samping negatif. Pengguna yang tidak mengalami kesulitan melihat animasi dll dapat merasa sulit untuk memahami pentingnya pengaturan aksesibilitas di Windows.

Hai @verelpode , @predavid akan mengarahkan pekerjaan di sekitar ScrollViewer baru jadi saya akan tunduk padanya.

17 Menyediakan UX default untuk mendukung klik dan gulir tengah mouse. (Sebaiknya)
18 Mendukung mode untuk mengklik dan menggeser melalui mouse (misalnya memindahkan konten di dalam penampil PDF). (Sebaiknya)

Saya sarankan mempertimbangkan apakah akan menghapus dukungan untuk 17, karena 18 bekerja jauh lebih baik daripada 17, dan hampir tidak ada yang menggunakan 17 dalam praktiknya. Memang saya mungkin berpikir bahwa 17 berarti sesuatu yang lain dari maksud Anda (deskripsi 17 hanya satu kalimat dan saya tidak 100% yakin bahwa itu berarti apa yang saya pikir artinya). Bukankah benar untuk mengatakan bahwa 18 sangat user-friendly dan mudah digunakan, sedangkan 17 adalah hal yang canggung yang semua orang berjuang untuk menggunakan dan menghindari penggunaan?
(Masalah ini berubah jika 17 diperlukan untuk alasan aksesibilitas, tetapi sejauh ini saya belum pernah mendengar ada yang mengatakan bahwa 17 adalah masalah aksesibilitas.)

@verelpode Saya pikir Anda memahami 17 dengan benar dan saya setuju bahwa 18 lebih penting dan biasanya lebih intuitif daripada 17. Tetapi mungkin ada skenario di mana "klik kiri dan seret" sudah digunakan untuk tujuan lain, seperti pemilihan, atau seret+lepas . Untuk skenario seperti itu, alangkah baiknya jika aplikasi dapat mengaktifkan pengguliran melalui klik tengah (17).

Saya pribadi menggunakan pengguliran klik tengah di browser dari waktu ke waktu, di mana klik kiri + seret menyebabkan pemilihan teks atau seret + jatuhkan gambar. Peramban UWP akan memiliki 18 dinonaktifkan dan 17 diaktifkan. Keduanya harus ikut serta melalui properti terpisah.

@lukasf

Saya pribadi menggunakan pengguliran klik tengah di browser dari waktu ke waktu, di mana klik kiri + seret menyebabkan pemilihan teks atau seret + jatuhkan gambar.

Poin bagus tentang kebutuhan untuk menghindari menyebabkan pemilihan teks dll berhenti bekerja. Apa pendapat Anda tentang solusi yang mungkin ini: Buat klik tengah memulai mode panning berbasis mouse (18) alih-alih memulai mode 17 yang canggung.

Ketika saya melihat apa yang dilakukan aplikasi lain, beberapa aplikasi memungkinkan Anda untuk memulai panning berbasis mouse dengan menahan tombol spasi sambil mengklik kiri di area konten yang dapat digulir. Solusi ini memungkinkan klik kiri untuk beroperasi secara normal di dalam area konten yang dapat digulir karena mode panning hanya dimulai melalui spasi+klik. Saya menemukan panning melalui spasi+klik sangat nyaman dan nyaman dan cepat.

Namun, solusi spasi+klik ini lebih mudah diterapkan di aplikasi yang tidak perlu menampilkan kotak teks apa pun yang dapat diedit dalam area konten yang dapat digulir. Jika kotak teks yang dapat diedit memang ada di area konten yang dapat digulir, maka akan menjadi masalah jika fitur panning membuat pengguna tidak dapat mengetik spasi di kotak teks. Oleh karena itu, seperti yang Anda katakan, fitur ini harus disertakan melalui properti. Atau, jangan gunakan bilah spasi, dan alih-alih membuat klik tengah memulai mode panning berbasis mouse (18), dan ini menghilangkan masalah pengguna yang tidak dapat mengetik spasi di kotak teks.

@verelpode
Dengan semua browser dan juga banyak aplikasi lain (Word, Adobe Reader, Outlook,...) mendukung mode 17, saya masih berpikir bahwa ini harus diterapkan. Hanya karena Anda secara pribadi merasa canggung bukan berarti itu tidak berguna bagi orang lain. Kedua mode tentu saja harus ikut serta, lalu pengembang dapat memutuskan apa yang akan digunakan dalam aplikasi mereka. Ini juga akan memungkinkan perilaku bilah spasi+klik Anda, jika masuk akal untuk suatu aplikasi: Aktifkan mode 18 di bilah spasi ke bawah, nonaktifkan lagi di bilah spasi ke atas.

@lukasf -- Oke, kedengarannya bagus. Saya pikir Anda bermaksud bahwa jika mode panning (18) tidak akan mencegah pemilihan teks atau drag+drop gambar dll, maka Anda akan berhenti menggunakan mode 17 dan beralih ke 18, tapi sekarang saya melihat preferensi Anda sebenarnya untuk kedua mode ke didukung.

Terima kasih atas tanggapan Anda @verelpode dan @lukasf , saya setuju dengan Anda bahwa pada akhirnya kami ingin tombol publik pada kontrol Scroller untuk menghidupkan/mematikan nomor 17 dan 18. Sebut saja 17=mouse-based constant-velocity-panning dan 18=penggeseran berbasis mouse.

Saya baru saja mengirimkan PR https://github.com/microsoft/microsoft-ui-xaml/pull/1472 untuk menambahkan beberapa pekerjaan investigasi yang saya lakukan. Saya ingin melihat seberapa dekat saya bisa mendukung 17 dan 18 menggunakan Scroller hari ini.

Semuanya berjalan cukup baik untuk 18=mouse-based panning, meskipun solusinya adalah 100% UI-thread-bound, tidak seperti pengalaman berbasis-sentuh atau berbasis-roda mouse. Saya menggunakan metode ScrollTo sambil mendengarkan acara PointerMoved mouse. Pada akhirnya kami ingin komponen InteractionTracker yang mendasarinya menangani gerakan mouse seperti halnya dengan gerakan jari.

Hal-hal yang jauh lebih rumit untuk 17=mouse-berbasis konstan-kecepatan-panning (pengalaman yang saya pribadi tidak suka). Prototipenya jauh dari ideal dan saya tidak mencoba untuk mengatasi semua masalah, tetapi dua khususnya menyangkut:

  • selama panning kecepatan konstan (yaitu panning 0-velocity-decay), saya tidak berpikir ada cara dengan Scroller saat ini untuk menghentikan gerakan tanpa melompat kembali ke posisi yang lebih lama (dengan ScrollBy(0, 0)) . Hanya saja tidak mungkin untuk mengetahui seberapa jauh utas komposisi telah melampaui utas UI. Jadi beberapa API Scroller publik baru akan diperlukan untuk menghentikan kecepatan dengan cara tanpa kesalahan.
  • Saya tidak dapat menyimpan tangkapan mouse setelah acara PointerReleased mouse. Tampaknya fitur kerangka kerja Xaml baru akan diperlukan untuk mencapai ini.
    Bagaimanapun, ini mungkin kasus lain di mana kita ingin InteractionTracker yang mendasarinya menangani beberapa pengalaman secara langsung.
    Saya akan mengingat ini dengan pasti ketika membahas fitur Scroller/InteractionTracker di masa mendatang.

@RBrid

Semuanya berjalan cukup baik untuk 18=mouse-based panning, ......
Hal-hal yang jauh lebih rumit untuk 17=mouse-berbasis konstan-kecepatan-panning (pengalaman yang saya pribadi tidak suka).

Hasil yang menarik! Dalam hal itu, mengingat kesulitan dengan 17=constant-velocity, dan mengingat 18 dapat diimplementasikan dengan cara yang tidak mencegah penggunaan normal klik kiri, maka menurut pendapat pribadi saya, saya pikir proposal tersebut mungkin harus diperbarui ke tinggalkan 17 dan dukung 18 sebagai gantinya, tetapi memang saya tidak tahu berapa banyak pengguna yang akan mengeluh jika 17=constant-velocity ditinggalkan.

Terima kasih @RBrid atas investigasi ini. Senang mendengar bahwa mode 18 sudah berfungsi! Saya setuju itu idealnya harus ditangani oleh InteractionTracker, untuk memungkinkan pengoperasian yang lancar bahkan selama pemuatan utas UI.

@verelpode Kedua mode ditetapkan sebagai "Harus". Jadi jika usaha terlalu tinggi untuk mewujudkan mode 17, itu bisa saja ditinggalkan (dan mungkin ditambahkan nanti, jika diperlukan). Tapi mungkin seseorang menemukan cara untuk mewujudkannya tanpa terlalu banyak perubahan.

Saya harap ScrollViewer baru memiliki kemampuan untuk menonaktifkan atau menyesuaikan Zoom dengan tombol "Ctrl".

Apakah halaman ini membantu?
0 / 5 - 0 peringkat

Masalah terkait

adrientetar picture adrientetar  ·  3Komentar

Gavin-Williams picture Gavin-Williams  ·  3Komentar

ratishphilip picture ratishphilip  ·  3Komentar

mrlacey picture mrlacey  ·  3Komentar

cosminstirbu picture cosminstirbu  ·  3Komentar