草庐IT

c# - 在 .Net 4.0 中从 .Net 4.5 绑定(bind)的延迟属性

coder 2024-05-27 原文

如何在 .Net 4.0 中实现 .Net 4.5 的延迟属性(描述 here)?

我知道我无法从 BindingBase 继承,因为 ProvideValue 是密封的。

我可以实现 MarkupExtension,但这意味着我现在必须重写 BindingExtension 的所有属性,还有其他方法吗?

最佳答案

最后,我决定使用组合将 DelayedBinding 实现为 MarkupExtension。

我遇到的唯一问题是如果 IProvideValueTarget 中的 TargetProperty 为 null,DataTemplates ProvideValue 应该返回此值。

[MarkupExtensionReturnType(typeof(object))]
public class DelayedBindingExtension : MarkupExtension
{
    private readonly Binding _binding = new Binding();

    public DelayedBindingExtension()
    {
        //Default value for delay
        Delay = TimeSpan.FromSeconds(0.5);
    }

    public DelayedBindingExtension(PropertyPath path)
        : this()
    {
        Path = path;
    }

    #region properties

    [DefaultValue(null)]
    public object AsyncState
    {
        get { return _binding.AsyncState; }
        set { _binding.AsyncState = value; }
    }

    [DefaultValue(false)]
    public bool BindsDirectlyToSource
    {
        get { return _binding.BindsDirectlyToSource; }
        set { _binding.BindsDirectlyToSource = value; }
    }

    [DefaultValue(null)]
    public IValueConverter Converter
    {
        get { return _binding.Converter; }
        set { _binding.Converter = value; }
    }

    [TypeConverter(typeof(CultureInfoIetfLanguageTagConverter)), DefaultValue(null)]
    public CultureInfo ConverterCulture
    {
        get { return _binding.ConverterCulture; }
        set { _binding.ConverterCulture = value; }
    }

    [DefaultValue(null)]
    public object ConverterParameter
    {
        get { return _binding.ConverterParameter; }
        set { _binding.ConverterParameter = value; }
    }

    [DefaultValue(null)]
    public string ElementName
    {
        get { return _binding.ElementName; }
        set { _binding.ElementName = value; }
    }

    [DefaultValue(null)]
    public object FallbackValue
    {
        get { return _binding.FallbackValue; }
        set { _binding.FallbackValue = value; }
    }

    [DefaultValue(false)]
    public bool IsAsync
    {
        get { return _binding.IsAsync; }
        set { _binding.IsAsync = value; }
    }

    [DefaultValue(BindingMode.Default)]
    public BindingMode Mode
    {
        get { return _binding.Mode; }
        set { _binding.Mode = value; }
    }

    [DefaultValue(false)]
    public bool NotifyOnSourceUpdated
    {
        get { return _binding.NotifyOnSourceUpdated; }
        set { _binding.NotifyOnSourceUpdated = value; }
    }

    [DefaultValue(false)]
    public bool NotifyOnTargetUpdated
    {
        get { return _binding.NotifyOnTargetUpdated; }
        set { _binding.NotifyOnTargetUpdated = value; }
    }

    [DefaultValue(false)]
    public bool NotifyOnValidationError
    {
        get { return _binding.NotifyOnValidationError; }
        set { _binding.NotifyOnValidationError = value; }
    }

    [DefaultValue(null)]
    public PropertyPath Path
    {
        get { return _binding.Path; }
        set { _binding.Path = value; }
    }

    [DefaultValue(null)]
    public RelativeSource RelativeSource
    {
        get { return _binding.RelativeSource; }
        set { _binding.RelativeSource = value; }
    }

    [DefaultValue(null)]
    public object Source
    {
        get { return _binding.Source; }
        set { _binding.Source = value; }
    }

    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    public UpdateSourceExceptionFilterCallback UpdateSourceExceptionFilter
    {
        get { return _binding.UpdateSourceExceptionFilter; }
        set { _binding.UpdateSourceExceptionFilter = value; }
    }

    [DefaultValue(UpdateSourceTrigger.Default)]
    public UpdateSourceTrigger UpdateSourceTrigger
    {
        get { return _binding.UpdateSourceTrigger; }
        set { _binding.UpdateSourceTrigger = value; }
    }

    [DefaultValue(null)]
    public object TargetNullValue
    {
        get { return _binding.TargetNullValue; }
        set { _binding.TargetNullValue = value; }
    }

    [DefaultValue(null)]
    public string StringFormat
    {
        get { return _binding.StringFormat; }
        set { _binding.StringFormat = value; }
    }

    [DefaultValue(false)]
    public bool ValidatesOnDataErrors
    {
        get { return _binding.ValidatesOnDataErrors; }
        set { _binding.ValidatesOnDataErrors = value; }
    }

    [DefaultValue(false)]
    public bool ValidatesOnExceptions
    {
        get { return _binding.ValidatesOnExceptions; }
        set { _binding.ValidatesOnExceptions = value; }
    }

    [DefaultValue(null)]
    public string XPath
    {
        get { return _binding.XPath; }
        set { _binding.XPath = value; }
    }

    [DefaultValue(null)]
    public Collection<ValidationRule> ValidationRules
    {
        get { return _binding.ValidationRules; }
    }

    #endregion

    [DefaultValue(null)]
    public TimeSpan Delay { get; set; }

    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        try
        {
            _binding.Mode = BindingMode.TwoWay;
            _binding.UpdateSourceTrigger = UpdateSourceTrigger.Explicit;
        }
        catch (InvalidOperationException)  //Binding in use already don't change it
        {
        }

        var valueProvider = serviceProvider.GetService(typeof (IProvideValueTarget)) as IProvideValueTarget;
        if (valueProvider != null)
        {
            var bindingTarget = valueProvider.TargetObject as DependencyObject;
            var bindingProperty = valueProvider.TargetProperty as DependencyProperty;
            if (bindingProperty != null && bindingTarget != null)
            {
                var result = (BindingExpression)_binding.ProvideValue(serviceProvider);

                new DelayBindingManager(result, bindingTarget, bindingProperty, Delay);
                return result;
            }
        }

        return this;
    }

    private class DelayBindingManager
    {
        private readonly BindingExpressionBase _bindingExpression;
        private readonly DependencyProperty _bindingTargetProperty;
        private DependencyPropertyDescriptor _descriptor;
        private readonly DispatcherTimer _timer;

        public DelayBindingManager(BindingExpressionBase bindingExpression, DependencyObject bindingTarget, DependencyProperty bindingTargetProperty, TimeSpan delay)
        {
            _bindingExpression = bindingExpression;
            _bindingTargetProperty = bindingTargetProperty;

            _descriptor = DependencyPropertyDescriptor.FromProperty(_bindingTargetProperty, bindingTarget.GetType());
            if (_descriptor != null)
                _descriptor.AddValueChanged(bindingTarget, BindingTargetTargetPropertyChanged);

            _timer = new DispatcherTimer();
            _timer.Tick += TimerTick;
            _timer.Interval = delay;
        }

        private void BindingTargetTargetPropertyChanged(object sender, EventArgs e)
        {
            var source = (DependencyObject)sender;
            if (!BindingOperations.IsDataBound(source, _bindingTargetProperty))
            {
                if (_descriptor != null)
                {
                    _descriptor.RemoveValueChanged(source, BindingTargetTargetPropertyChanged);
                    _descriptor = null;
                }
                return;
            }

            _timer.Stop();
            _timer.Start();
        }

        private void TimerTick(object sender, EventArgs e)
        {
            _timer.Stop();
            _bindingExpression.UpdateSource();
        }
    }
}

关于c# - 在 .Net 4.0 中从 .Net 4.5 绑定(bind)的延迟属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7661149/

有关c# - 在 .Net 4.0 中从 .Net 4.5 绑定(bind)的延迟属性的更多相关文章

  1. ruby-on-rails - Ruby net/ldap 模块中的内存泄漏 - 2

    作为我的Rails应用程序的一部分,我编写了一个小导入程序,它从我们的LDAP系统中吸取数据并将其塞入一个用户表中。不幸的是,与LDAP相关的代码在遍历我们的32K用户时泄漏了大量内存,我一直无法弄清楚如何解决这个问题。这个问题似乎在某种程度上与LDAP库有关,因为当我删除对LDAP内容的调用时,内存使用情况会很好地稳定下来。此外,不断增加的对象是Net::BER::BerIdentifiedString和Net::BER::BerIdentifiedArray,它们都是LDAP库的一部分。当我运行导入时,内存使用量最终达到超过1GB的峰值。如果问题存在,我需要找到一些方法来更正我的代

  2. ruby-on-rails - 如果为空或不验证数值,则使属性默认为 0 - 2

    我希望我的UserPrice模型的属性在它们为空或不验证数值时默认为0。这些属性是tax_rate、shipping_cost和price。classCreateUserPrices8,:scale=>2t.decimal:tax_rate,:precision=>8,:scale=>2t.decimal:shipping_cost,:precision=>8,:scale=>2endendend起初,我将所有3列的:default=>0放在表格中,但我不想要这样,因为它已经填充了字段,我想使用占位符。这是我的UserPrice模型:classUserPrice回答before_val

  3. ruby-on-rails - 在混合/模块中覆盖模型的属性访问器 - 2

    我有一个包含模块的模型。我想在模块中覆盖模型的访问器方法。例如:classBlah这显然行不通。有什么想法可以实现吗? 最佳答案 您的代码看起来是正确的。我们正在毫无困难地使用这个确切的模式。如果我没记错的话,Rails使用#method_missing作为属性setter,因此您的模块将优先,阻止ActiveRecord的setter。如果您正在使用ActiveSupport::Concern(参见thisblogpost),那么您的实例方法需要进入一个特殊的模块:classBlah

  4. ruby - 如何模拟 Net::HTTP::Post? - 2

    是的,我知道最好使用webmock,但我想知道如何在RSpec中模拟此方法:defmethod_to_testurl=URI.parseurireq=Net::HTTP::Post.newurl.pathres=Net::HTTP.start(url.host,url.port)do|http|http.requestreq,foo:1endresend这是RSpec:let(:uri){'http://example.com'}specify'HTTPcall'dohttp=mock:httpNet::HTTP.stub!(:start).and_yieldhttphttp.shou

  5. ruby - ruby 中的 TOPLEVEL_BINDING 是什么? - 2

    它不等于主线程的binding,这个toplevel作用域是什么?此作用域与主线程中的binding有何不同?>ruby-e'putsTOPLEVEL_BINDING===binding'false 最佳答案 事实是,TOPLEVEL_BINDING始终引用Binding的预定义全局实例,而Kernel#binding创建的新实例>Binding每次封装当前执行上下文。在顶层,它们都包含相同的绑定(bind),但它们不是同一个对象,您无法使用==或===测试它们的绑定(bind)相等性。putsTOPLEVEL_BINDINGput

  6. ruby - 多个属性的 update_column 方法 - 2

    我有一个具有一些属性的模型:attr1、attr2和attr3。我需要在不执行回调和验证的情况下更新此属性。我找到了update_column方法,但我想同时更新三个属性。我需要这样的东西:update_columns({attr1:val1,attr2:val2,attr3:val3})代替update_column(attr1,val1)update_column(attr2,val2)update_column(attr3,val3) 最佳答案 您可以使用update_columns(attr1:val1,attr2:val2

  7. ruby - Nokogiri 剥离所有属性 - 2

    我有这个html标记:我想得到这个:我如何使用Nokogiri做到这一点? 最佳答案 require'nokogiri'doc=Nokogiri::HTML('')您可以通过xpath删除所有属性:doc.xpath('//@*').remove或者,如果您需要做一些更复杂的事情,有时使用以下方法遍历所有元素会更容易:doc.traversedo|node|node.keys.eachdo|attribute|node.deleteattributeendend 关于ruby-Nokog

  8. ruby-on-rails - Rails 模型——非持久类成员或属性? - 2

    对于Rails模型,是否可以/建议让一个类的成员不持久保存到数据库中?我想将用户最后选择的类型存储在session变量中。由于我无法从我的模型中设置session变量,我想将值存储在一个“虚拟”类成员中,该成员只是将值传递回Controller。你能有这样的类(class)成员吗? 最佳答案 将非持久属性添加到Rails模型就像任何其他Ruby类一样:classUser扩展解释:在Ruby中,所有实例变量都是私有(private)的,不需要在赋值前定义。attr_accessor创建一个setter和getter方法:classUs

  9. c# - 如何在 ruby​​ 中调用 C# dll? - 2

    如何在ruby​​中调用C#dll? 最佳答案 我能想到几种可能性:为您的DLL编写(或找人编写)一个COM包装器,如果它还没有,则使用Ruby的WIN32OLE库来调用它;看看RubyCLR,其中一位作者是JohnLam,他继续在Microsoft从事IronRuby方面的工作。(估计不会再维护了,可能不支持.Net2.0以上的版本);正如其他地方已经提到的,看看使用IronRuby,如果这是您的技术选择。有一个主题是here.请注意,最后一篇文章实际上来自JohnLam(看起来像是2009年3月),他似乎很自在地断言RubyCL

  10. C# 到 Ruby sha1 base64 编码 - 2

    我正在尝试在Ruby中复制Convert.ToBase64String()行为。这是我的C#代码:varsha1=newSHA1CryptoServiceProvider();varpasswordBytes=Encoding.UTF8.GetBytes("password");varpasswordHash=sha1.ComputeHash(passwordBytes);returnConvert.ToBase64String(passwordHash);//returns"W6ph5Mm5Pz8GgiULbPgzG37mj9g="当我在Ruby中尝试同样的事情时,我得到了相同sha

随机推荐