简体   繁体   中英

WPF Linq to SQL Returning a Custom Object with Data Binding to DataGrid C# MVVM

I am trying to make the jump from WinForms to WPF and I'm trying to learn the correct way. I want to use a correct MVVM model. This is my first WPF project ever and I am having trouble with databinding with a linq result. I am aware that I could do this very easily in the code behind or even not use a custom object and return entire table form the linq query to the datagrid while still using a separate class. But I would like to stick to this format. I don't want to use a datatable.

Assume that I have a dbml with a "Job" table. I want to select columns "Job" (Linq seems to automatically rename this column to Job1), "Customer", and "Order_Date".

Here is my code:

namespace Custom_Teplate.Model
{
    public class LINQResult 
    {
        public System.String JobNum
        { get; set; }
        public System.String CustomerName
        { get; set; }
        public System.DateTime Order_Date
        {get; set; }

        public static LINQResult Create()
        {
            DataDataContext dc = new DataDataContext();
            dynamic query = (from ddd in dc.Jobs
                             where (ddd.Status == "Active")
                             select new LINQResult
                             {
                                 JobNum = ddd.Job1,
                                 CustomerName = ddd.Customer,
                                 Order_Date = ddd.Order_Date,   
                             });
           return query;
        }
    }
}

I add the namespace to my XMAL:

xmlns:c="clr-namespace:Custom_Teplate.Model"
<Window.Resources>
    <c:LINQResult x:Key="ResultListData" />
</Window.Resources>

and set the itemssource as follows:

ItemsSource="{Binding Source={StaticResource ResultListData}}

That's not really how I would do this. Your first mistake is that although you have added an instance of your LINQResult class into the Resources section, it has no data in it because you never call the Create method. This is how I would achieve this:

I access the database using Linq2SQL and fill custom data types like your example, but here's the difference... I have a view model class for each view. In the view model classes, I have all the properties that I want to display in the UI, whether they are collections or singular items. The view model classes implement the INotifyPropertyChanged interface (this is essential) through a base class.

I have DataTemplate s set up in App.xaml that link the various view models to views and then I can display a view in the UI like this:

<ContentControl Content="{Binding ViewModel}" />

In the view model constructor, I call the database and fill the collection(s) and set the properties. In your example, you seem to be creating a Linq query that would return multiple items ( IEnumerable<LINQResult> ), but you're trying to return just one of these items from your Create method.

I would normally extend the ObservableCollection<T> class for each of my collection classes, so if I were you, I would create this:

public class LinqResults : ObservableCollection<LinqResult> 
{
    public LinqResults(IEnumerable<LinqResult> linqResults) : base(linqResults) { }
}

I would then change your query method to something like this:

public static LinqResults Create()
{
    DataDataContext dc = new DataDataContext();
    LinqResults linqResults = new LinqResults(
        from job in dc.Jobs
        where job.Status == "Active"
        select new LinqResult
        {
            JobNum = job.Job1,
            CustomerName = job.Customer,
            Order_Date = job.Order_Date,
        });
    return linqResults;
}

Then in a view model, I would add a collection property of type LinqResults and 'plug it in' to the INotifyPropertyChanged` interface:

public LinqResults LinqResults 
{
    get { return linqResults; }
    set { linqResults = value; NotifyPropertyChanged("LinqResults"); }
}

Finally, bind to the collection in a view and define a DataTemplate for your data type (remembering to define an XML namespace to access it):

    <ListBox ItemsSource="{Binding LinqResults}">
    <ListBox.ItemTemplate>
        <DataTemplate DataType="{x:Type YourXmlNamespace:LinqResult}">
            <StackPanel>
                <TextBlock Text="{Binding JobNum}" />
                <TextBlock Text="{Binding CustomerName}" />
                <TextBlock Text="{Binding Order_Date}" />
            </StackPanel>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

Please take a look at Josh Smith's WPF Apps With The Model-View-ViewModel Design Pattern article for more information on MVVM.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM