Автоматическая вертикальная полоса прокрутки в WPF TextBlock?
у меня есть TextBlock
в WPF. Я пишу ему много строк, намного превышающих его вертикальную высоту. Я ожидал, что вертикальная полоса прокрутки появится автоматически, когда это произойдет, но этого не произошло. Я попытался найти свойство полосы прокрутки на панели свойств, но не смог его найти.
Как я могу сделать вертикальную полосу прокрутки, созданные автоматически для моего TextBlock
Как только его содержимое превысит его высоту?
уточнение: я бы предпочел сделать это от дизайнера, а не напрямую запись в XAML.
8 ответов
оберните его в Средство просмотра прокрутки:
<ScrollViewer>
<TextBlock />
</ScrollViewer>
Примечание этот ответ относится к TextBlock
(текстовый элемент только для чтения), как указано в исходном вопросе.
если вы хотите показать полосы прокрутки в элементе TextBox
(редактируемый текстовый элемент) затем используйте ScrollViewer
свойства:
<TextBox ScrollViewer.HorizontalScrollBarVisibility="Disabled"
ScrollViewer.VerticalScrollBarVisibility="Auto" />
допустимыми значениями для этих двух свойств являются Disabled
, Auto
, Hidden
и Visible
.
теперь можно использовать следующее:
<TextBox Name="myTextBox"
ScrollViewer.HorizontalScrollBarVisibility="Auto"
ScrollViewer.VerticalScrollBarVisibility="Auto"
ScrollViewer.CanContentScroll="True">SOME TEXT
</TextBox>
что-то лучше будет:
<Grid Width="Your-specified-value" >
<ScrollViewer>
<TextBlock Width="Auto" TextWrapping="Wrap" />
</ScrollViewer>
</Grid>
Это гарантирует, что текст в вашем textblock не переполняется и не перекрывает элементы под textblock, как это может быть, если вы не используете сетку. Это произошло со мной, когда я попробовал другие решения, хотя textblock уже был в сетке с другими элементами. Имейте в виду, что ширина textblock должна быть автоматической, и вы должны указать желаемое с в элементе сетки. Я сделал это в мой код и он работает красиво. HTH.
<ScrollViewer Height="239" VerticalScrollBarVisibility="Auto">
<TextBox AcceptsReturn="True" TextWrapping="Wrap" LineHeight="10" />
</ScrollViewer>
Это способ использовать текстовое поле прокрутки в XAML и использовать его в качестве текстовой области.
этот ответ описывает решение с использованием MVVM.
это решение отлично подходит, если вы хотите добавить окно журнала в окно, которое автоматически прокручивается вниз каждый раз, когда добавляется новое сообщение журнала.
как только эти прикрепленные свойства добавлены, их можно повторно использовать везде, поэтому оно делает для очень модульного и многоразового программного обеспечения.
добавьте этот XAML:
<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">
добавьте это прикрепленное свойство:
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
}
и это придает свойство (чтобы очистить поле):
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();
}
}
затем, если вы используете фреймворк инъекции зависимостей, такой как MEF, вы можете поместить весь код для ведения журнала в собственную ViewModel:
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
}
вот как это работает:
- ViewModel переключает вложенные свойства для управления текстовым полем.
- поскольку он использует "Append", это молниеносно.
- любой другой ViewModel может генерировать сообщения журнала, вызывая методы на ведение журнала ViewModel.
- поскольку мы используем ScrollViewer, встроенный в текстовое поле, мы можем автоматически прокручивать его в нижней части текстового поля при каждом добавлении нового сообщения.
<ScrollViewer MaxHeight="50"
Width="Auto"
HorizontalScrollBarVisibility="Disabled"
VerticalScrollBarVisibility="Auto">
<TextBlock Text="{Binding Path=}"
Style="{StaticResource TextStyle_Data}"
TextWrapping="Wrap" />
</ScrollViewer>
Я делаю это по-другому, помещая MaxHeight в ScrollViewer.
просто отрегулируйте MaxHeight, чтобы показать больше или меньше строк текста. Простой.
можно использовать
ScrollViewer.HorizontalScrollBarVisibility="Visible"
ScrollViewer.VerticalScrollBarVisibility="Visible"
это вложенное свойство wpf. Для получения дополнительной информации
http://wpfbugs.blogspot.in/2014/02/wpf-layout-controls-scrollviewer.html
Не знаю, есть ли у кого-то еще эта проблема, но упаковка моя TextBlock
на ScrollViewer
somewhow испортил мой пользовательский интерфейс - в качестве простого обходного пути я понял, что замена TextBlock
на TextBox
как это
<TextBox Name="textBlock" SelectionBrush="Transparent" Cursor="Arrow" IsReadOnly="True" Text="My Text" VerticalScrollBarVisibility="Auto">
создает TextBox
что выглядит и ведет себя как TextBlock
С помощью полосы прокрутки (и вы можете сделать все это в конструкторе).