2013-04-18 2 views
1

나는 해결하려고 애쓰는 흥미로운 문제가 있습니다. 기본적으로 나는 ItemsPanel으로 여러 바인딩 된 문자열로 만든 단락을 시뮬레이트하기 위해 WrapPanel을 사용하는 항목 컨트롤이 있습니다. 그러나 내가 새 단락을 시작할 때와 같이 휴식을 강요 할 필요가있는 시간이 있지만 TextBlockDateTemplate에 중단을 넣는 것은 실제로 부모 랩 패널에 중단을 두지 않습니다. 여기랩 패 널 템플릿을 사용하여 항목 컨트롤에서 휴식을 취하십시오.

<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"); 

enter image description here

나는 단락으로 흐름이 싶습니다

그 단지 연결을 계속 유지하면서 수동 브레이크가 실행되면이를 존중하십시오. 이렇게 :

 
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
+0

어떤 이유로 당신이 문자열을 연결 한 후 간단한 텍스트 상자에 바인딩되지 않은이 있습니까? – Kenneth

+0

문자열을 연결하지 않고 간단한 텍스트 상자에 바인딩하는 이유가 있습니까? – Kenneth

+0

"Break"는 "NewLine"을 의미합니까? –

답변

2

나는 ItemsControl을 잡아서 대신 텍스트 블록의 Inlines 컬렉션을 사용합니다. 아쉽게도 TextBlock.Inlines은 종속성 속성이 아니기 때문에 문자열 컬렉션을 직접 바인딩 할 수는 없지만 첨부 된 종속성 속성을 사용하여이 문제를 해결하는 것은 어렵지 않습니다.

또한 CollectionChanged 이벤트의 전파에 대한 지원이 추가되었으므로 ViewModel.Fragments 문자열은 텍스트 블록을 업데이트합니다. 제거는 문자열과 일치하는 첫 번째 조각이 제거된다는 제한이 있지만 작동합니다.

enter image description here

<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"); 
    } 
} 

FlowSupport :

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); 
         } 
        } 
       }); 
      } 
     } 
    } 
} 
+0

유망한 소리가 들리니 집에 도착하면 시험해 보겠습니다. –

+0

흠,이 솔루션의 유일한 문제점은 항목의 컨트롤과 래핑 패널에서 각 단어의 특성, 즉 대담 텍스트의 색 ... 등을 제어 할 수 있다는 점이었습니다. 이 방법으로 그 효과를 더 이상 얻을 수 있습니까? –

+0

해결 방법을 찾지 않아도됩니다. 인라인에'Run' 개체를 추가하고 속성을 설정할 수 있습니다. 한 가지 더 문제가 있습니다. OnFragmentsChanged는 컬렉션이 실제로 변경 될 때가 아니라로드시에만 실행됩니다. –

관련 문제