2010-12-04 93 views
9

我有数据从web服务以ObservableCollection<string>的形式返回,我想将该集合绑定到只读TextBox,以便用户可以选择并将数据复制到剪贴板。将ObservableCollection <>绑定到文本框

要获取绑定到TextBox的Text属性的集合,我创建了IValueConverter将集合转换为文本字符串。这似乎工作,只是它只能工作一次,就好像绑定不能识别对Observable集合的后续更改。这是一个复制问题的简单应用程序,只是为了确认绑定工作正常,我也绑定到一个`ListBox'

这是因为文本绑定简单不处理集合的更改事件?

当然,我可以选择一个选项来处理集合更改,并将它们传播给TextBox绑定到的Text属性,这很好,但我想了解为什么我觉得这是一个明显的解决方案无法按预期工作。

XAML

<Window x:Class="WpfTextBoxBinding.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:local="clr-namespace:WpfTextBoxBinding" 
     Title="MainWindow" Height="331" Width="402"> 
    <StackPanel> 
    <StackPanel.Resources> 
     <local:EnumarableToTextConverter x:Key="EnumarableToTextConverter" /> 
    </StackPanel.Resources> 
    <TextBox Text="{Binding TextLines, Mode=OneWay, Converter={StaticResource EnumarableToTextConverter}}" Height="100" /> 
    <ListBox ItemsSource="{Binding TextLines}" Height="100" /> 
    <Button Click="Button_Click" Content="Add Line" /> 
    </StackPanel > 
</Window> 

代码隐藏

using System; 
using System.Collections; 
using System.Collections.Generic; 
using System.Collections.ObjectModel; 
using System.Text; 
using System.Windows; 
using System.Windows.Data; 
using System.Globalization; 

namespace WpfTextBoxBinding 
{ 
    /// <summary> 
    /// Interaction logic for MainWindow.xaml 
    /// </summary> 
    public partial class MainWindow : Window 
    { 
    public ObservableCollection<string> TextLines {get;set;} 

    public MainWindow() 
    { 
     DataContext = this; 

     TextLines = new ObservableCollection<string>(); 

     // Add some initial data, this shows that the 
     // TextBox binding works the first time  
     TextLines.Add("First Line"); 

     InitializeComponent();  
    } 

    private void Button_Click(object sender, RoutedEventArgs e) 
    { 
     TextLines.Add("Line :" + TextLines.Count); 
    } 
    } 

    public class EnumarableToTextConverter : IValueConverter 
    { 
    public object Convert(
     object value, Type targetType, 
     object parameter, CultureInfo culture) 
    { 
     if (value is IEnumerable) 
     { 
     StringBuilder sb = new StringBuilder(); 
     foreach (var s in value as IEnumerable) 
     { 
      sb.AppendLine(s.ToString()); 
     } 
     return sb.ToString(); 
     } 
     return string.Empty; 
    } 

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

您可能需要为要更新的文本框引发属性更改的事件。 – ChrisF 2010-12-04 11:16:01

+0

@ChrisF,谢谢。我希望通过绑定将更改通知传播到TextBox。 – 2010-12-04 11:24:53

回答

5

这是因为文本结合 简单不处理收集的变化 事件?

确实。绑定只有在其源属性发生更改时才会更新。如果通过设置全新的ObservableCollection并执行INotifyPropertyChanged来更改TextLines属性,则您的绑定将按预期工作。向集合中添加新元素只有在绑定到类似ItemsControl.ItemsSource这样的属性以侦听集合更改时才会有意义。当然

一种选择将是对我 处理收集的变化和 传播完成那些Text属性 该文本框结合了,这是 罚款。

这将是另一种解决方案。

+0

谢谢朱利安,我希望我错过了一些东西,这只是工作。 – 2010-12-04 11:23:13

0

以下代码

private void Button_Click(object sender, RoutedEventArgs e) 
    { 
     TextLines.Add("Line :" + TextLines.Count); 
     BindingExpression be = BindingOperations.GetBindingExpression(txtName, TextBox.TextProperty); 
     be.UpdateTarget(); 
    } 

更新其中txtName的是如下并结合示出的文本框的

MVVM方式

1- Difine在你的ViewModel字符串类型的属性的名称此属性为下面显示的文本框文本属性,并且现在不需要移除ValueConverter。

public string TextLines {get;set;} 

<TextBox Text="{Binding TextLines, Mode=OneWay/> 

2 - 我想,你最有可能使用一个命令处理程序说你的命令是AddMoreLines

所以在AddMoreLine命令处理程序,在您的OBservrableCollection添加新对象后,创建一个处理按钮单击事件StringBuilder并追加您Collection的所有内容,并将字符串分配给在步骤1中创建的属性。

3-调用PropertyChanged Handler。

4

稍微更优雅的方法是在Text属性上使用MultiBinding并绑定到Collection的Count属性。这将在每次集合的计数发生更改时更新绑定,并根据您定义的MultiValueConverter更新文本。

<TextBox> 
    <TextBox.Text> 
     <MultiBinding Converter="{x:Static l:Converters.LogEntryCollectionToTextConverter}"> 
      <Binding Path="LogEntries" Mode="OneWay"/> 
      <Binding Path="LogEntries.Count" Mode="OneWay" /> 
     </MultiBinding> 
    </TextBox.Text> 
</TextBox> 

和转换器:

public static class Converters 
{ 
    public static LogEntryCollectionToTextConverter LogEntryCollectionToTextConverter = new LogEntryCollectionToTextConverter(); 
} 

public class LogEntryCollectionToTextConverter : IMultiValueConverter 
{ 
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) 
    { 
     ObservableCollection<LogEntry> logEntries = values[0] as ObservableCollection<LogEntry>; 

     if (logEntries != null && logEntries.Count > 0) 
      return logEntries.ToString(); 
     else 
      return String.Empty; 
    } 

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) 
    { 
     throw new NotImplementedException(); 
    } 
} 

在我的使用情况下,我不容许的文本框,以更新其源(因此'Mode =“单向”'),但如果需要的话Converter的ConvertBack方法将处理该问题。

相关问题