我的WPF应用程序从后端服务接收我需要在UI中显示的消息流。这些消息差异很大,我希望有不同的视觉布局(字符串格式,颜色,字体,图标,等等)对于每条消息。
我希望能够为每个消息创建一个内联(运行,TextBlock,斜体等),然后以某种方式将它们都放在一个ObservableCollection<>中,并在UI中使用WPF数据绑定在我的TextBlock.Inlines上的魔力。我不知道怎么做,这是可能的吗?
发布于 2009-12-25 08:21:32
这是不可能的,因为TextBlock.Inlines属性不是依赖属性。只有依赖项属性才能成为数据绑定的目标。
根据您的确切布局要求,您可以使用ItemsControl来实现这一点,将其ItemsPanel设置为WrapPanel,将其ItemsSource设置为您的集合。(这里可能需要一些实验,因为Inline不是UIElement,所以它的默认呈现可能会使用ToString()而不是显示。)
或者,您可能需要使用一个可绑定的PartsSource属性和一个TextBlock作为其默认模板来构建一个新控件,例如MultipartTextBlock。设置PartsSource时,您的控件将附加一个CollectionChanged事件处理程序(直接或通过CollectionChangedEventManager),并在PartsSource集合更改时从代码更新TextBlock.Inlines集合。
在这两种情况下,如果您的代码直接生成Inline元素(因为Inline不能在两个地方同时使用),则可能需要小心。您也可以考虑公开文本、字体等的抽象模型(即视图模型),并通过DataTemplate创建实际的Inline对象。这也可能会提高可测试性,但显然会增加复杂性和工作量。
发布于 2012-03-03 21:08:08
您可以向TextBlock子类添加依赖项属性
public class BindableTextBlock : TextBlock
{
public ObservableCollection<Inline> InlineList
{
get { return (ObservableCollection<Inline>)GetValue(InlineListProperty); }
set { SetValue(InlineListProperty, value); }
}
public static readonly DependencyProperty InlineListProperty =
DependencyProperty.Register("InlineList",typeof(ObservableCollection<Inline>), typeof(BindableTextBlock), new UIPropertyMetadata(null, OnPropertyChanged));
private static void OnPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
BindableTextBlock textBlock = sender as BindableTextBlock;
ObservableCollection<Inline> list = e.NewValue as ObservableCollection<Inline>;
list.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(textBlock.InlineCollectionChanged);
}
private void InlineCollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add)
{
int idx = e.NewItems.Count -1;
Inline inline = e.NewItems[idx] as Inline;
this.Inlines.Add(inline);
}
}
}发布于 2017-12-02 02:54:11
这是另一种利用WPF行为/附加属性的解决方案:
public static class TextBlockExtensions
{
public static IEnumerable<Inline> GetBindableInlines ( DependencyObject obj )
{
return (IEnumerable<Inline>) obj.GetValue ( BindableInlinesProperty );
}
public static void SetBindableInlines ( DependencyObject obj, IEnumerable<Inline> value )
{
obj.SetValue ( BindableInlinesProperty, value );
}
public static readonly DependencyProperty BindableInlinesProperty =
DependencyProperty.RegisterAttached ( "BindableInlines", typeof ( IEnumerable<Inline> ), typeof ( TextBlockExtensions ), new PropertyMetadata ( null, OnBindableInlinesChanged ) );
private static void OnBindableInlinesChanged ( DependencyObject d, DependencyPropertyChangedEventArgs e )
{
var Target = d as TextBlock;
if ( Target != null )
{
Target.Inlines.Clear ();
Target.Inlines.AddRange ( (System.Collections.IEnumerable) e.NewValue );
}
}
}在XAML中,像这样使用它:
<TextBlock MyBehaviors:TextBlockExtensions.BindableInlines="{Binding Foo}" />这使您不必从TextBlock继承。它也可以使用ObservableCollection而不是IEnumerable,在这种情况下,您需要订阅集合更改。
https://stackoverflow.com/questions/1959856
复制相似问题