WPF TextBlock'ta otomatik dikey kaydırma çubuğu?


336

Bir var TextBlockWPF. Dikey yüksekliğini aşan birçok satır yazıyorum. Bu olduğunda dikey bir kaydırma çubuğunun otomatik olarak görünmesini bekledim, ancak olmadı. Özellikler bölmesinde kaydırma çubuğu özelliği aramaya çalıştım, ancak bir tane bulamadım.

TextBlockİçeriği yüksekliğini aştığında dikey kaydırma çubuğunu otomatik olarak nasıl oluşturabilirim ?

Açıklama: Bunu doğrudan XAML'ye yazarak değil tasarımcıdan yapmayı tercih ederim.


1
Bu soruyu tekrar okuduktan sonra, TextBlockiki kez ve bir TextBoxkez bahsettiğinizi fark ettim .
Drew Noakes

Yanıtlar:


555

Kaydırma görüntüleyiciye sarın:

<ScrollViewer>
    <TextBlock />
</ScrollViewer>

NOT Bu cevap TextBlock, orijinal soruda istendiği gibi (salt okunur bir metin öğesi) için geçerlidir.

Bir TextBox(düzenlenebilir metin öğesinde) kaydırma çubuklarını göstermek istiyorsanız , ScrollViewerekli özellikleri kullanın :

<TextBox ScrollViewer.HorizontalScrollBarVisibility="Disabled"
         ScrollViewer.VerticalScrollBarVisibility="Auto" />

Bu iki özellik için geçerli değerler şunlardır Disabled, Auto, Hiddenve Visible.


2
Bunu tasarımcıdan nasıl yaparım?
Bab Yogoo

16
Maalesef emin değilim, WPF tasarımcısını kullanmıyorum. XAML'yi doğrudan eklerseniz tasarımcı kendini günceller.
Drew Noakes

5
@conqenator TextBox.ScrollToEnd ();
Petey B

2
@Greg, soru hakkında TextBlockdeğil TextBox.
Drew Noakes

7
Bazen, ekteki öğenin herhangi bir yüksekliği zorlamaması durumunda scoll'i görünmeye zorlamak için Scrollviewer üzerinde bir MaxHeight gerekir.
HackerBaloo

106

şimdi aşağıdakileri kullanabilirsiniz:

<TextBox Name="myTextBox" 
         ScrollViewer.HorizontalScrollBarVisibility="Auto"
         ScrollViewer.VerticalScrollBarVisibility="Auto"
         ScrollViewer.CanContentScroll="True">SOME TEXT
</TextBox>

19
@jjnguy, ben yaklaşık olarak orijinal soruyu yorumlanır TextBlockdeğil TextBox(başlık ve açılış hattında olduğu gibi), ancak ikinci paragraf söz TextBox. Açıkçası, bu cevap kesinlikle metin kutuları için en iyi yaklaşımdır ve benimki metin blokları için bildiğim en iyisidir :)
Drew Noakes

@ Çekti, ah, mantıklı. Açıklama için teşekkürler.
Mayıs 11:37

2
Benim için de daha iyi çalıştı. En azından bir TextBox için, kabul edilen cevapta olduğu gibi etrafında ScrollViewer kullanıldığında TextBox'ın sınırları kaybolur, çünkü sadece kontrolün tamamı değil içeriği de kaydırılır.
Yakıtlı

20

Daha iyi bir şey olurdu:

<Grid Width="Your-specified-value" >
    <ScrollViewer>
         <TextBlock Width="Auto" TextWrapping="Wrap" />
    </ScrollViewer>
</Grid>

Bu, ızgarayı kullanmıyorsanız, metin bloğunuzdaki metnin taşmayı ve metin bloğunun altındaki öğelerin üzerine gelmemesini sağlar. Bu, textblock zaten diğer unsurlarla bir ızgarada olmasına rağmen başka çözümler denediğimde başıma geldi. Metin bloğunun genişliğinin Otomatik olması gerektiğini ve Izgara öğesinde ile istediğinizi belirtmeniz gerektiğini unutmayın. Bunu kodumda yaptım ve güzel çalışıyor. HTH.


7
<ScrollViewer Height="239" VerticalScrollBarVisibility="Auto">
    <TextBox AcceptsReturn="True" TextWrapping="Wrap" LineHeight="10" />
</ScrollViewer>

Bu, XAML'de kayan TextBox'ı kullanmanın ve metin alanı olarak kullanmanın bir yoludur.


1
Soru ile ilgili TextBlockdeğil TextBox.
Afzaal Ahmad Zeeshan

Çok doğru bir cevap değil, ancak VerticalScrollBarVisibility'nin yararlı bir ipucu olduğunu gördüm, bu yüzden +1
Malachi

4

Bu cevap MVVM kullanan bir çözümü açıklamaktadır.

Bir pencereye bir günlük kutusu eklemek istiyorsanız, her yeni günlük mesajı eklendiğinde otomatik olarak alta kaydırılan bu çözüm mükemmeldir.

Bu ekli özellikler eklendiğinde, her yerde yeniden kullanılabilirler, böylece çok modüler ve yeniden kullanılabilir yazılımlar yapar.

Bu XAML'ı ekle:

<TextBox IsReadOnly="True"   
         Foreground="Gainsboro"                           
         FontSize="13" 
         ScrollViewer.HorizontalScrollBarVisibility="Auto"
         ScrollViewer.VerticalScrollBarVisibility="Auto"
         ScrollViewer.CanContentScroll="True"
         attachedBehaviors:TextBoxApppendBehaviors.AppendText="{Binding LogBoxViewModel.AttachedPropertyAppend}"                                       
         attachedBehaviors:TextBoxClearBehavior.TextBoxClear="{Binding LogBoxViewModel.AttachedPropertyClear}"                                    
         TextWrapping="Wrap">

Bu ekli özelliği ekle:

public static class TextBoxApppendBehaviors
{
    #region AppendText Attached Property
    public static readonly DependencyProperty AppendTextProperty =
        DependencyProperty.RegisterAttached(
            "AppendText",
            typeof (string),
            typeof (TextBoxApppendBehaviors),
            new UIPropertyMetadata(null, OnAppendTextChanged));

    public static string GetAppendText(TextBox textBox)
    {
        return (string)textBox.GetValue(AppendTextProperty);
    }

    public static void SetAppendText(
        TextBox textBox,
        string value)
    {
        textBox.SetValue(AppendTextProperty, value);
    }

    private static void OnAppendTextChanged(
        DependencyObject d,
        DependencyPropertyChangedEventArgs args)
    {
        if (args.NewValue == null)
        {
            return;
        }

        string toAppend = args.NewValue.ToString();

        if (toAppend == "")
        {
            return;
        }

        TextBox textBox = d as TextBox;
        textBox?.AppendText(toAppend);
        textBox?.ScrollToEnd();
    }
    #endregion
}

Ve bu ekli özellik (kutuyu temizlemek için):

public static class TextBoxClearBehavior
{
    public static readonly DependencyProperty TextBoxClearProperty =
        DependencyProperty.RegisterAttached(
            "TextBoxClear",
            typeof(bool),
            typeof(TextBoxClearBehavior),
            new UIPropertyMetadata(false, OnTextBoxClearPropertyChanged));

    public static bool GetTextBoxClear(DependencyObject obj)
    {
        return (bool)obj.GetValue(TextBoxClearProperty);
    }

    public static void SetTextBoxClear(DependencyObject obj, bool value)
    {
        obj.SetValue(TextBoxClearProperty, value);
    }

    private static void OnTextBoxClearPropertyChanged(
        DependencyObject d,
        DependencyPropertyChangedEventArgs args)
    {
        if ((bool)args.NewValue == false)
        {
            return;
        }

        var textBox = (TextBox)d;
        textBox?.Clear();
    }
}   

Ardından, MEF gibi bir bağımlılık enjeksiyon çerçevesi kullanıyorsanız, günlüğe kaydetmeye özgü tüm kodu kendi ViewModel'ine yerleştirebilirsiniz:

public interface ILogBoxViewModel
{
    void CmdAppend(string toAppend);
    void CmdClear();

    bool AttachedPropertyClear { get; set; }

    string AttachedPropertyAppend { get; set; }
}

[Export(typeof(ILogBoxViewModel))]
public class LogBoxViewModel : ILogBoxViewModel, INotifyPropertyChanged
{
    private readonly ILog _log = LogManager.GetLogger<LogBoxViewModel>();

    private bool _attachedPropertyClear;
    private string _attachedPropertyAppend;

    public void CmdAppend(string toAppend)
    {
        string toLog = $"{DateTime.Now:HH:mm:ss} - {toAppend}\n";

        // Attached properties only fire on a change. This means it will still work if we publish the same message twice.
        AttachedPropertyAppend = "";
        AttachedPropertyAppend = toLog;

        _log.Info($"Appended to log box: {toAppend}.");
    }

    public void CmdClear()
    {
        AttachedPropertyClear = false;
        AttachedPropertyClear = true;

        _log.Info($"Cleared the GUI log box.");
    }

    public bool AttachedPropertyClear
    {
        get { return _attachedPropertyClear; }
        set { _attachedPropertyClear = value; OnPropertyChanged(); }
    }

    public string AttachedPropertyAppend
    {
        get { return _attachedPropertyAppend; }
        set { _attachedPropertyAppend = value; OnPropertyChanged(); }
    }

    #region INotifyPropertyChanged
    public event PropertyChangedEventHandler PropertyChanged;

    [NotifyPropertyChangedInvocator]
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
    #endregion
}

Şöyle çalışır:

  • ViewModel, TextBox'ı kontrol etmek için Ekli Özellikler arasında geçiş yapar.
  • "Append" kullandığından şimşek hızında.
  • Başka herhangi bir ViewModel, günlük ViewModel'de yöntemleri çağırarak günlük iletileri oluşturabilir.
  • TextBox içinde yerleşik olan ScrollViewer'ı kullandığımızda, her yeni mesaj eklendiğinde otomatik olarak metin kutusunun en altına inmesini sağlayabiliriz.

4
<ScrollViewer MaxHeight="50"  
              Width="Auto" 
              HorizontalScrollBarVisibility="Disabled"
              VerticalScrollBarVisibility="Auto">
     <TextBlock Text="{Binding Path=}" 
                Style="{StaticResource TextStyle_Data}" 
                TextWrapping="Wrap" />
</ScrollViewer>

ScrollViewer MaxHeight koyarak başka bir şekilde yapıyorum.

MaxHeight'ı daha fazla veya daha az metin satırı gösterecek şekilde ayarlamanız yeterlidir. Kolay.



1

Bir metin bloğu için bu önerileri almaya çalıştım, ama işe yaramadı. Hatta onu tasarımcıdan çalıştırmaya çalıştım. (Mizanpaj'a bakın ve alttaki "V" aşağı okunu tıklayarak listeyi genişletin) Kaydırma görüntüleyiciyi Görünür ve ardından Otomatik olarak ayarlamayı denedim , ancak yine de çalışmaz.

Sonunda vazgeçti ve değişmiş TextBlockbir etmek TextBoxile Readonly nitelik seti, ve bir cazibe gibi çalıştı.


0

Başkası bu sorunu var ama eğer Dont know gözlerimi sarma TextBlockbir içine ScrollViewerbenim UI berbat somewhow - Basit ben değiştirilmesi anladım Geçici çözüm olarak TextBlockbir tarafından TextBoxbu gibi

<TextBox  Name="textBlock" SelectionBrush="Transparent" Cursor="Arrow" IsReadOnly="True" Text="My Text" VerticalScrollBarVisibility="Auto">

bir kaydırma çubuğuna sahip TextBoxgibi görünen ve davranan bir tane oluşturur TextBlock(ve hepsini tasarımcıda yapabilirsiniz).


0

Bu, bu soru için basit bir çözümdür. Dikey kaydırma yalnızca metin taştığında etkinleştirilir.

<TextBox Text="Try typing some text here " ScrollViewer.VerticalScrollBarVisibility="Auto" TextWrapping="WrapWithOverflow" />

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.