WPF TextBox绑定不会使用拖放进行更新

时间:2017-08-29 18:50:10

标签: c# wpf xaml data-binding

我有一个wpf项目,我有一个绑定文本框,AllowDrop设置为true。如果我直接在此文本框中键入并保留该框,则此文本框的绑定属性将按预期更改。

但是,如果我创建一个drop事件并将文本框的文本值设置为文件名值,则文本框绑定属性不会更改。我必须单击文本框并选中它。

我必须误解绑定属性应该如何工作。我的想法是,如果框的文本改变了,它也应该更新绑定属性。

现在看来,我必须让代码更新属性而不是依赖于绑定。以下是我创建的示例项目。

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>

以下是我的viewmodel

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

我尝试将绑定模式设置为twoway,以及其他绑定设置,而不会改变行为。我想要做的是弄清楚如何让drop功能就像手动输入框并离开框而不必绕过我的绑定并直接设置属性。

3 个答案:

答案 0 :(得分:4)

使ViewModel实现INotifyPropertyChanged。 而不是直接更改文本框的文本,而是更改viewModel中的fileName。这样就可以了。

您还必须在XMLFile-Property的setter中调用OnPropertyChanged

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 :(得分: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();

答案 2 :(得分: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();
}

希望这有帮助!