Dapatkan posisi gulir Kotak Teks WPF

Saya perlu menambahkan beberapa hiasan pada konten kontrol WPF TextBox. Pada dasarnya itu berfungsi dengan baik, saya bisa mendapatkan posisi indeks karakter yang ditentukan dan menata elemen saya yang lain sesuai dengan itu. Tapi semuanya rusak ketika TextBox di-scroll. Posisi layout saya tidak lagi sesuai dengan teks yang ditampilkan karena telah dipindahkan ke tempat lain.

Sekarang saya cukup terkejut bahwa kelas TextBox tidak memberikan informasi apa pun tentang status penggulirannya, atau kejadian apa pun saat penggulirannya berubah. Apa yang bisa saya lakukan sekarang?

Saya menggunakan Snoop untuk mencari tahu apakah ada sub-elemen pengguliran yang dapat saya tanyakan, tetapi ScrollContentPresenter juga tidak memiliki informasi pengguliran apa pun. Saya benar-benar ingin menempatkan elemen dekorasi saya langsung ke dalam area yang digulir sehingga pengguliran dapat memengaruhinya juga, tetapi hanya ada satu kontrol konten dan itu sudah menjadi salah satu internal TextBox.


person ygoe    schedule 15.02.2013    source sumber
comment
Mungkin mencoba berlangganan acara yang dirutekan ScrollViewer.ScrollChanged? Ini memberikan informasi seperti tinggi jangkauan, offset gulir, ukuran area pandang (semua dalam dimensi horizontal dan vertikal), mungkin itu bisa membantu. Saya tidak yakin saya memahami tugas Anda sepenuhnya. Tapi cobalah.   -  person Haspemulator    schedule 16.02.2013


Jawaban (2)


Saya tidak yakin bagaimana cara menangkap suatu peristiwa ketika kotak teks telah digulir (mungkin menggunakan jawaban narohi untuk itu), tetapi ada cara sederhana untuk melihat posisi gulir saat ini:

// Gets or sets the vertical scroll position.
textBox.VerticalOffset

(Dari http://msdn.microsoft.com/en-us/library/system.windows.controls.primitives.textboxbase.verticaloffset(v=vs.100).aspx)

Saya menggunakannya untuk melihat apakah kotak teks digulir sampai akhir, seperti ini:

public static bool IsScrolledToEnd(this TextBox textBox)
{
    return textBox.VerticalOffset + textBox.ViewportHeight == textBox.ExtentHeight;
}
person John Gibb    schedule 05.02.2014
comment
John, terima kasih, saya sudah mencoba IsScrolledToEnd Anda. Biasanya berhasil, tetapi tidak selalu. Masalahnya adalah Anda membandingkan ganda dengan operator ==. Menurut saya seharusnya ada toleransi 1 baris dalam perbandingan ini, seperti ini: bool scrollToEnd = Memo.VerticalOffset > Memo.ExtentHeight - Memo.ViewportHeight - fontHeight; - person Aleksandr; 12.12.2017
comment
@Aleksandr Di mana Anda mendapatkan fontHeight? Saya menggunakan Memo.FontSize dan sepertinya berfungsi sebagaimana mestinya. - person Gravitate; 19.03.2019
comment
double fontHeight = Memo.FontSize * Memo.FontFamily.LineSpacing; - person Aleksandr; 21.03.2019

Anda bisa mendapatkan ScrollViewer dengan metode ini dengan memasukkan kotak teks Anda sebagai argumen dan tipe ScrollView. Kemudian Anda dapat berlangganan acara ScrollChanged.

public static T FindDescendant<T>(DependencyObject obj) where T : DependencyObject
{
    if (obj == null) return default(T);
    int numberChildren = VisualTreeHelper.GetChildrenCount(obj);
    if (numberChildren == 0) return default(T);

    for (int i = 0; i < numberChildren; i++)
    {
        DependencyObject child = VisualTreeHelper.GetChild(obj, i);
        if (child is T)
        {
            return (T)(object)child;
        }
    }

    for (int i = 0; i < numberChildren; i++)
    {
        DependencyObject child = VisualTreeHelper.GetChild(obj, i);
        var potentialMatch = FindDescendant<T>(child);
        if (potentialMatch != default(T))
        {
            return potentialMatch;
        }
    }

    return default(T);
}

Contoh:

public MainWindow()
{
    InitializeComponent();
    Loaded += new RoutedEventHandler(MainWindow_Loaded);
}

void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
    ScrollViewer s = FindDescendant<ScrollViewer>(txtYourTextBox);
    s.ScrollChanged += new ScrollChangedEventHandler(s_ScrollChanged);
}

void s_ScrollChanged(object sender, ScrollChangedEventArgs e)
{
    // check event args for information needed
}
person Nathan Hillyer    schedule 15.02.2013