【问题标题】:WPF Dictionary Binding failure is very slowWPF字典绑定失败很慢
【发布时间】:2012-11-28 16:45:40
【问题描述】:

我在我的应用程序中绑定了大部分 Label 对象,以便可以从 Web 服务中替换它们。

我将替换内容存储在字典中。替换因应用加载的客户端而异。

我遇到的问题是大部分时间我不替换标签,绑定失败是抛出一个非常慢的异常。

这里是一个例子:(注意这段代码是正确的,如果找不到匹配的话它会很慢。)

<Label Content="_Gender"
       Helpers:CaptionHelper.PropertyName="Content"
       Helpers:CaptionHelper.PropertyValue="{Binding Labels[Gender], 
                                                     FallbackValue=_Gender}"
       Target="{Binding ElementName=cbGender}" />

当绑定尝试查找 Lables[Gender] 时,我在输出窗口中得到了这个:

System.Windows.Data Warning: 17 : Cannot get 'Item[]' value (type 'String') from 'Labels' (type 'Dictionary`2'). BindingExpression:Path=Labels[Gender]; DataItem='MyViewMV'
      (HashCode=63776763); target element is 'Label' (Name=''); target property is 'PropertyValue'(type 'String') TargetInvocationException:'System.Reflection.TargetInvocationException: 
           Exception has been thrown by the target of an invocation. ---> System.Collections.Generic.KeyNotFoundException: 
           The given key was not present in the dictionary.
   at System.Collections.Generic.Dictionary`2.get_Item(TKey key)
   --- End of inner exception stack trace ---
   at System.RuntimeMethodHandle._InvokeMethodFast(Params Truncated)
   at System.Reflection.RuntimeMethodInfo.Invoke(Params Truncated)
   at System.Reflection.RuntimeMethodInfo.Invoke(Params Truncated)
   at MS.Internal.Data.PropertyPathWorker.GetValue(Params Truncated)
   at MS.Internal.Data.PropertyPathWorker.RawValue(Params Truncated)'

因为我有很多这些,所以大约需要一秒钟的时间来浏览它们。

有没有办法在字典查找失败时使绑定不抛出异常?或者以某种方式更快地失败?

【问题讨论】:

    标签: c# .net wpf xaml


    【解决方案1】:

    如果您可以选择,我会将您的 IDictionary 实现更改为返回 null 的实现,而不是使用 TargetNullValue(或者甚至是 IDictionary&lt;TKey, object&gt; 并返回 DependencyProperty.UnsetValue,如果您仍然使用 FallbackValue ):

    public class PassthruDictionary<TKey, TValue> : IDictionary<TKey, TValue>
    {
        private Dictionary<TKey, TValue> instance;
    
        // ... other stuff
    
        public TValue this[TKey key]
        {
            get
            {
                TValue value;
                if (instance.TryGetValue(key, out value))
                {
                    return value;
                }
                else
                {
                    return default(TValue);
                }
            }
            // ... more
        }
    }
    

    【讨论】:

    • 不确定这对于澄清问题是否太老了,但在这里:我似乎找不到返回 DependecyProeprty.UnsetValue 的方法。假设我有一个PassthruDictionary&lt;string,string&gt;,我该如何返回 UnsetValue? (它可以编译,但会为我抛出运行时异常。)
    【解决方案2】:

    是的,如果您不在调试器中运行代码,则可以显着提高速度。实际上,Visual Studio 中 stackteace 的打印到目前为止是最慢的部分。如果您在没有附加调试器的情况下运行应用程序,我很确定性能损失不会再明显了。

    我遇到了类似的问题,我们在库中捕获异常,即使您这样做了,VS 也会在每次捕获(和处理)异常时打印关于在代码中捕获的第一次机会异常的注释。异常在启动时被触发了大约 50 次,应用程序需要大约 10 秒才能启动,而这一切都只是因为控制台日志记录。一旦我在没有调试器的情况下运行应用程序,它几乎立即启动。

    因此,尝试解决该异常可能只是过早的优化。

    【讨论】:

      【解决方案3】:

      编辑:

      实际上,所有这些都是在 VS 输出窗格中禁用输出。它实际上并没有加快速度。

      原文:

      我遇到了类似的问题,但我想捕获并记录错误。但是,您可以使用以下解决方案简单地禁用将错误输出到 VS2010 输出窗口。解决方案分为两部分,第一部分是一个简单的类:

      using System.Diagnostics;
      
      namespace DevBindingErrors
      {
          /// <summary>
          /// Intercepts all binding error messages. Stops output appearing in VS2010 debug window.
          /// </summary>
          class BindingTraceListener: TraceListener
          {
              private string _messageType;
      
              public override void Write(string message)
              {
                  // Always happens in 2 stages: first stage writes "System.Windows.Data Error: 40 :" or similar.
                  _messageType = message;
              }
      
              public override void WriteLine(string message)
              {
                  Debug.WriteLine(string.Format("{0}{1}", _messageType, message));
              }
          }
      }
      

      第二部分在 App.xaml.cs 中:

      using System.Diagnostics;
      using System.Windows;
      
      namespace DevBindingErrors
      {
          /// <summary>
          /// Interaction logic for App.xaml
          /// </summary>
          public partial class App : Application
          {
              public App()
              {
                  PresentationTraceSources.Refresh();
                  PresentationTraceSources.DataBindingSource.Listeners.Add(new BindingTraceListener());
                  PresentationTraceSources.DataBindingSource.Switch.Level = SourceLevels.Warning;
              }
          }
      }
      

      如果您想忽略所有绑定错误,只需注释掉 Debug.WriteLine(...) 行。 (不过我真的不推荐这样做)这也将加快执行速度,而不会失去调试应用程序的能力。

      这个解决方案的想法来自this page,其中也有关于 WPF 中跟踪源的更多详细信息。

      【讨论】:

      • 你不能定义 TRACE。
      猜你喜欢
      • 1970-01-01
      • 2011-09-08
      • 1970-01-01
      • 2015-10-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多