I make a chat. To display a list of messages I use FlowDocument with attached binding. (I did not write the control) It looks like this:

namespace FlowItemsControlApp.Controls { public class FlowItemsControl : Control { private FlowDocument _document; static FlowItemsControl() { DefaultStyleKeyProperty.OverrideMetadata( typeof(FlowItemsControl), new FrameworkPropertyMetadata(typeof(FlowItemsControl))); } #region ItemsSource public static readonly DependencyProperty ItemsSourceProperty = DependencyProperty.Register( nameof(ItemsSource), typeof(IEnumerable), typeof(FlowItemsControl), new PropertyMetadata(OnItemsSourceChanged)); public IEnumerable ItemsSource { get { return (IEnumerable)GetValue(ItemsSourceProperty); } set { SetValue(ItemsSourceProperty, value); } } private static void OnItemsSourceChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) { var flowItemsControl = (FlowItemsControl) sender; var newValue = (IEnumerable) e.NewValue; var oldValue = (IEnumerable) e.OldValue; flowItemsControl.OnItemsSourceChanged(newValue, oldValue); } private void OnItemsSourceChanged(IEnumerable newValue, IEnumerable oldValue) { var notifyCollectionChanged = oldValue as INotifyCollectionChanged; if (notifyCollectionChanged != null) { notifyCollectionChanged.CollectionChanged -= OnItemsChanged; } notifyCollectionChanged = newValue as INotifyCollectionChanged; if (notifyCollectionChanged != null) { notifyCollectionChanged.CollectionChanged += OnItemsChanged; } ApplyItemsSource(newValue); } private void ApplyItemsSource(IEnumerable itemsSource) { if (_document == null) return; foreach (var newItem in itemsSource) { var newContainer = GetContainerForItem(newItem); if (ItemTemplate != null) { var content = ItemTemplate.LoadContent() as Paragraph; if (content != null) { var inlines = content.Inlines.ToList(); content.Inlines.Clear(); newContainer.Inlines.AddRange(inlines); } } newContainer.DataContext = newItem; _document.Blocks.Add(newContainer); } } private void OnItemsChanged(object sender, NotifyCollectionChangedEventArgs e) { if (_document == null) return; switch (e.Action) { case NotifyCollectionChangedAction.Add: foreach (var newItem in e.NewItems) { var newContainer = GetContainerForItem(newItem); newContainer.DataContext = newItem; _document.Blocks.Add(newContainer); } break; case NotifyCollectionChangedAction.Remove: foreach (var oldItem in e.OldItems) { var oldContainer = _document.Blocks.FirstOrDefault(x => x.DataContext == oldItem); if (oldContainer == null) continue; _document.Blocks.Remove(oldContainer); } break; case NotifyCollectionChangedAction.Reset: _document.Blocks.Clear(); break; } } #endregion #region ItemTemplate public static readonly DependencyProperty ItemTemplateProperty = DependencyProperty.Register( nameof(ItemTemplate), typeof (DataTemplate), typeof (FlowItemsControl), new PropertyMetadata(OnItemTemplateChanged)); public DataTemplate ItemTemplate { get { return (DataTemplate)GetValue(ItemTemplateProperty); } set { SetValue(ItemTemplateProperty, value); } } private static void OnItemTemplateChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) { var flowItemsControl = (FlowItemsControl)sender; var newValue = (DataTemplate)e.NewValue; flowItemsControl.OnItemTemplateChanged(newValue); } private void OnItemTemplateChanged(DataTemplate newValue) { if (_document == null) return; foreach (var paragraph in _document.Blocks.OfType<Paragraph>()) { var content = newValue.LoadContent() as Paragraph; paragraph.Inlines.Clear(); if (content != null) { var inlines = content.Inlines.ToList(); content.Inlines.Clear(); paragraph.Inlines.AddRange(inlines); } } } #endregion public override void OnApplyTemplate() { _document = Template.FindName("Document", this) as FlowDocument; } protected virtual Paragraph GetContainerForItem(object item) { return new Paragraph() { DataContext = item, }; } } } 

+

 <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:controls="clr-namespace:FlowItemsControlApp.Controls"> <Style x:Key="{x:Type controls:FlowItemsControl}" TargetType="{x:Type controls:FlowItemsControl}"> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type controls:FlowItemsControl}"> <ContentControl> <FlowDocument x:Name="Document" /> </ContentControl> </ControlTemplate> </Setter.Value> </Setter> </Style> </ResourceDictionary> <controls:FlowItemsControl ItemsSource="{Binding MessageVMs}" Grid.Row="1"> <controls:FlowItemsControl.ItemTemplate> <DataTemplate> <Paragraph> <Run Text="{Binding Time, StringFormat=HH:mm}" /> <Run Text="{Binding UserName}" Foreground="Blue" TextDecorations="Underline"/> <Run Text="&gt;"/> <Run Text="{Binding Text}" /> </Paragraph> </DataTemplate> </controls:FlowItemsControl.ItemTemplate> </controls:FlowItemsControl> 

screen: https://www.dropbox.com/s/wnt9cn0eusz58sk/screen.png?dl=0

Help please remove the strip with the interface from the PageViewer below. I absolutely do not need it.

    1 answer 1

    Your

     <FlowDocument x:Name="Document" /> 

    implicitly wraps around in FlowDocumentReader . Try to specify the container explicitly:

     <RichTextBox> <FlowDocument x:Name="Document" /> </RichTextBox> 

    It turns out that it is necessary:

    Kaaaz-z-ly!