using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Text.RegularExpressions;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
namespace AppNamespace
{
public static class BindTextList
{
public static IEnumerable<object> GetSource(DependencyObject obj)
{
return (IEnumerable<object>)obj.GetValue(SourceProperty);
}
public static void SetSource(DependencyObject obj, IEnumerable<object> value)
{
obj.SetValue(SourceProperty, value);
}
// Using a DependencyProperty as the backing store for Source. This enables animation, styling, binding, etc...
public static readonly DependencyProperty SourceProperty =
DependencyProperty.RegisterAttached("Source", typeof(IEnumerable<object>), typeof(BindTextList), new PropertyMetadata(null, Source_Changed));
public static string GetTextMemberPaths(DependencyObject obj)
{
return (string)obj.GetValue(TextMemberPathsProperty);
}
public static void SetTextMemberPaths(DependencyObject obj, string value)
{
obj.SetValue(TextMemberPathsProperty, value);
}
// Using a DependencyProperty as the backing store for TextMemberPath. This enables animation, styling, binding, etc...
public static readonly DependencyProperty TextMemberPathsProperty =
DependencyProperty.RegisterAttached("TextMemberPaths", typeof(string), typeof(BindTextList), new PropertyMetadata("", TextMemberPath_Changed));
public static string GetSeperator(DependencyObject obj)
{
return (string)obj.GetValue(SeperatorProperty);
}
public static void SetSeperator(DependencyObject obj, string value)
{
obj.SetValue(SeperatorProperty, value);
}
// Using a DependencyProperty as the backing store for Seperator. This enables animation, styling, binding, etc...
public static readonly DependencyProperty SeperatorProperty =
DependencyProperty.RegisterAttached("Seperator", typeof(string), typeof(BindTextList), new PropertyMetadata(", "/*, Seperator_Changed*/));
public static string GetStringFormat(DependencyObject obj)
{
return (string)obj.GetValue(StringFormatProperty);
}
public static void SetStringFormat(DependencyObject obj, string value)
{
obj.SetValue(StringFormatProperty, value);
}
// Using a DependencyProperty as the backing store for StringFormat. This enables animation, styling, binding, etc...
public static readonly DependencyProperty StringFormatProperty =
DependencyProperty.RegisterAttached("StringFormat", typeof(string), typeof(BindTextList), new PropertyMetadata("{0}", StringFormat_Changed));
private static System.Runtime.CompilerServices.ConditionalWeakTable<TextBlock, ChangeListener> tbTable = new System.Runtime.CompilerServices.ConditionalWeakTable<TextBlock, ChangeListener>();
private static void Source_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var tb = d as TextBlock;
if (tb == null) return;
if (e.OldValue != e.NewValue)
{
if (e.OldValue is INotifyCollectionChanged oldNCC)
{
if (tbTable.TryGetValue(tb, out var oldListener))
{
CollectionChangedEventManager.RemoveListener(oldNCC, oldListener);
tbTable.Remove(tb);
}
}
if (e.NewValue is INotifyCollectionChanged newNCC)
{
var listener = new ChangeListener(tb);
tbTable.Add(tb, listener);
CollectionChangedEventManager.AddListener(newNCC, listener);
}
}
CreateInlines(tb);
}
//private static void Seperator_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
//{
// var tb = d as TextBlock;
// if (tb != null) CreateInlines(tb);
//}
private static void TextMemberPath_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var tb = d as TextBlock;
if (tb != null) CreateInlines(tb);
}
private static void StringFormat_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var tb = d as TextBlock;
if (tb != null) CreateInlines(tb);
}
private static void CreateInlines(TextBlock tb)
{
var source = GetSource(tb);
tb.Inlines.Clear();
if (source == null) return;
var sep = GetSeperator(tb);
var textPath = GetTextMemberPaths(tb);
var format = GetStringFormat(tb);
var paths = Regex.Split(textPath, @"(?<!\^),");
var enumerator = source.GetEnumerator();
if (!enumerator.MoveNext()) return;
while (true)
{
BindingBase b;
if (paths.Length == 1)
{
b = new Binding(textPath)
{
Source = enumerator.Current,
StringFormat = format,
Mode = BindingMode.OneWay
};
}
else
{
var mb = new MultiBinding()
{
StringFormat = format,
Mode = BindingMode.OneWay
};
foreach (var path in paths)
{
mb.Bindings.Add(new Binding(path) { Source = enumerator.Current });
}
b = mb;
}
var r = new Run();
r.SetBinding(Run.TextProperty, b);
tb.Inlines.Add(r);
if (!enumerator.MoveNext()) break;
b = new Binding()
{
Path = new PropertyPath(SeperatorProperty),
Source = tb
};
r = new Run();
r.SetBinding(Run.TextProperty, b);
tb.Inlines.Add(r);
}
}
private class ChangeListener : IWeakEventListener
{
public TextBlock TextBlock { get; }
public ChangeListener(TextBlock tb)
{
TextBlock = tb;
}
public bool ReceiveWeakEvent(Type managerType, object sender, EventArgs e)
{
if (managerType != typeof(CollectionChangedEventManager)) return false;
CreateInlines(TextBlock);
return true;
}
}
}
}