2014-04-19 16 views
2

經過20多年的編程窗口和WPF兩天我覺得我什麼都不知道:-)綁定列表<string>到一個TextBox

我的第一個WPF程序是非常簡單的:你從資源管理器拖放了一些文件和他們的名字顯示在一個TextBox控件中。 (對於ListBox來說,它工作正常,但這不是我想要的,當然在Drop事件中手動添加行也是可行的 - 但我想了解Binding方法..)

So我寫了一個轉換器,但不知怎麼它沒有使用(斷點不會被打),什麼也沒有顯示。

它應該是一件小事,或者我完全偏離軌道。找到了許多類似的東西的例子,我一起修補它,但仍然無法使它工作。

(我可能不會需要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> 

而且隨着罷了代碼隱藏data屬性結合並拖動&下降代碼,其中工程。

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

    } 
} 

注意:我已經editied的最後一塊代碼強調UpdateTarget呼叫重要性。

回答

2

必須將TextBox的DataContext設置爲綁定數據。像這樣:

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

謝謝。其實我原來的程序中有這條線。我發佈的是一個精簡版。但現在我有了一個工作版本,我將能夠用原始代碼追蹤探針(s)。 – TaW

3

對於Binding工作,你需要分配Window's DataContext到屬性駐留的實例,在你的情況下是窗口類本身。在構造函數中

所以設置的DataContext,它應該很好地工作:

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

OR

你必須在你的綁定使用ElementName明確解決從XAML綁定:

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

對於XAML的工作方法,您必須在XAML加載之前,即在InitializeComponent被調用之前,清零該列表。

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

感謝這個替代方案。非常需要學習..簡單地將它添加到xaml中會在轉換器中引發空對象引用錯誤。 (程序啓動時該值爲空。)我可以捕獲它,但我想知道不同行爲的原因是什麼?我懷疑xaml現在被調用了嗎? – TaW

+0

我已更新您的問題的答案。看看是否有幫助。 –

0

這是應該爲你工作的一般模式。如果您有任何疑問,請聯繫我。祝你好運! 〜賈斯汀

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