本文介绍了如何绑定Binding.Path属性到底层数据?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图以非常动态的方式绑定TextBlock的Text属性。我需要从基础对象获取路径。



这是DataTemplate:

 < DataTemplate DataType = {x:Type local:DummyClass}> 
< TextBlock Text = {Binding Path = ???} />
< / DataTemplate>

DummyClass对象有一个名为FieldValuePath的属性 - 需要放在哪里的路径? ??是的



背后的想法是数据模板应该是用于查看/编辑任何对象的任何属性的GUI。所以最好能够声明XAML,它会将一些控件(文本框,文本框,日期戳等)绑定到给定的属性。



也许有人有任何建议关于如何实现这样的事情?

解决方案

如果你在代码背后创建绑定,那么你可以让它工作。例如,一个简单的代码生成绑定是:

 绑定绑定=新绑定(BindingPath); 
binding.Mode = BindingMode.TwoWay;
BindingOperations.SetBinding(textBoxName,TextBox.TextProperty,binding);

由于此绑定(BindingPath)中的路径只是一个字符串,该字符串可能来自任何可用的对象。



您需要挂接创建数据项才能设置这些绑定。






根据您的意见,进一步的可能性:



概述了一种通过从MarkupExtension继承来创建自定义绑定类的方法。您可能可以使用此作为起点,将您的建议包装成可重用的xaml标记,用于您的特殊绑定案例。






更多的想法:



好的,这是一个有趣的问题,所以我决定花点时间看看我能否提出一个可行的解决方案。对于以下代码示例的长度,我提前道歉...



将我的解决方案与我上面链接的博客文章一起创建了这个类:

  public class IndirectBinder:MarkupExtension 
{
public string IndirectProperty {get;组;

public override object ProvideValue(IServiceProvider serviceProvider)
{
//尝试为我们的自定义工作获取绑定项
DependencyObject targetObject;
DependencyProperty targetProperty;
bool status = TryGetTargetItems(serviceProvider,out targetObject,out targetProperty);

if(status)
{
控制targetControl = targetObject作为控件;
if(targetControl == null)return null;

//查找从
对象获取绑定的对象dataContext = targetControl.DataContext;
if(dataContext == null)return null;

//反映间接属性并获取值
PropertyInfo pi = dataContext.GetType()。GetProperty(IndirectProperty);
if(pi == null)return null;

string realProperty = pi.GetValue(dataContext,null)as string;
if(realProperty == null)返回null;

//根据内部属性创建绑定
绑定绑定= new Binding(realProperty);
binding.Mode = BindingMode.TwoWay;
BindingOperations.SetBinding(targetObject,targetProperty,binding);

//返回绑定的初始值
PropertyInfo realPi = dataContext.GetType()。GetProperty(realProperty);
if(realPi == null)return null;

return realPi.GetValue(dataContext,null);

}

返回null;

}

protected virtual bool TryGetTargetItems(IServiceProvider provider,out DependencyObject target,out DependencyProperty dp)
{
target = null;
dp = null;
if(provider == null)return false;

//创建绑定并将其分配给目标
IProvideValueTarget service =(IProvideValueTarget)provider.GetService(typeof(IProvideValueTarget));
if(service == null)return false;

//我们需要依赖对象/属性
target = service.TargetObject作为DependencyObject;
dp = service.TargetProperty作为DependencyProperty;
return target!= null&& dp!= null;
}

您可以使用这个新的标记与以下xaml:

 < TextBox Text ={local:IndirectBinder IndirectProperty = FieldValuePath}/> 

其中TextBox可以是继承自控件的任何类,Text可以是任何依赖属性。 >

显然,如果您需要暴露任何其他数据绑定选项(例如一种或两种方式绑定),则需要向该类添加更多属性。



虽然这是一个复杂的解决方案,但它使用转换器的一个优点是最终创建的绑定是针对实际的内部属性而不是对象。这意味着它会对PropertyChanged事件做出正确的反应。


I'm trying to bind a TextBlock's Text property in a very dynamic way. I need to get the Path from an underlying object.

Here's the DataTemplate:

<DataTemplate DataType={x:Type local:DummyClass}>
  <TextBlock Text={Binding Path=???} />
</DataTemplate>

The DummyClass object has a property named "FieldValuePath" - the path that needs to be put where the ??? is.

The idea behind this is that the data template is supposed to be a GUI for viewing/editing any property of any object. So it's kind of preferable to be able to declare XAML which would bind some controls (textboxes, textblocks, datepickers, etc) to a given property.

Maybe anyone has any suggestions on how to implement such thing?

解决方案

If you create the binding in the code behind then you could get it to work. For example a simple code generated binding is:

Binding binding = new Binding("BindingPath");
binding.Mode = BindingMode.TwoWay;
BindingOperations.SetBinding(textBoxName, TextBox.TextProperty, binding);

Since the path in this binding ("BindingPath") is just a string, that string could come from any available object.

You'll need to hook into the creation of your data items to set these binding though.


A further possibility based on your comments:

This blog post outlines a way to create a custom binding class by inheriting from MarkupExtension. You may be able to use this as a starting point to wrap my suggestion into a reusable xaml markup for your special binding case.


More thoughts:

Okay, this was an interesting problem, so I decided to spend a little time seeing if I could come up with a working solution. I apologise in advance for the length of the following code samples...

Basing my solution on the blog post I linked to above I created this class:

public class IndirectBinder : MarkupExtension
    {
        public string IndirectProperty { get; set; }

        public override object ProvideValue(IServiceProvider serviceProvider)
        {
            //try to get bound items for our custom work
            DependencyObject targetObject;
            DependencyProperty targetProperty;
            bool status = TryGetTargetItems(serviceProvider, out targetObject, out targetProperty);

            if (status)
            {
                Control targetControl = targetObject as Control;
                if (targetControl == null) return null;

                //Find the object to take the binding from
                object dataContext = targetControl.DataContext;
                if (dataContext == null) return null;

                //Reflect out the indirect property and get the value
                PropertyInfo pi = dataContext.GetType().GetProperty(IndirectProperty);
                if (pi == null) return null;

                string realProperty = pi.GetValue(dataContext, null) as string;
                if (realProperty == null) return null;

                //Create the binding against the inner property
                Binding binding = new Binding(realProperty);
                binding.Mode = BindingMode.TwoWay;
                BindingOperations.SetBinding(targetObject, targetProperty, binding);

                //Return the initial value of the binding
                PropertyInfo realPi = dataContext.GetType().GetProperty(realProperty);
                if (realPi == null) return null;

                return realPi.GetValue(dataContext, null);

            }

            return null;

        }

        protected virtual bool TryGetTargetItems(IServiceProvider provider, out DependencyObject target, out DependencyProperty dp)
        {
            target = null;
            dp = null;
            if (provider == null) return false;

            //create a binding and assign it to the target
            IProvideValueTarget service = (IProvideValueTarget)provider.GetService(typeof(IProvideValueTarget));
            if (service == null) return false;

            //we need dependency objects / properties
            target = service.TargetObject as DependencyObject;
            dp = service.TargetProperty as DependencyProperty;
            return target != null && dp != null;
        }

You can use this new markup with the following xaml:

<TextBox Text="{local:IndirectBinder IndirectProperty=FieldValuePath}"/>

Where TextBox can be any class that inherits from control and Text can be any dependency property.

Obviously if you need to expose any of the other databinding options (such as one or two way binding) then you'll need to add more properties to the class.

While this is a complicated solution, one advantage that it has over using a converter is that the binding that is finally created is against the actual inner property rather than the object. This means that it correctly reacts to PropertyChanged events.

这篇关于如何绑定Binding.Path属性到底层数据?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-12 07:04