2017-08-29 46 views
2

我有一個wpf項目,其中我有一個綁定的文本框已AllowDrop設置爲true。如果我直接在此文本框中鍵入並離開框,則此文本框的綁定屬性會按預期更改。WPF文本框綁定不會更新與拖放

但是,如果我創建拖放事件並將文本框的文本值設置爲文件名值,則文本框綁定屬性不會更改。我必須點擊文本框並將其標記出來。

我必須誤解如何綁定屬性應該工作。我的想法是,如果框中的文本發生變化,它也應該更新綁定屬性。

現在,我必須讓代碼更新屬性,而不是依賴綁定。以下是我創建的示例項目。

XAML: 
<Window.DataContext> 
    <local:XmlFile x:Name="XmlFileInfo"/> 
</Window.DataContext> 
... 
<StackPanel Orientation="Horizontal" Grid.Row="0"> 
     <Label Content="XML File:"/> 
     <TextBox x:Name="xmlFilePath" Text="{Binding XMLFile}" Height="25" VerticalAlignment="Top" MinWidth="300" AllowDrop="True" PreviewDragOver="xmlFilePath_PreviewDragOver" Drop="xmlFilePath_Drop"/> 
</StackPanel> 

而下面是我的視圖模型

public class XmlFile 
{ 
    private string _xmlfile; 
    private string _xmlElementName; 
    public string XMLFile 
    { 
     get { return _xmlfile; } 
     set 
     { 
      if (value != _xmlfile) 
      { 
       _xmlfile = value; 
       _xmlElementName = SetElementNameFromFileName(); 
      } 
     } 
    } 
... 
} 

最後我對XAML

public partial class MainWindow : Window 
{ 
    public MainWindow() 
    { 
     InitializeComponent(); 
    } 

    private void Exit_Click(object sender, RoutedEventArgs e) 
    { 
     Application.Current.Shutdown(); 
    } 

    private void SetControlState() 
    { 
     FileTest.IsEnabled = false; 
     if (!string.IsNullOrEmpty(XmlFileInfo.XMLFile)) 
     { 
      if(XmlFileInfo.IsValidXml(XmlFileInfo.XMLFile)) 
      { 
       FileTest.IsEnabled = true; 
      } 
     } 
    } 

    private void xmlFilePath_PreviewDragOver(object sender, DragEventArgs e) 
    { 
     e.Handled = true; 
    } 

    private void xmlFilePath_Drop(object sender, DragEventArgs e) 
    { 
     var filenames = (string[])e.Data.GetData(DataFormats.FileDrop); 
     if (filenames == null) return; 
     var filename = filenames.FirstOrDefault(); 
     if (filename == null) return; 
     //XmlFileInfo.XMLFile = filename; <-- This bypasses the binding 
     (sender as TextBox).Text = filename; // This should trigger updating binding 
     SetControlState(); //<-- enables a button control if file is valid 
    } 
} 

後面的代碼,我已經嘗試設置綁定模式,以雙向,和其他綁定設置沒有任何變化在行爲中。我想要做的是弄清楚如何讓拖放功能的行爲就像手動輸入框並離開框,而不必繞過我的綁定並直接設置屬性。

+2

是否有任何理由您的ViewModel沒有實現INotifyPropertyChanged? –

+2

您需要將INotifyOfPropertyChanged接口添加到您的類中 – sTrenat

+0

如果這是真的,那麼爲什麼手動輸入到文本框中工作? –

回答

4

使您的ViewModel實現INotifyPropertyChanged。 不是直接更改文本框的文本,而是更改viewModel中的fileName。這將做到這一點。

您也可以撥打OnPropertyChanged在你的二傳手XMLFILE-物業

public class XmlFile : INotifyPropertyChanged 
{ 
    private string _xmlfile; 
    private string _xmlElementName; 
    public string XMLFile 
    { 
     get { return _xmlfile; } 
     set 
     { 
      if (value != _xmlfile) 
      { 
       _xmlfile = value; 
       _xmlElementName = SetElementNameFromFileName(); 
       OnPropertyChanged(nameof(XMLFile); //this tells your UI to update 
      } 
     } 
    } 
... 
} 


private void xmlFilePath_Drop(object sender, DragEventArgs e) 
    { 
     var filenames = (string[])e.Data.GetData(DataFormats.FileDrop); 
     if (filenames == null) return; 
     var filename = filenames.FirstOrDefault(); 
     if (filename == null) return; 
     //XmlFileInfo.XMLFile = filename; <-- This bypasses the binding 
     var viewModel = (XmlFile)this.DataContext; 
     viewModel.XMLFile = filename; 
     SetControlState(); //<-- enables a button control if file is valid 
    } 

你應該有一個看看如何DataBinding作品。

+1

謝謝大家。令人困惑的是,wpf通過調用LostFocus和更新來處理手動輸入,但是丟棄不會。在我的「實時」代碼中,我有'INotifyPropertyChanged'設置,但不是在我創建的這個小測試項目中。然而,我遺漏的一點是drop方法調用viewmodel並通過viewmodel設置文件名。謝謝@Tobias。 –

1

什麼你要找的是以下內容:

 var textBox = sender as TextBox; 

     if (textBox == null) 
      return; 

     // Sets the value of the DependencyProperty without overwriting the value, this will also update the ViewModel/XmlFile that TextBox is bound to. 
     textBox.SetCurrentValue(TextBox.TextProperty, "My Test Value"); 

您還可以強制綁定通過以下更新目標(XMLFILE):

 var textBinding = textBox.GetBindingExpression(TextBox.TextProperty); 

     // This will force update the target (rather than wait until control loses focus) 
     textBinding?.UpdateTarget(); 
0

我有一種情況,我需要用文件路徑填充多個文本框。我使用了這裏提供的akjoshi的想法:Update ViewModel from View。我用以下方式實現它:

private void Text_Drop(object sender, DragEventArgs e) 
{ 
    TextBox temp = sender as TextBox; 
    if(temp == null) 
     return; 
    string[] tempArray = (string[])e.Data.GetData(DataFormats.FileDrop, false); 
    temp.Text = tempArray[0]; 
    sender = temp; 
    BindingExpression bind = BindingOperations.GetBindingExpression(temp, TextBox.TextProperty); 
    bind.UpdateSource(); 
} 

希望這有助於!