Question

I have a property that performs a yield return in its get function:

Data:

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

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

ViewModel:

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>

Works and compiles just fine (the property is of type IEnumerable). You can even bind to it, and the UI updates correctly. However, having this code breaks other (seemingly random) bindings on other controls, even bindings internal to other user controls.

My question is, why? This is perfectly valid C# and if anything it should break the bound UI control, not others.

Update Updated source code to be more complete. When I used the above, the getter for "TimePassed" was never called and the progress bar's Value was always 0.

If it helps, using the same yield return in a function, calling it and assigning the result.ToList() to the property doesn't break anything. I am still curious as to why the posted code is causing the "TimePassed" binding to fail (getter is never called).

Also interesting is that if I use Snoop to investigate the binding, the getter DOES get called when I try to look at the "broken" element.

Was it helpful?

Solution

It all works. Here is my test code.

<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;
                }
            }
        }
    }
}

I would look through this and tweak your values to match and see if that helps. If it doesn't then the problem is outside of the scope of the code you posted.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top