简体   繁体   English

WPF文本框绑定不会通过拖放更新

[英]WPF TextBox Binding does not update with Drag and Drop

I have a wpf project where I have a bound text box that has AllowDrop set to true. 我有一个wpf项目,其中有一个绑定的文本框,其中AllowDrop设置为true。 If I type directly into this text box and leave the box, the bound property for this text box changes as expected. 如果我直接在此文本框中键入内容并离开该框,则此文本框的bound属性会按预期更改。

However, if I create a drop event and set the text value for the text box to the filename value, the text box bound property does not change. 但是,如果我创建放置事件并将文本框的文本值设置为文件名值,则文本框的绑定属性不会更改。 I have to click into the text box and tab out of it. 我必须单击进入文本框并从中跳出标签。

I must be misunderstanding how bound properties should work. 我一定会误解绑定属性应如何工作。 My thinking was that if the text of the box changes that it should update the bound property as well. 我的想法是,如果框的文本更改,那么它也应该更新绑定的属性。

As it stands now, I have to have the code behind update the property rather than rely upon the binding. 就目前而言,我必须拥有更新属性的背后代码,而不是依赖于绑定。 Below is from a sample project I created. 以下是我创建的示例项目。

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>

And below is my viewmodel 下面是我的视图模型

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

And finally my code behind for XAML 最后是我的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
    }
}

I have tried setting the binding mode to twoway, and other binding settings without any change in behavior. 我尝试将绑定模式设置为双向,并且其他绑定设置未更改任何行为。 What I would like to do is figure out how to get the drop functionality to act just like manually typing into the box and leaving the box without having to bypass my binding and directly setting the property. 我想做的是弄清楚如何使放置功能发挥作用,就像手动键入框并离开框一样,而不必绕开绑定并直接设置属性。

Make your ViewModel implement INotifyPropertyChanged. 使您的ViewModel实现INotifyPropertyChanged。 Instead of directly changing the text of your textbox change the fileName in your viewModel. 与其直接更改文本框的文本,不如更改viewModel中的fileName。 That will do the trick. 这样就可以了。

You also have to call OnPropertyChanged in the setter of your XMLFile-Property 您还必须在XMLFile-Property的设置器中调用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
    }

You should have a look at how DataBinding works. 您应该看看DataBinding是如何工作的。

What you're looking for is the following: 您要寻找的是以下内容:

        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");

You can also force the binding to update the target(XmlFile) by the following: 您还可以通过以下方式强制绑定更新目标(XmlFile):

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

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

I had a situation where I needed to populate multiple textboxes with filepaths. 我遇到一种情况,需要用文件路径填充多个文本框。 I used the ideas from akjoshi presented here: Update ViewModel from View . 我使用了akjoshi中提出的想法: 从View更新ViewModel I implemented it in the following way: 我通过以下方式实现了它:

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

Hope this helps! 希望这可以帮助!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM