【问题标题】:Why does yield return in a property getter break WPF bindings? [closed]为什么属性 getter 中的 yield return 会破坏 WPF 绑定? [关闭]
【发布时间】:2014-03-07 01:36:44
【问题描述】:

我有一个在其 get 函数中执行收益返回的属性:

数据:

public class TestSummary
{
   [Description("Test1")]
   public TestResult Test1 {get; set;}

   [Description("Test2")]
   public TestResult Test2 {get; set;}
}
public enum TestResult
{
   Failed,
   Passed
}

视图模型:

private TestSummary TestResults
{
  get { return new TestSummary() { Test1=Failed, Test2=Passed }; }
}
public int TimePassed
{
   get
   {
       return 2;
   }
}

public IEnumerable<String> FailedTests
{
   get
   {
      PropertyDescriptorCollection attributes = TypeDescriptor.GetProperties(TestResults);
     foreach (PropertyInfo failedResult in typeof(TestSummary).GetProperties(BindingFlags.Instance | BindingFlags.Public)
                                              .Where(p => p.PropertyType == typeof(TestResult)).Where(t => (TestResult)t.GetValue(TestResults) == TestResult.Failed))
     {
        yield return ((DescriptionAttribute)attributes[failedResult.Name].Attributes[typeof(DescriptionAttribute)]).Description;
     }
   }
}

XAML:

<UserControl>
<UserControl.DataContext>
   <local:ViewModel/>
</UserControl.DataContext>
   <StackPanel>
       <ItemsControl ItemsSource="{Binding FailedTests}"/>
       <ProgressBar Value="{Binding TimePassed}"/>
   </StackPanel>
</UserControl>

工作和编译都很好(属性是 IEnumerable 类型)。您甚至可以绑定到它,并且 UI 会正确更新。但是,使用此代码会破坏其他控件上的其他(看似随机的)绑定,甚至是其他用户控件的内部绑定。

我的问题是,为什么?这是完全有效的 C#,如果有的话,它应该破坏绑定的 UI 控件,而不是其他控件。

更新 更新源代码更完整。当我使用上述方法时,从未调用过“TimePassed”的getter,进度条的值始终为0。

如果有帮助,在函数中使用相同的 yield return,调用它并将 result.ToList() 分配给属性不会破坏任何东西。我仍然很好奇为什么发布的代码导致“TimePassed”绑定失败(永远不会调用getter)。

另外有趣的是,如果我使用 Snoop 来调查绑定,当我尝试查看“损坏”元素时,getter 会被调用。

【问题讨论】:

  • 请发布此行为的最小可重现示例。
  • 代码已更新,足以让我重现该问题。
  • 包括详细解释“破坏其他绑定”的含义。 IE。你做什么,预期什么,正在发生什么。
  • 永远不会调用“损坏”绑定的 getter,如果您在其上放置转换器,则转换函数也不会调用,因此 UI 永远不会更新。我希望所有绑定都能像“破坏”绑定一样发挥作用。
  • 您是否认为您已发布此行为的最小可重现示例?如果您不向我们展示all the relevant code required to reproduce your problem,任何人都可以尝试调试您的问题。

标签: c# wpf yield-return


【解决方案1】:

一切正常。这是我的测试代码。

<Window x:Class="BindingTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:bindingTest="clr-namespace:BindingTest"
        Title="MainWindow" Height="350" Width="525">
    <Window.DataContext>
        <bindingTest:ViewModel/>
    </Window.DataContext>
    <Grid>
        <StackPanel>
            <ItemsControl ItemsSource="{Binding FailedTests}"/>
            <ProgressBar Value="{Binding TimePassed,Mode=OneWay}"/>
        </StackPanel>
    </Grid>
</Window>

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;

namespace BindingTest
{
    public class TestSummary
    {
        [Description("Test1")]
        public TestResult Test1 { get; set; }

        [Description("Test2")]
        public TestResult Test2 { get; set; }

        [Description("Test3")]
        public TestResult Test3 { get; set; }
    }
    public enum TestResult
    {
        Failed,
        Passed
    }

    public class ViewModel
    {
        private TestSummary TestResults
        {
            get { return new TestSummary()
            {
                Test1 = TestResult.Failed, 
                Test2 = TestResult.Passed,
                Test3 = TestResult.Failed
            }; }
        }

        public int TimePassed
        {
            get
            {
                return 2;
            }
        }

        public IEnumerable<String> FailedTests
        {
            get
            {
                PropertyDescriptorCollection attributes = TypeDescriptor.GetProperties(TestResults);
                foreach (PropertyInfo failedResult in typeof(TestSummary).GetProperties(BindingFlags.Instance | BindingFlags.Public)
                                                         .Where(p => p.PropertyType == typeof(TestResult))
                                                         .Where(t => (TestResult)t.GetValue(TestResults,null) == TestResult.Failed))
                {
                    yield return ((DescriptionAttribute)attributes[failedResult.Name].Attributes[typeof(DescriptionAttribute)]).Description;
                }
            }
        }
    }
}

我会仔细查看并调整您的值以匹配,看看是否有帮助。如果不是,则问题超出了您发布的代码的范围。

【讨论】:

  • 感谢您,这个问题似乎非常不一致(与实际代码中的更多绑定更加一致)并且很可能与机器相关。我认为这是 WPF 源中某处的冲突。再次感谢!
  • 我会考虑将其从 IEnumerable 更改为实际列表或数组。如果绑定了多次,那么每次绑定都会重置枚举器并给你异常结果。
  • 它没有绑定多次,但这是我最终不得不做的。感谢您的帮助和建议!
猜你喜欢
  • 1970-01-01
  • 2015-08-21
  • 1970-01-01
  • 2012-10-14
  • 1970-01-01
  • 2021-05-27
  • 1970-01-01
  • 2021-11-03
  • 1970-01-01
相关资源
最近更新 更多