【问题标题】:Bind a List<string> to a TextBox将 List<string> 绑定到 TextBox
【发布时间】:2014-06-03 20:39:51
【问题描述】:

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

Codebehind 只需要绑定的数据属性和拖放代码即可。

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 调用的重要性。

【问题讨论】:

    标签: c# wpf binding textbox ivalueconverter


    【解决方案1】:

    要使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();
    

    【讨论】:

    • 感谢您的选择。要学习的东西太多了。不过,只需将其添加到 xaml 就会在转换器中引发空对象引用错误。 (程序启动时该值为 null。)我可以捕捉到它,但我想知道不同行为的原因是什么?我怀疑 xaml 现在被更早地调用了?
    • 我已经更新了您问题的答案。看看有没有帮助。
    【解决方案2】:

    必须设置 TextBox 的 DataContext 才能绑定数据。像这样:

        public MainWindow()
        {
            InitializeComponent();
            fileNames = new List<string>();
            this.tb_files.DataContext = this;
        }
    

    【讨论】:

    • 谢谢。实际上我在原始程序中有这一行。我发布的是精简版。但是现在我有了一个工作版本,我将能够使用原始代码追踪探针..
    【解决方案3】:

    这是适合您的一般模式。如果您有任何疑问,请联系我。祝你好运! ~贾斯汀

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

    【讨论】:

      猜你喜欢
      • 2016-01-02
      • 2013-12-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-05-03
      • 2011-11-11
      • 2011-02-10
      • 1970-01-01
      相关资源
      最近更新 更多