WPF文本块与List <string> </string>的绑定

时间:2008-12-05 22:26:32

标签: wpf generics text binding

有没有人知道是否有一种简单的方法将文本块绑定到List。 到目前为止我所做的是创建一个listview并将其绑定到List,然后我在listview中有一个使用单个文本块的模板。

我真正想要做的就是将List绑定到一个文本块并让它显示所有行。

在Winforms中有一个“Lines”属性,我可以将List放入,但我没有在WPF文本块或TextBox上看到它。

有什么想法吗?

我想念一些简单的事吗?

这是代码

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

和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;}

我正在使用Prism创建控件并将其放入WindowRegion

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

感谢

4 个答案:

答案 0 :(得分:32)

将List转换为单个字符串,其中“\ r \ n”作为其间的分隔符。并将其绑定到TextBlock。确保TextBlock的高度不受限制,以便它可以根据行数增长。 我将它实现为XAML Binding的值转换器,它将字符串列表转换为单个字符串,并在其间添加新行

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

ListToStringConverter看起来像这样:

[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();
    }
}

答案 1 :(得分:4)

如果您使用转换器,它首次完美工作, 但是如果一个或多个日志记录进入日志记录列表,则绑定没有更新,因为转换器仅在第一次运行时才起作用。 所有没有项控件的控件都不会订阅listchanged事件!

这是一个针对此场景的小代码

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>

转换器

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

修改

这是更新propblem的快速解决方案(也可以使用附加属性)

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

这是CustomTextBlock(未测试)

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

@Fueled希望这会有所帮助

答案 2 :(得分:2)

我会无耻地发布一个链接,回答我对一个非常相似的问题的回答:Binding ObservableCollection<> to a TextBox

就像punker76所说,如果你将Text绑定到一个集合,它将在你设置集合时更新,但是当集合发生变化时不会更新。此链接演示了punker76解决方案的替代方案(诀窍是多次绑定到集合的计数)。

答案 3 :(得分:0)

对于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想要覆盖你对象的ToString()。