ItemsControl をチャックして、代わりにテキストブロックの Inlines コレクションを使用します。残念ながら、依存関係プロパティではないため、文字列のコレクションを直接バインドすることはできませんがTextBlock.Inlines
、添付の依存関係プロパティを使用してそれを回避することは難しくありません。
CollectionChanged イベントの伝播のサポートも追加したので、文字列を追加するViewModel.Fragments
とテキストブロックが更新されます。削除も機能しますが、文字列に一致する最初の Fragment が削除されるという制限があります。
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication1"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<local:ViewModel />
</Window.DataContext>
<Grid>
<TextBlock local:FlowSupport.Fragments="{Binding Fragments}" TextWrapping="WrapWithOverflow" Margin="10" Background="Beige" />
</Grid>
</Window>
ビューモデル:
public class ViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName)
{
if (this.PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
private ObservableCollection<string> _fragments;
public ObservableCollection<string> Fragments { get { return _fragments; } set { _fragments = value; OnPropertyChanged("Fragments"); } }
public ViewModel()
{
Fragments = new ObservableCollection<string>();
Fragments.Add("This is ");
Fragments.Add("the first line, ");
Fragments.Add("it is very long and will drift to the ");
Fragments.Add("second line naturally since it is controlled by a wrap panel");
Fragments.Add("\nThis I want to force to the line below where the line above ends\n");
Fragments.Add("rapid \nnew \nlines");
}
}
フローサポート:
using System;
using System.Linq;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Collections.Specialized;
namespace WpfApplication1
{
public static class FlowSupport
{
private static Dictionary<TextBlock, NotifyCollectionChangedEventHandler> _collChangedHandlers = new Dictionary<TextBlock,NotifyCollectionChangedEventHandler>();
public static ObservableCollection<string> GetFragments(TextBlock tb) { return (ObservableCollection<string>)tb.GetValue(FragmentsProperty); }
public static void SetFragments(TextBlock tb, ObservableCollection<string> value) { tb.SetValue(FragmentsProperty, value); }
public static readonly DependencyProperty FragmentsProperty = DependencyProperty.RegisterAttached("Fragments", typeof(ObservableCollection<string>), typeof(FlowSupport), new PropertyMetadata(new ObservableCollection<string>(), OnFragmentsChanged));
private static void OnFragmentsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var tb = d as TextBlock;
if (tb != null)
{
CreateCollectionChangedHandler(tb); // create handler, once per textblock
tb.Inlines.Clear();
var oldInlines = e.OldValue as ObservableCollection<string>;
if (oldInlines != null)
{
oldInlines.CollectionChanged -= _collChangedHandlers[tb];
}
var inlines = e.NewValue as ObservableCollection<string>;
if (inlines != null)
{
inlines.CollectionChanged += _collChangedHandlers[tb];
foreach (string s in inlines)
tb.Inlines.Add(s);
}
}
}
private static void CreateCollectionChangedHandler(TextBlock tb)
{
if (!_collChangedHandlers.ContainsKey(tb))
{
_collChangedHandlers.Add(tb, (s1, e1) =>
{
if (e1.NewItems != null)
{
foreach (string text in e1.NewItems)
tb.Inlines.Add(text);
}
if (e1.OldItems != null)
{
foreach (string text in e1.OldItems)
{
Inline inline = tb.Inlines.FirstOrDefault(i => ((Run)i).Text == text);
if (inline != null)
tb.Inlines.Remove(inline);
}
}
});
}
}
}
}