15

テキストブロックをリストにバインドする簡単な方法があるかどうかは誰にもわかりません。これまでに行ったことは、リストビューを作成してリストにバインドし、リストビュー内に単一のテキストブロックを使用するテンプレートを作成することです。

私が本当にやりたいことは、リストをテキストブロックにバインドして、すべての行を表示させることです。

Winforms には、リストをスローできる "Lines" プロパティがありましたが、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

4 に答える 4

36

リストを区切り文字として「\r\n」を使用して単一の文字列に変換します。それを TextBlock にバインドします。TextBlock が高さで制限されていないことを確認して、行数に基づいて拡大できるようにします。これを、文字列のリストを間に改行を追加して単一の文字列に変換する XAML バインディングへの値コンバーターとして実装します。

<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();
    }
}
于 2008-12-05T23:35:29.147 に答える
5

コンバーターを使用すると、初めて完全に機能しますが、1 つ以上のログがログ リストに表示された場合、コンバーターは初回のみ機能するため、バインディングは更新されません。項目コントロールではないすべてのコントロールは、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;
    }
  }
}

編集

ここに更新の問題の簡単な解決策があります(これは添付プロパティでも作成できます)

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これが役立つことを願っています

于 2011-11-09T08:20:06.823 に答える
2

非常によく似た質問の回答へのリンクを恥知らずに投稿します: Binding ObservableCollection<> to a TextBox

punker76 が言ったように、テキストをコレクションにバインドすると、コレクションを設定すると更新されますが、コレクションが変更されたときは更新されません。このリンクは、punker76 のソリューションに代わる方法を示しています (秘訣は、コレクションのカウントにもマルチバインドすることです)。

于 2012-01-24T14:20:39.100 に答える
0

オブジェクトの連結コレクションの場合:

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

オブジェクトの ToString() をオーバーライドすることを考えてみてください。

于 2015-12-31T09:05:13.963 に答える