C# 使用“包裹”面板模板强制打断项目控件
我有一个有趣的问题,我一直想解决。基本上,我有一个items控件,它使用C# 使用“包裹”面板模板强制打断项目控件,c#,wpf,xaml,itemscontrol,wrappanel,C#,Wpf,Xaml,Itemscontrol,Wrappanel,我有一个有趣的问题,我一直想解决。基本上,我有一个items控件,它使用WrapPanel作为ItemsPanel来模拟从几个绑定字符串构建的段落。然而,有时我需要强制中断,比如当我开始一个新段落时,但是在文本块中插入中断实际上并不会在父换行面板中插入中断。代码如下: <ItemsControl ItemsSource="{Binding Fragments}" > <ItemsControl.ItemsPanel> <ItemsPanelT
WrapPanel
作为ItemsPanel
来模拟从几个绑定字符串构建的段落。然而,有时我需要强制中断,比如当我开始一个新段落时,但是在文本块中插入中断实际上并不会在父换行面板中插入中断。代码如下:
<ItemsControl ItemsSource="{Binding Fragments}" >
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock
TextWrapping="Wrap"
Text="{Binding}"/> <!--If this text has a break it won't
propagate that break to the wrap panel,
but instead just in this text block which
causes the formatting to look wrong-->
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
下面是片段的一个简单定义,它将显示我所说的内容:
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("\n\r This I want to force to the line below where the line above ends");
Fragments.Add("rapid \n\r new \n\r lines");
Fragments=新的ObservableCollection();
碎片。添加(“这是”);
添加(“第一行”);
添加(“它很长,将漂移到最远处”);
添加(“第二行,因为它由包裹面板控制”);
片段。添加(“\n\r我想将其强制到上面一行结束的下面一行”);
添加(“快速\n\r新\n\r行”);
我希望这些段落能够继续连接起来,但在遇到手册中的段落时,要尊重手册中的段落。像这样:
This is the first line, it is very long and will drift to the second line
naturally since it is controlled by a wrap panel.
This I want to force to the line below where the line above ends.
rapid
new
lines
这是第一条线,它很长,将漂移到第二条线
自然,因为它是由包裹面板控制的。
我想把它强制到下面的线,上面的线结束的地方。
迅速的
新的
lines我会放弃ItemsControl,转而使用textblock的Inlines集合。不幸的是,您无法直接绑定字符串集合,因为TextBlock.Inlines
不是依赖性属性,但使用附加的依赖性属性解决这一问题并不困难:
我还添加了对CollectionChanged事件传播的支持,因此向ViewModel.Fragments添加字符串将更新textblock。删除也会起作用,但有一个限制,即删除与字符串匹配的第一个片段
<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");
}
}
公共类视图模型:INotifyPropertyChanged
{
公共事件属性更改事件处理程序属性更改;
私有void OnPropertyChanged(字符串propertyName)
{
if(this.PropertyChanged!=null)
PropertyChanged(这是新的PropertyChangedEventArgs(propertyName));
}
私有可观察收集片段;
公共ObservableCollection片段{get{return}U片段;}set{U片段=值;OnPropertyChanged(“片段”);}
公共视图模型()
{
片段=新的ObservableCollection();
碎片。添加(“这是”);
添加(“第一行”);
添加(“它很长,将漂移到最远处”);
添加(“第二行,因为它由包裹面板控制”);
添加(“\n我想强制到上面一行结束的下面一行中”\n”);
添加(“快速\n新\n行”);
}
}
流动支持:
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);
}
}
});
}
}
}
}
使用系统;
使用System.Linq;
使用System.Collections.Generic;
使用System.Collections.ObjectModel;
使用System.Windows;
使用System.Windows.Controls;
使用System.Windows.Documents;
使用System.Collections.Specialized;
命名空间WpfApplication1
{
公共静态类流支持
{
私有静态字典_collChangedHandlers=新字典();
公共静态ObservableCollection GetFragments(TextBlock){return(ObservableCollection)tb.GetValue(FragmentsProperty);}
公共静态void SetFragments(TextBlock tb,ObservableCollection值){tb.SetValue(FragmentsProperty,value);}
public static readonly dependencProperty FragmentsProperty=dependencProperty.RegisterAttached(“片段”、类型of(ObservableCollection)、类型of(FlowSupport)、新属性元数据(新ObservableCollection()、OnFragmentsChanged));
FragmentSchanged上的私有静态无效(DependencyObject d、DependencyPropertyChangedEventArgs e)
{
var tb=d作为文本块;
如果(tb!=null)
{
CreateCollectionChangedHandler(tb);//创建处理程序,每个文本块一次
tb.Inlines.Clear();
var oldInlines=e.OldValue作为可观察集合;
if(oldInlines!=null)
{
oldInlines.CollectionChanged-=\u collChangedHandlers[tb];
}
var inlines=e.作为可观察集合的新值;
如果(内联线!=null)
{
inlines.CollectionChanged+=\u collChangedHandlers[tb];
foreach(内联线中的字符串s)
tb.Inlines.Add(s);
}
}
}
私有静态void CreateCollectionChangedHandler(文本块tb)
{
如果(!\u collChangedHandlers.ContainsKey(tb))
{
_collChangedHandlers.Add(tb,(s1,e1)=>
{
if(e1.NewItems!=null)
{
foreach(e1.NewItems中的字符串文本)
tb.Inlines.Add(文本);
}
如果(e1.OldItems!=null)
{
foreach(e1.OldItems中的字符串文本)
{
Inline-Inline=tb.Inlines.FirstOrDefault(i=>((运行)i.Text==Text);
如果(内联!=null)
tb.inline.Remove(inline);
}
}
});
}
}
}
}
是否有任何原因不将字符串连接起来,然后将其绑定到简单文本框?是否有任何原因不将字符串连接起来,然后将其绑定到简单文本框?所谓“中断”是指“换行”?@sa_ddam213 yes newlin