绑定列表<;字符串>;到文本框
本文关键字:文本 gt 字符串 lt 绑定 列表 | 更新日期: 2023-09-27 17:59:10
经过20多年的windows编程和两天的WPF,我觉得自己什么都不知道:-)
我的第一个WPF程序非常简单:从资源管理器中删除一些文件,它们的名称显示在TextBox控件中。(它适用于ListBox,但这不是我想要的。当然,在Drop事件中手动添加行也可以,但我想了解绑定方式。)
所以我写了一个转换器,但不知怎么的,它没有被使用(断点不会被击中),什么都没有显示。
这应该是一件小事,或者我完全偏离了轨道。找到了许多类似的例子,我从中拼凑了这些,但仍然无法使其发挥作用。
(我可能不需要ConvertBack,但无论如何都要写下来。)
这是转换器类别:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Data;
namespace WpTest02
{
public class ListToTextConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
StringBuilder sb = new StringBuilder();
foreach (string s in (List<string>)value) sb.AppendLine(s);
return sb.ToString();
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
string[] lines = ((string)value).Split(new string[] { @"'r'n" }, StringSplitOptions.RemoveEmptyEntries);
return lines.ToList<String>();
}
}
}
MainWindow.xaml,我怀疑绑定问题是:
<Window x:Class="WpTest02.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpTest02"
Title="MainWindow" Height="350" Width="525"
>
<Window.Resources>
<local:ListToTextConverter x:Key="converter1" />
</Window.Resources>
<Grid >
<TextBox Name="tb_files" Margin="50,20,0,0" AllowDrop="True"
PreviewDragOver="tb_files_PreviewDragOver" Drop="tb_files_Drop"
Text="{Binding Path=fileNames, Converter={StaticResource converter1} }"
/>
</Grid>
</Window>
而Codebehin除了要绑定的数据属性和拖放之外,什么都没有;丢弃代码,这是有效的。
using System;
//etc ..
namespace WpTest02
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
fileNames = new List<string>();
}
public List<string> fileNames { get; set; }
private void tb_files_Drop(object sender, DragEventArgs e)
{
var files = ((DataObject)e.Data).GetFileDropList();
foreach (string s in files) fileNames.Add(s);
// EDIT: this doesn't help ? Wrong!
// EDIT: this is actually necessary! :
tb_files.GetBindingExpression(TextBox.TextProperty).UpdateTarget();
// this obviosly would work:
//foreach (string s in files) tb_files.Text += s + "'r'n";
}
private void tb_files_PreviewDragOver(object sender, DragEventArgs e)
{
e.Handled = true;
}
}
}
注意:我已经编辑了最后一段代码来强调UpdateTarget
调用的重要性。
要使Binding
工作,您需要将Window's DataContext
分配给属性所在的实例,在您的情况下,该实例就是Window类本身。
所以在构造函数中设置DataContext,它应该可以正常工作:
public MainWindow()
{
InitializeComponent();
fileNames = new List<string>();
DataContext = this;
}
或
您必须在绑定中使用ElementName
从XAML显式解析绑定:
<Window x:Name="myWindow">
....
<TextBox Text="{Binding Path=fileNames, ElementName=myWindow,
Converter={StaticResource converter1}}"/>
为了使XAML方法发挥作用,您必须在加载XAML之前初始化列表,即在调用InitializeComponent
之前。
fileNames = new List<string>();
InitializeComponent();
必须设置TextBox的DataContext才能绑定数据。像这样:
public MainWindow()
{
InitializeComponent();
fileNames = new List<string>();
this.tb_files.DataContext = this;
}
这是适用于您的通用模式。如有任何问题,请随时与我联系。祝你好运~Justin
<Window xmlns:vm="clr-namespace:YourProject.YourViewModelNamespace"
xmlns:vc="clr-namespace:YourProject.YourValueConverterNamespace">
<Window.Resources>
<vc:YourValueConverter x:key="YourValueConverter" />
</Window.Resources>
<Window.DataContext>
<vm:YourViewViewModel />
</Window.DataContext>
<TextBox Text="{Binding MyItems, Converter={StaticResource YourValueConverter}}"/>
</Window>
public class YourViewViewModel : ViewModelBase
{
ObservableCollection<string> _myItems;
ObservableCollection<string> MyItems
{
get { return _gameProfileListItems; }
set { _gameProfileListItems = value; OnPropertyChanged("MyItems"); }
}
public void SetMyItems()
{
// go and get your data here, transfer it to an observable collection
// and then assign it to this.GameProfileListItems (i would recommend writing a .ToObservableCollection() extension method for IEnumerable)
this.MyItems = SomeManagerOrUtil.GetYourData().ToObservableCollection();
}
}
public class YourView : Window
{
YourViewViewModel ViewModel
{
{ get return this.DataContext as YourViewViewModel; }
}
public void YourView()
{
InitializeComponent();
InitializeViewModel();
}
void InitializeViewModel()
{
this.ViewModel.SetMyItems();
}
}