Wpf 绑定可观察集合<&燃气轮机;到文本框
我以Wpf 绑定可观察集合<&燃气轮机;到文本框,wpf,silverlight,data-binding,ivalueconverter,Wpf,Silverlight,Data Binding,Ivalueconverter,我以可观察集合的形式从web服务返回数据我想将集合绑定到只读文本框,以便用户可以选择并将数据复制到剪贴板 要将集合绑定到我创建的文本框的Text属性,请使用IValueConverter,该文本框将集合转换为文本字符串。这似乎是可行的,只是它只工作一次,就好像绑定不识别可观察集合的后续更改一样。下面是一个简单的应用程序,它重现了这个问题,只是为了确认绑定是否正常工作,我还绑定了一个“ListBox” 这是因为文本绑定简单不处理集合的更改事件吗 当然,我可以选择处理集合更改,并将这些更改传播到Te
可观察集合的形式从web服务返回数据
我想将集合绑定到只读文本框
,以便用户可以选择并将数据复制到剪贴板
要将集合绑定到我创建的文本框的Text属性,请使用IValueConverter
,该文本框将集合转换为文本字符串。这似乎是可行的,只是它只工作一次,就好像绑定不识别可观察集合的后续更改一样。下面是一个简单的应用程序,它重现了这个问题,只是为了确认绑定是否正常工作,我还绑定了一个“ListBox”
这是因为文本绑定简单不处理集合的更改事件吗
当然,我可以选择处理集合更改,并将这些更改传播到TextBox绑定到的文本属性中,这很好,但我想了解为什么我认为显而易见的解决方案没有按预期工作
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();
}
}
}
使用系统;
使用系统集合;
使用System.Collections.Generic;
使用System.Collections.ObjectModel;
使用系统文本;
使用System.Windows;
使用System.Windows.Data;
利用制度全球化;
命名空间WpfTextBoxBinding
{
///
///MainWindow.xaml的交互逻辑
///
公共部分类主窗口:窗口
{
公共ObservableCollection文本行{get;set;}
公共主窗口()
{
DataContext=this;
TextLines=新的ObservableCollection();
//添加一些初始数据,这表明
//文本框绑定第一次起作用
文本行。添加(“第一行”);
初始化组件();
}
私有无效按钮\u单击(对象发送者,路由目标e)
{
TextLines.Add(“Line:+TextLines.Count”);
}
}
公共类EnumarableToTextConverter:IValueConverter
{
公共对象转换(
对象值,类型targetType,
对象参数,CultureInfo(区域性)
{
if(值为IEnumerable)
{
StringBuilder sb=新的StringBuilder();
foreach(值为IEnumerable的var s)
{
某人追加(s.ToString());
}
使某人返回字符串();
}
返回字符串。空;
}
公共对象转换回(
对象值,类型targetType,
对象参数,CultureInfo(区域性)
{
抛出新的NotImplementedException();
}
}
}
这是因为文本绑定吗
simple不处理更改
收藏活动
的确如此。绑定仅在其源属性更改时更新。如果您通过设置一个全新的ObservableCollection
来更改TextLines
属性,并实现INotifyPropertyChanged
,您的绑定将按预期工作。只有当集合绑定到侦听集合更改的属性(如ItemsControl.ItemsSource
)时,向集合添加新元素才有意义
我当然有一个选择
处理集合更改和
将它们传播到文本属性
文本框绑定到的,即
好的
这将是另一个解决方案。更新下面的代码
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-如下图所示,在ViewModel中定义string类型的属性,并将此属性绑定到下图所示的textbox文本属性a,无需立即删除ValueConverter
public string TextLines {get;set;}
<TextBox Text="{Binding TextLines, Mode=OneWay/>
公共字符串文本行{get;set;}
实现这一点的一种稍微优雅的方法是对Text属性使用MultiBinding并绑定到集合的Count属性。这将在每次集合的计数更改时更新绑定,并根据您定义的多值转换器更新文本
<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();
}
}
公共静态类转换器
{
公共静态LogEntryCollectionToTextConverter LogEntryCollectionToTextConverter=新LogEntryCollectionToTextConverter();
}
公共类LogEntryCollectionToTextConverter:IMultiValueConverter
{
公共对象转换(对象[]值,类型targetType,对象参数,CultureInfo区域性)
{
ObservableCollection logEntries=作为ObservableCollection的值[0];
if(logEntries!=null&&logEntries.Count>0)
返回logEntries.ToString();
其他的
返回字符串。空;
}
公共对象[]转换回(对象值,类型[]目标类型,对象参数,CultureInfo区域性)
{
抛出新的NotImplementedException();
}
}
在我的用例中,我不允许文本框更新其源代码(因此使用“Mode=”OneWay“'),但如果需要,转换器的ConvertBack方法将处理该问题。您可能需要引发一个属性更改事件以更新文本框。@ChrisF,谢谢。我希望更改通知能通过绑定发送到文本框中。谢谢Julien,我希望我遗漏了一些东西,这会起作用。谢谢。在实际应用程序中,更新发生在视图模型中,视图模型不知道视图以及哪些控件绑定到属性。因此,我不能直接采用这种方法。很抱歉,我对这个问题的简单复制没有显示出设计的这一面。通常我会在我的视图上从我的vm和handel引发一个事件,这是一种黑客行为,并在我的视图和ViewModel之间创建一个绑定,但有时它不可能与MVVM 100%兼容,我可以告诉你一个典型的例子,比如处理DataGrid cell一级操作。但是在你的情况下,有可能不破坏MVVM,如果你想的话,我可以告诉你怎么做。