wpf 将 List<string> 绑定到 TextBox

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/23169330/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-13 11:35:05  来源:igfitidea点击:

Bind a List<string> to a TextBox

c#wpfbindingtextboxivalueconverter

提问by TaW

After 20+ years of windows programming and two days of WPF I feel I know nothing :-)

经过 20 多年的 Windows 编程和两天的 WPF 我觉得我一无所知:-)

My first WPF program is really simple: You drop a few files from explorer and their names are shown in a TextBox control. (It works fine for a ListBox, but that isn't what I want. And of course adding the lines manually in the Drop event works as well - but I want to learn about the Binding ways..)

我的第一个 WPF 程序非常简单:从资源管理器中删除一些文件,它们的名称显示在 TextBox 控件中。(它适用于 ListBox,但这不是我想要的。当然,在 Drop 事件中手动添加行也有效 - 但我想了解绑定方式..)

So I wrote a Converter but somehow it insn't used (breakpoints won't get hit) and nothing shows up.

所以我写了一个转换器,但不知何故它没有被使用(断点不会被击中)并且没有任何显示。

It should be a small thing or maybe I'm totally off track. Found many examples for similar things from which i patched this together but still can't get it to work.

这应该是一件小事,或者我可能完全偏离了轨道。找到了许多类似事物的示例,我从中将其修补在一起,但仍然无法使其正常工作。

(I probably won't need the ConvertBack, but wrote it down anyway..)

(我可能不需要 ConvertBack,但无论如何还是把它写下来......)

Here is the converter class:

这是转换器类:

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

}

The MainWindow.xaml, where I suspect the binding problem to be:

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>

And the Codebehind with nothing more the the data property to bind to and the drag&drop code, which works.

而代码隐藏仅包含要绑定到的数据属性和拖放代码,该代码有效。

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

    }
}

Note: I have editied the last piece of code to stress the importance of the UpdateTargetcall.

注意:我编辑了最后一段代码以强调UpdateTarget调用的重要性。

回答by Rohit Vats

For Bindingto work you need to assign Window's DataContextto the instance where property resides which in your case is Window class itself.

为了Binding工作,您需要分配Window's DataContext给属性所在的实例,在您的情况下是 Window 类本身。

So set DataContext in constructor and it should work fine:

所以在构造函数中设置 DataContext ,它应该可以正常工作:

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

OR

或者

You have to explicitly resolve the binding from XAML using ElementNamein your binding:

您必须在绑定中使用 XAML 显式解析ElementName绑定:

<Window x:Name="myWindow">
  ....
  <TextBox Text="{Binding Path=fileNames, ElementName=myWindow,
                          Converter={StaticResource converter1}}"/>

For XAML approach to work, you have to initialize the list before XAML gets loaded i.e. before InitializeComponentgets called.

要使 XAML 方法起作用,您必须在加载 XAML 之前即在InitializeComponent调用之前初始化列表。

fileNames = new List<string>();
InitializeComponent();

回答by Martijn van Put

The DataContext of the TextBox must be set to bind the data. Like this:

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

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

回答by Justin

this is the general pattern which should work for you. Feel free to contact me with any questions. Best of luck! ~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();
    }
}