9

I've been searching for hours on this error that appears in the output window. I'm pretty new to bindings in WPF, so I'm sure there's something I'm missing.

Full text of the error (there is one for each binding path, all similar to this one):

System.Windows.Data Error: 39 : BindingExpression path error: 'TestItem' property not found on 'object' ''String' (HashCode=-842352750)'. BindingExpression:Path=TestItem; DataItem='String' (HashCode=-842352750); target element is 'TextBlock' (Name=''); target property is 'Text' (type 'String')

EDIT: Everything seems to work as it should, but I get these errors in the output window.

XAML:

<UserControl>
    <UserControl.Resources>
        <c:MyData x:Key="myDataSource"/>
        <DataTemplate x:Key="image">
            <Image x:Name="TheImage" />
            <DataTemplate.Triggers>
                <DataTrigger Binding="{Binding Path=PassFail}" Value="PASS">
                    <Setter TargetName="TheImage" Property="Source" Value="Images/accept.png" />
                </DataTrigger>
                <DataTrigger Binding="{Binding Path=PassFail}" Value="FAIL">
                    <Setter TargetName="TheImage" Property="Source" Value="Images/delete.png" />
                </DataTrigger>
                <DataTrigger Binding="{Binding Path=PassFail}" Value="WARNING">
                    <Setter TargetName="TheImage" Property="Source" Value="Images/warning.png" />
                </DataTrigger>
            </DataTemplate.Triggers>
        </DataTemplate>
        <Storyboard x:Key="OnMouseLeftButtonDown1"/>
    </UserControl.Resources>
    <UserControl.DataContext>
        <Binding Source="{StaticResource myDataSource}"/>
    </UserControl.DataContext>
    <ListView Margin="0,94,-4,-7" x:Name="lsvwOutput" ItemsSource="{Binding Source={StaticResource myDataSource}}"  MouseUp="lsvwOutput_MouseUp" FontFamily="Verdana">
        <ListView.View>
            <GridView>
                <GridViewColumn Header="Test Item" Width="300"  DisplayMemberBinding="{Binding Path=TestItem}" />
                <GridViewColumn Header="Information" Width="0" DisplayMemberBinding="{Binding Path=Information}"/>
                <GridViewColumn Header="Result" Width="0" DisplayMemberBinding="{Binding Path=PassFail}"/>
                <GridViewColumn Header="Result" CellTemplate="{StaticResource image}" />
            </GridView>
        </ListView.View>
    </ListView
</UserControl>

Code behind:

public class MyData : INotifyPropertyChanged
{
    private string _testitem = "";
    private string _information = "";
    private string _passfail = "";

    public string TestItem {
        get { return _testitem; }
        set
        {
            _testitem = value;
            OnPropertyChanged("TestItem");
        }

    }
    public string Information {
        get { return _information; }
        set
        {
            _information = value;
            OnPropertyChanged("Information");
        }
    }
    public string PassFail {
        get { return _passfail; }
        set
        {
            _passfail = value;
            OnPropertyChanged("PassFail");
        }
    }
    public string Text { get; set; }
abatishchev
  • 98,240
  • 88
  • 296
  • 433
isorfir
  • 771
  • 2
  • 8
  • 19
  • Why are you setting a non-enumerable object to the ItemsSource? – Landern Mar 21 '11 at 19:02
  • @Moses I've changed what my ItemsSource was several times now, looking at different examples. I don't have a good understanding what _should_ go there. The code I posed was the last iteration I tried, not necessarily have I would have originally done. – isorfir Mar 21 '11 at 19:18

2 Answers2

11

You don't want to set the DataContext on the UserControl. Instead, you want to set it in the scope of the UserControl.

Usually you do this in the constructor of the UserControl. I usually add a line like this:

this.RootElement.DataContext = myData;

Where RootElement is the first sub-element (the Content) of your UserControl (usually a panel like Grid or StackPanel).

In your case it would be:

this.lsvwOutput.DataContext = FindResource("myDataSource");

And makes sure that it's after the InitializeComponent() call.

It's just a question of scoping. You set the datacontext on the root panel of the usercontrol. This is a really non-obvious part of WPF.

UPDATE: As Markus points out below, in the case of a listview, you want to set an array of data, not just a data point. Take that into consideration when setting the DataContext in your constructor.

cunningdave
  • 1,470
  • 10
  • 13
  • that's not the problem! actually that datacontext isn't beeing used anywhere since he is binding that listviews itemssource to the static resource and not relative to the current DataContext (which still would have worked) – Markus Hütter Mar 21 '11 at 19:04
  • Looks like that was it! The errors no longer show up. I thought it had something to do with the scope, but I didn't find a clear example showing me what I needed. Thanks! – isorfir Mar 21 '11 at 19:23
  • Well then the problem was probably two-fold - I agree that you're creating an instance of the data and not an array, like Markus said below. But this is a good pattern to follow whenever you're creating a WPF, and frankly wish that it would just default that way, since it would make authoring controls that much easier for beginners. – cunningdave Mar 21 '11 at 19:27
  • @cunningdave Is there a way to eliminate this error? I have a control bound to a property that may not exist. I want to disable the binding or at least the error for this binding. I've tried FallbackValue, but it doesn't work. – Shimmy Weitzhandler Mar 25 '12 at 03:35
  • @Shimmy There isn't really a way to get rid of it, cause it's a valid error. However, bindings are designed to be failsafe - even if they report an error in the output, that's okay. This is a valid scenario when, for instance, working in a design tool like Blend. At runtime, you may want to bind to a dynamic property that is basically impossible to model at design time. The only way to truly get rid of the error would be to detect the property in behind-code and only set it if it exists, probably using reflection if you have no knowledge of the bound ViewModel. – cunningdave Mar 26 '12 at 15:29
  • @cunningdave The thing is my ViewModel exposes a property X which is a Model, all the controls bind to its various properties, I get zillion errors on those properties. I know it's by design, and I know it's a valid use case, however, I was looking for convenience. Thanks for your reply! – Shimmy Weitzhandler Mar 26 '12 at 23:33
6

seems like you're binding your listviews itemssource to an object, not an array. is everything working visually? or do you see nothing?

EDIT: what happens if you write instead of:

<c:MyData x:Key="myDataSource"/>

this:

<x:Array x:Key="myDataSource" Type="{x:Type c:MyData}">
  <c:MyData />      
</x:Array>

or any likewise collection definition

Markus Hütter
  • 7,796
  • 1
  • 36
  • 63
  • I should have mentioned that everything works properly, but these errors exist regardless. I get this error when using your code: "Operation is not valid while ItemsSource is in use. Access and modify elements with ItemsControl.ItemsSource instead." – isorfir Mar 21 '11 at 19:13
  • @isorfir that's what I was after with my question! Don't worry that you see these error messages. they're not uncommon. While the Bindingengine figures out things, there can be errors if something is not present on time, but still everything works fine – Markus Hütter Mar 21 '11 at 19:15
  • Markus, I've bumped you up because I think you're more right than I am. – cunningdave Mar 21 '11 at 19:28