数据绑定到 WPF 中的方法

发布于 2024-08-21 23:33:13 字数 2696 浏览 2 评论 0原文

我在将 TextBox.Text 属性数据绑定到对象的方法时遇到问题。这个想法是允许用户在 TextBox 中写入文件名,然后使用 TextBlock 输出该文件的扩展名。

class GetFileInfo
{
    public string GetFileExtension(string fileName)
    {
        return Path.GetExtension(fileName);
    }
}

这是我的 XAML:

<Window.Resources>
    <ObjectDataProvider x:Key="getFileInfo" MethodName="GetFileExtension" ObjectType="{x:Type local:GetFileInfo}">
        <ObjectDataProvider.MethodParameters>
            <sys:String>abc.text</sys:String>
        </ObjectDataProvider.MethodParameters>
    </ObjectDataProvider>
</Window.Resources>

<StackPanel>
    <TextBox Name="textBox1">
        <TextBox.Text>
            <Binding Source="{StaticResource getFileInfo}" Path="MethodParameters[0]" BindsDirectlyToSource="True" UpdateSourceTrigger="PropertyChanged" />
        </TextBox.Text>
    </TextBox>
    <TextBlock Name="textBlock1" Text="{Binding Source={StaticResource getFileInfo}}"/>
</StackPanel>

由于某种原因,它没有执行任何操作。有知道的可以指出可能是什么原因吗? 以下是我在设计器上以及运行应用程序时看到的内容:

替代文字

这是当我尝试在运行时设置其他文本时发生的情况:

替代文本以下是调试器在运行时尝试设置其他文本时给出的错误:

System.Windows.Data 错误:8:无法将值从目标保存回源。 BindingExpression:Path=方法参数[0]; DataItem='ObjectDataProvider' (HashCode=2207369);目标元素是“TextBox”(名称=“textBox1”);目标属性为“Text”(类型“String”)ArgumentException:“System.ArgumentException:类型为“MS.Internal.Data.PropertyPathWorker + IListIndexerArg”的对象无法转换为类型“System.Int32”。 在System.RuntimeType.TryChangeType(对象值,Binder活页夹,CultureInfo文化,布尔需要SpecialCast) 在 System.RuntimeType.CheckValue(对象值,活页夹活页夹,CultureInfo 区域性,BindingFlags invokeAttr) 在System.Reflection.MethodBase.CheckArguments(Object []参数,Binder活页夹,BindingFlags invokeAttr,CultureInfo文化,签名sig) 在System.Reflection.RuntimeMethodInfo.Invoke(对象obj,BindingFlags invokeAttr,Binder活页夹,Object []参数,CultureInfo文化,布尔skipVisibilityChecks) 在System.Reflection.RuntimeMethodInfo.Invoke(对象obj,BindingFlags invokeAttr,Binder活页夹,Object []参数,CultureInfo文化) 在System.Reflection.RuntimePropertyInfo.SetValue(对象obj,对象值,BindingFlags invokeAttr,活页夹活页夹,对象[]索引,CultureInfo文化) 在 MS.Internal.Data.PropertyPathWorker.SetValue(对象项,对象值) 在 MS.Internal.Data.ClrBindingWorker.UpdateValue(对象值) 在 System.Windows.Data.BindingExpression.UpdateSource(对象值)'

I am having trouble databinding a TextBox.Text property to a object's method. The idea is allowing the user to write in a TextBox a file name and then have a TextBlock output that file's extension.

class GetFileInfo
{
    public string GetFileExtension(string fileName)
    {
        return Path.GetExtension(fileName);
    }
}

Here is my XAML:

<Window.Resources>
    <ObjectDataProvider x:Key="getFileInfo" MethodName="GetFileExtension" ObjectType="{x:Type local:GetFileInfo}">
        <ObjectDataProvider.MethodParameters>
            <sys:String>abc.text</sys:String>
        </ObjectDataProvider.MethodParameters>
    </ObjectDataProvider>
</Window.Resources>

<StackPanel>
    <TextBox Name="textBox1">
        <TextBox.Text>
            <Binding Source="{StaticResource getFileInfo}" Path="MethodParameters[0]" BindsDirectlyToSource="True" UpdateSourceTrigger="PropertyChanged" />
        </TextBox.Text>
    </TextBox>
    <TextBlock Name="textBlock1" Text="{Binding Source={StaticResource getFileInfo}}"/>
</StackPanel>

For some reason it is not doing anything. Anyknow could point out what may be the reasons?
Here is what I see on the designer and when I run the application:

alt text

And here is what happens when I try setting other text at run-time:

alt text

Here is the error given by de debugger when trying to set other text at run-time:

System.Windows.Data Error: 8 : Cannot save value from target back to source. BindingExpression:Path=MethodParameters[0]; DataItem='ObjectDataProvider' (HashCode=2207369); target element is 'TextBox' (Name='textBox1'); target property is 'Text' (type 'String') ArgumentException:'System.ArgumentException: Object of type 'MS.Internal.Data.PropertyPathWorker+IListIndexerArg' cannot be converted to type 'System.Int32'.
at System.RuntimeType.TryChangeType(Object value, Binder binder, CultureInfo culture, Boolean needsSpecialCast)
at System.RuntimeType.CheckValue(Object value, Binder binder, CultureInfo culture, BindingFlags invokeAttr)
at System.Reflection.MethodBase.CheckArguments(Object[] parameters, Binder binder, BindingFlags invokeAttr, CultureInfo culture, Signature sig)
at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture, Boolean skipVisibilityChecks)
at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at System.Reflection.RuntimePropertyInfo.SetValue(Object obj, Object value, BindingFlags invokeAttr, Binder binder, Object[] index, CultureInfo culture)
at MS.Internal.Data.PropertyPathWorker.SetValue(Object item, Object value)
at MS.Internal.Data.ClrBindingWorker.UpdateValue(Object value)
at System.Windows.Data.BindingExpression.UpdateSource(Object value)'

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

脱离于你 2024-08-28 23:33:13

虽然可以使用 Binding 来调用方法并获取其返回值,但这并不简单。绑定到属性以及使用绑定和更改通知的组合来获取您正在寻找的结果要简单得多。

创建一个具有两个属性的类:FilenameExtensionFilename 只是一个读/写字符串属性。 Extension 是一个只读字符串属性,其 getter 会调用您尝试调用的方法。

现在让该类实现 INotifyPropertyChanged,因为如果属性可以在代码中更改,则它需要一种方法来告诉绑定它已经这样做了。让 Filename 属性的 setter 通知绑定 Extension 属性已更改。

Binding 添加到 TextBox,使用 TwoWay 模式绑定到 Filename 属性。将 Binding 添加到使用默认 OneWay 模式绑定到 ExtensionTextBox

事件顺序是:

  1. 用户在绑定的 TextBox 中键入新的 Filename 并按 TAB 键。
  2. TextBox 失去焦点。
  3. 因为 Binding 的模式是 TwoWay,并且它使用在目标失去焦点时更新源的默认行为,所以它就是这么做的。
  4. Binding 通过调用 Filename setter 来更新源。
  5. Filename setter 引发 PropertyChanged
  6. Binding 处理 PropertyChanged,查看其参数,并发现 Extension 属性已更改。
  7. Binding 调用Extension 属性的 getter。
  8. Extension 属性的 getter 调用该方法来确定 Filename 的扩展名,并将其返回给 Binding
  9. Binding 使用 Extension 的新值更新其目标 TextBox

这是数据绑定和 MVVM 模式的核心概念。一旦你理解了它,它就会成为你的第二天性,WPF 开发变得简单一千万倍。

While it's possible to use Binding to call a method and get its return value, it's not straightforward. It's much simpler to bind to properties, and to use the combination of binding and change notification to get the result you're looking for.

Create a class with two properties, Filename and Extension. Filename is just a read/write string property. Extension is a read-only string property whose getter calls the method that you're trying to call.

Now make that class implement INotifyPropertyChanged, because if a property can change in code, it needs a way of telling the binding that it has done so. Make the setter of the Filename property notify bindings that the Extension property has changed.

Add a Binding to a TextBox that binds to the Filename property using the TwoWay mode. Add a Binding to a TextBox that binds to Extension using the default OneWay mode.

The sequence of events is:

  1. User types a new Filename into a bound TextBox and presses TAB.
  2. The TextBox loses focus.
  3. Because the Binding's mode is TwoWay, and it's using the default behavior of updating the source when the target loses focus, that's what it does.
  4. The Binding updates the source by calling the Filename setter.
  5. The Filename setter raises PropertyChanged.
  6. The Binding handles PropertyChanged, looks at its argument, and sees that the Extension property has changed.
  7. The Binding calls the Extension property's getter.
  8. The Extension property's getter calls the method to determine the extension for Filename, and returns it to the Binding.
  9. The Binding updates its target TextBox with the new value of Extension.

This is the core concept underlying data binding and the MVVM pattern. Once you understand it, it becomes second nature, and WPF development becomes about ten million times easier.

烟─花易冷 2024-08-28 23:33:13

看来你需要了解一下MVVM,看看这篇经典文章
http://msdn.microsoft.com/en-us/magazine/dd419663。 ASPX

Looks like you need to get an understanding of MVVM , check this classic article
http://msdn.microsoft.com/en-us/magazine/dd419663.aspx

汐鸠 2024-08-28 23:33:13

数据绑定要求在更新源时调用 NotifyPropertyChanged 事件。在这种情况下,您需要将此函数调用包装在 get/set 中,如下所示:



public class FileWrapper: System.ComponentModel.INotifyPropertyChanged{
    private string m_filename;

    public string FileExtension{
        get{ return GetFileExtension(FileName);}
    }

    public string FileName{
        get{ return m_filename;}
        set{ m_filename = value; OnPropertyChanged("FileName"); OnPropertyChanged( "FileExtension");
    }

    public string GetFileExtension( string filename){
        //implementation
    }

    public event System.ComponentModel.NotifyPropertyChangedEvent PropertyChanged = (a,b)=>{};

    protected void OnPropertyChanged(string property){
        PropertyChanged( this, new System.ComponentModel.PropertyChangedEventArgs( property ));
    }
}

Databinding requires the NotifyPropertyChanged event to be called when the source is updated. In this case, you'd want to wrap this function call in a get/set like so:



public class FileWrapper: System.ComponentModel.INotifyPropertyChanged{
    private string m_filename;

    public string FileExtension{
        get{ return GetFileExtension(FileName);}
    }

    public string FileName{
        get{ return m_filename;}
        set{ m_filename = value; OnPropertyChanged("FileName"); OnPropertyChanged( "FileExtension");
    }

    public string GetFileExtension( string filename){
        //implementation
    }

    public event System.ComponentModel.NotifyPropertyChangedEvent PropertyChanged = (a,b)=>{};

    protected void OnPropertyChanged(string property){
        PropertyChanged( this, new System.ComponentModel.PropertyChangedEventArgs( property ));
    }
}

余厌 2024-08-28 23:33:13

好吧,这似乎是运行 WPF 4.0 时的一个错误,可以在此处。

哎呀,我有点仓促了.. 只要您为 3.5 框架(在 VS 2010 中)编译该示例,它就可以完美运行。
但是,如果将其转换为 WPF 4.0 项目,则当您编辑文本框时,将不再在 odp2 上调用 ObjectDataProvider 上的 WeightOnPlanet 方法。
我尝试在 Binding 或 ObjectDataProvider 上找到任何新属性 - 但到目前为止还没有任何结果......

在 3.5 中编译时,它在这里工作得很好。

Ok, seems like this a bug when running WPF 4.0, as can be seen in comments here.

Woops, I was a bit hasty .. the example works perfectly as long you compile it for the 3.5 framework (in VS 2010).
But if you convert it to WPF 4.0 project the method WeightOnPlanet on ObjectDataProvider is nolonger invoked on odp2 when you edit the textbox.
I have tried to find any new Attributes on either the Binding or the ObjectDataProvider – but nothing has worked out so far …

When compiling in 3.5, it works fine here.

偏爱你一生 2024-08-28 23:33:13

DataContext 是否已设置?在您的代码隐藏中,您是否将 TextBlock 的值设置为“saadsas”(我只能猜测),这破坏了您的数据绑定?

Is the DataContext set? In your code-behind, did you set the value for your TextBlock to "saadsas" (I can only guess), which broke your databinding?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文