2008-12-05 25 views
10

có ai biết nếu có một cách đơn giản để ràng buộc việc chặn văn bản vào Danh sách. Những gì tôi đã làm cho đến nay là tạo ra một listview và ràng buộc nó vào danh sách và sau đó tôi có một mẫu trong listview sử dụng một textblock duy nhất.Kết hợp chặn văn bản WPF với Danh sách <string>

những gì tôi thực sự muốn làm là chỉ cần ràng buộc Danh sách vào một khối chữ và có nó hiển thị tất cả các dòng.

Trong Winforms có thuộc tính "Lines" mà tôi chỉ có thể ném List vào, nhưng tôi không thấy nó trên textblock WPF, hoặc TextBox.

Bất kỳ ý tưởng nào?

tôi đã bỏ lỡ điều gì đó đơn giản?

Dưới đây là đoạn code

<UserControl x:Class="QSTClient.Infrastructure.Library.Views.WorkItemLogView" 
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     Width="500" Height="400"> 
<StackPanel> 
    <ListView ItemsSource="{Binding Path=Logs}" > 
     <ListView.View> 
      <GridView> 
       <GridViewColumn Header="Log Message"> 
        <GridViewColumn.CellTemplate> 
         <DataTemplate> 
          <TextBlock Text="{Binding}"/> 
         </DataTemplate> 
        </GridViewColumn.CellTemplate> 
       </GridViewColumn> 
      </GridView> 
     </ListView.View> 
    </ListView> 
</StackPanel> 

và Lớp WorkItem

public class WorkItem 
{ 
    public string Name { get; set; } 
    public string Description { get; set; } 
    public string CurrentLog { get; private set; } 
    public string CurrentStatus { get; private set; } 
    public WorkItemStatus Status { get; set; } 
    public ThreadSafeObservableCollection<string> Logs{get;private set;} 

Tôi đang sử dụng Prism để tạo ra sự kiểm soát và đặt nó vào một WindowRegion

 WorkItemLogView newView = container.Resolve<WorkItemLogView>(); 
     newView.DataContext = workItem; 
     regionManager.Regions["ShellWindowRegion"].Add(newView); 

thanks

Trả lời

28

Chuyển đổi danh sách của bạn thành một chuỗi duy nhất bằng "\ r \ n" làm dấu phân tách ở giữa. và liên kết nó với TextBlock. Hãy chắc chắn rằng TextBlock không bị giới hạn với chiều cao của nó, để nó có thể phát triển dựa trên số lượng các dòng. tôi sẽ thực hiện điều này như một Chuyển đổi giá trị gia tăng để XAML Binding mà chuyển đổi một danh sách các chuỗi thành một chuỗi duy nhất với dòng sản phẩm mới được thêm vào trong giữa

<TextBlock Text="{Binding Path=Logs,Converter={StaticResource ListToStringConverter}}"/> 

Các ListToStringConverter sẽ trông như thế này:

[ValueConversion(typeof(List<string>), typeof(string))] 
public class ListToStringConverter : IValueConverter 
{ 

    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
    { 
     if (targetType != typeof(string)) 
      throw new InvalidOperationException("The target must be a String"); 

     return String.Join(", ", ((List<string>)value).ToArray()); 
    } 

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
    { 
     throw new NotImplementedException(); 
    } 
} 
+0

Điều đó hoàn toàn phù hợp với bạn Jobi. – Joshua

2

nếu bạn sử dụng trình biến đổi nó hoạt động lần đầu tiên hoàn hảo, nhưng nếu một hoặc nhiều lần ghi nhật ký đi vào danh sách ghi nhật ký, không có cập nhật về ràng buộc của bạn, bởi vì trình biến đổi chỉ hoạt động ở lần đầu tiên. tất cả các điều khiển không có điều khiển mục không đăng ký sự kiện được thay đổi!

đây là một mã chút cho kịch bản này

using System; 
using System.Collections.ObjectModel; 
using System.Windows; 

namespace BindListToTextBlock 
{ 
    /// <summary> 
    /// Interaction logic for MainWindow.xaml 
    /// </summary> 
    public partial class MainWindow : Window 
    { 
    private WorkItem workItem; 

    public MainWindow() { 
     this.WorkItems = new ObservableCollection<WorkItem>(); 
     this.DataContext = this; 
     this.InitializeComponent(); 
    } 

    public class WorkItem 
    { 
     public WorkItem() { 
     this.Logs = new ObservableCollection<string>(); 
     } 

     public string Name { get; set; } 
     public ObservableCollection<string> Logs { get; private set; } 
    } 

    public ObservableCollection<WorkItem> WorkItems { get; set; } 

    private void Button_Click(object sender, RoutedEventArgs e) { 
     this.workItem = new WorkItem() {Name = string.Format("new item at {0}", DateTime.Now)}; 
     this.workItem.Logs.Add("first log"); 
     this.WorkItems.Add(this.workItem); 
    } 

    private void Button_Click_1(object sender, RoutedEventArgs e) { 
     if (this.workItem != null) { 
     this.workItem.Logs.Add(string.Format("more log {0}", DateTime.Now)); 
     } 
    } 
    } 
} 

XAML

<Window x:Class="BindListToTextBlock.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:BindListToTextBlock="clr-namespace:BindListToTextBlock" 
     Title="MainWindow" 
     Height="350" 
     Width="525"> 
    <Grid> 
    <Grid.Resources> 
     <BindListToTextBlock:ListToStringConverter x:Key="ListToStringConverter" /> 
    </Grid.Resources> 
    <Grid.RowDefinitions> 
     <RowDefinition Height="Auto" /> 
     <RowDefinition Height="Auto" /> 
     <RowDefinition /> 
    </Grid.RowDefinitions> 
    <Button Grid.Row="0" 
      Content="Add item..." 
      Click="Button_Click" /> 
    <Button Grid.Row="1" 
      Content="Add some log to last item" 
      Click="Button_Click_1" /> 
    <ListView Grid.Row="2" 
       ItemsSource="{Binding Path=WorkItems}"> 
     <ListView.View> 
     <GridView> 
      <GridViewColumn Header="Name"> 
      <GridViewColumn.CellTemplate> 
       <DataTemplate> 
       <TextBlock Text="{Binding Path=Name}" /> 
       </DataTemplate> 
      </GridViewColumn.CellTemplate> 
      </GridViewColumn> 
      <GridViewColumn Header="Log Message"> 
      <GridViewColumn.CellTemplate> 
       <DataTemplate> 
       <TextBlock Text="{Binding Path=Logs, Converter={StaticResource ListToStringConverter}}" /> 
       </DataTemplate> 
      </GridViewColumn.CellTemplate> 
      </GridViewColumn> 
     </GridView> 
     </ListView.View> 
    </ListView> 
    </Grid> 
</Window> 

bộ chuyển đổi

using System; 
using System.Collections; 
using System.Globalization; 
using System.Linq; 
using System.Windows; 
using System.Windows.Data; 

namespace BindListToTextBlock 
{ 
    public class ListToStringConverter : IValueConverter 
    { 
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { 
     if (value is IEnumerable) { 
     return string.Join(Environment.NewLine, ((IEnumerable)value).OfType<string>().ToArray()); 
     } 
     return "no messages yet"; 
    } 

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { 
     return DependencyProperty.UnsetValue; 
    } 
    } 
} 

EDIT

đây là một giải pháp nhanh chóng cho propblem cập nhật (điều này cũng có thể được thực hiện với một tài sản gắn liền)

public class CustomTextBlock : TextBlock, INotifyPropertyChanged 
{ 
    public static readonly DependencyProperty ListToBindProperty = 
    DependencyProperty.Register("ListToBind", typeof(IBindingList), typeof(CustomTextBlock), new PropertyMetadata(null, ListToBindPropertyChangedCallback)); 

    private static void ListToBindPropertyChangedCallback(DependencyObject o, DependencyPropertyChangedEventArgs e) 
    { 
    var customTextBlock = o as CustomTextBlock; 
    if (customTextBlock != null && e.NewValue != e.OldValue) { 
     var oldList = e.OldValue as IBindingList; 
     if (oldList != null) { 
     oldList.ListChanged -= customTextBlock.BindingListChanged; 
     } 
     var newList = e.NewValue as IBindingList; 
     if (newList != null) { 
     newList.ListChanged += customTextBlock.BindingListChanged; 
     } 
    } 
    } 

    private void BindingListChanged(object sender, ListChangedEventArgs e) 
    { 
    this.RaisePropertyChanged("ListToBind"); 
    } 

    public IBindingList ListToBind 
    { 
    get { return (IBindingList)this.GetValue(ListToBindProperty); } 
    set { this.SetValue(ListToBindProperty, value); } 
    } 

    private void RaisePropertyChanged(string propName) 
    { 
    var eh = this.PropertyChanged; 
    if (eh != null) { 
     eh(this, new PropertyChangedEventArgs(propName)); 
    } 
    } 

    public event PropertyChangedEventHandler PropertyChanged; 
} 

ở đây là việc sử dụng cho CustomTextBlock (không kiểm tra)

<TextBlock Text="{Binding Path=ListToBind, RelativeSource=Self, Converter={StaticResource ListToStringConverter}}" 
      ListToBind={Binding Path=Logs} /> 

@Fueled niềm hy vọng này giúp

+0

Có cách giải quyết nào cho vấn đề này không? Tôi gặp vấn đề chính xác trong dự án đăng nhập của tôi. – Fueled

+0

@Fueled tôi đã cập nhật câu trả lời của tôi – punker76

+0

Cảm ơn, nhưng tôi đã kết thúc bằng cách sử dụng một MultiValueConverter và liên kết với thuộc tính Count của bộ sưu tập, có tác dụng cập nhật thuộc tính Văn bản mỗi khi bộ sưu tập cập nhật. Xem câu trả lời của tôi cho một câu hỏi tương tự khác: http://stackoverflow.com/questions/4353186/binding-observablecollection-to-a-textbox/8847910#8847910. – Fueled

1

Tôi sẽ không biết xấu hổ đăng liên kết tới câu trả lời của tôi về một câu hỏi rất giống: Binding ObservableCollection<> to a TextBox.

Giống như punker76 cho biết, nếu bạn liên kết Văn bản với bộ sưu tập, nó sẽ cập nhật khi bạn đặt bộ sưu tập, nhưng không phải khi bộ sưu tập thay đổi. Liên kết này thể hiện một giải pháp thay thế cho giải pháp của punker76 (mẹo này cũng liên quan đến số lượng bộ sưu tập).

0

Đối với bộ sưu tập của các đối tượng concat:

/// <summary>Convertisseur pour concaténer des objets.</summary> 
[ValueConversion(typeof(IEnumerable<object>), typeof(object))] 
public class ConvListToString : IValueConverter { 
    /// <summary>Convertisseur pour le Get.</summary> 
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { 
     return String.Join(", ", ((IEnumerable<object>)value).ToArray()); 
    } 
    /// <summary>Convertisseur inverse, pour le Set (Binding).</summary> 
    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { 
     throw new NotImplementedException(); 
    } 
} 

Juste nghĩ đến overide ToString() của đối tượng của bạn.

Các vấn đề liên quan