2

The data from the DataTable doesn't fill the ComboBox or TextBox. Data from a SQL Server database is used to fill a DataTable, which is working fine, and I think the CollectionViewSource is okay as well, but the binding to the display elements isn't showing.

I originally created the view from the TableAdapter designer, and it all worked fine, the data was shown and I could move through the table rows. I needed to code for an SQL connection to the Data Source, so I created a SQL Data Adapter, using it to fill a DataSet then creating a DataTable from that dataset. Stepping thru the debugger, I can see that the DataTable ("compDataTable") contains all the data. I then used this DataTable as the CollectionViewSource ('tbl_CompsViewSource') to bind to my View controls, same as the original TableAdapter did, but when I run it, the View controls are blank. I tried to debug the binding through the System.Diagnostics, but it doesn't show any error except when it tries to fill in the View controls. The Error thrown is:

System.Windows.Data Error: 40 : BindingExpression path error: 'Name' property not found on 'object' ''Char' (HashCode=4325442)'. BindingExpression:Path=Name; DataItem='Char' (HashCode=4325442); target element is 'ComboBox' (Name='nameComboBox'); target property is 'NoTarget' (type 'Object')

and

System.Windows.Data Error: 40 : BindingExpression path error: 'Value' property not found on 'object' ''EnumerableCollectionView' (HashCode=28278595)'. BindingExpression:Path=Value; DataItem='EnumerableCollectionView' (HashCode=28278595); target element is 'TextBox' (Name='valueTextBox'); target property is 'Text' (type 'String')

The XML code is :

<Window x:Class="CompsTabAdapt.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:diag="clr-namespace:System.Diagnostics;assembly=WindowsBase"
    Title="MainWindow" Loaded="Window_Loaded">
<Window.Resources>
    <CollectionViewSource x:Key="tbl_CompsViewSource" Source="{Binding Source=compDataTable}" diag:PresentationTraceSources.TraceLevel="High"/>
</Window.Resources>

<StackPanel DataContext="{Binding tbl_CompsViewSource}">
    <Label Content="Compound :"/>
    <ComboBox x:Name="nameComboBox" DisplayMemberPath="Name" ItemsSource="{Binding}" IsEditable="True">
        <ComboBox.ItemsPanel>
            <ItemsPanelTemplate>
                <VirtualizingStackPanel/>
            </ItemsPanelTemplate>
        </ComboBox.ItemsPanel>
    </ComboBox>
    <StackPanel Orientation="Horizontal">
        <Label Width="120">Value: </Label>
        <TextBox x:Name="valueTextBox" Text="{Binding Value, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}"/>
    </StackPanel>
</StackPanel>
</Window>

and the code behind is :

using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;

namespace CompsTabAdapt
{
public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

    SqlDataAdapter CompsDataAdapt = new SqlDataAdapter();
    DataSet compDataSet = new DataSet();
    DataTable compDataTable = new DataTable();
    CollectionViewSource tbl_CompsViewSource = new CollectionViewSource();


    private void Window_Loaded(object sender, RoutedEventArgs e)
    {
        try
        {
            string dbcon = ConfigurationManager.ConnectionStrings["ConnOrigString"].ConnectionString;
            using (SqlConnection Connection = new SqlConnection(dbcon))
            {
                Connection.Open();
                CompsDataAdapt = new SqlDataAdapter("SELECT * FROM tbl_Comps", Connection);
                CompsDataAdapt.Fill(compDataSet);
                Connection.Close();
                compDataTable = compDataSet.Tables[0];
            }
        }
        catch
        {
            dbConnect();
        }
        finally
        {
            tbl_CompsViewSource = (CollectionViewSource)(this.FindResource("tbl_CompsViewSource"));
            tbl_CompsViewSource.View.MoveCurrentToFirst();
        }
}
}
GPiton
  • 21
  • 1

1 Answers1

0

System.Windows.Data Error: 40 : BindingExpression path error: 'Value' property not found on 'object' ''EnumerableCollectionView' (HashCode=28278595)'. BindingExpression:Path=Value; DataItem='EnumerableCollectionView' (HashCode=28278595); target element is 'TextBox' (Name='valueTextBox'); target property is 'Text' (type 'String') what this message is telling you is that it didn't find the property Value on the sourceof the binding of a TextBox named "valueTextBox". Looking at the xaml <TextBox x:Name="valueTextBox" Text="{Binding Value, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}"/> no source is defined for the binding so the source will be it's datacontex (or in this case, the datacontex of the first parent with a set datacontext). This is the stackpanel

<Window.Resources>
     <CollectionViewSource x:Key="tbl_CompsViewSource" Source="{Binding Source=compDataTable}" diag:PresentationTraceSources.TraceLevel="High"/>
</Window.Resources>

<StackPanel DataContext="{Binding tbl_CompsViewSource}">

So the source is compDataTable which is defined in the code behind (you should probably explicitly set the acess modifiers, I was surprised to see it was acessible).

In the code behind, I can see compDataTable = compDataSet.Tables[0]; So compDataTable is of type Table but the type Table doesn't have a property named Value so the binding fails.

Regarding the other error, you are treating compDataTable as a collection and trying to access the Name property of one of it's items which of course fail.

My guess is that you meant to access the rows of this table so you should check this link which has an exemple of how to acess the data.

foreach(DataTable table in dataSet.Tables)
{
    foreach(DataRow row in table.Rows)
    {
        foreach (DataColumn column in table.Columns)
        {
            //Add it to a list instead and bind the list
            Console.WriteLine(row[column]);
        }
    }
}

*Example in the link

Ostas
  • 839
  • 7
  • 11
  • There seem to plenty of articles that claim that a DataTable in and of itself is a valid source for binding, with the column names valid as properties. When I originally set up the bindings through creation of a TableAdapter, the bindings all worked. In the error messages. both 'Name' and 'Value' properties are valid table columns, though the data in the underlying 'Value' column is float rather than text (char). – GPiton Mar 06 '21 at 19:03
  • Maybe link one of those articles so I can show you how to adapt the syntax for your case because right now it is not correct and you can't bind directly to a DataTable object, maybe you are mistaking it for DataTable.DefaultView [DataView](https://docs.microsoft.com/fr-fr/dotnet/api/system.data.dataview?view=net-5.0) instead ? Even if it was possible, in your binding, the `Name` property is targeting a property of an item of the source while `Value` is targeting a property of the source so it can't be right. (It is the same has writing `this.valueTextBox.Text = compDataTable.Value;` in c#) – Ostas Mar 07 '21 at 00:19
  • Try it in your code behind and you will have a message telling you `DataTable doesn't have a property name 'Value'` which is close to the one you are getting in your binding except DataTable is not a collection so the previous binding doesn't work as intended either. Check [this answer](https://stackoverflow.com/a/43299917/13448212) it might clear the confusion. – Ostas Mar 07 '21 at 00:25