DisplayName13579
DisplayName13579

Reputation: 239

WPF C# Data-binding to DataGridTextColumn

I'm having a difficult time getting any data in this datagrid view to appear. I've followed some suggestions in a few other StackOverflow forum posts but am not having any luck getting the content to appear.

<DataGrid 
    x:Name="DataGridEmployees"
    DataContext="{Binding RelativeSource={RelativeSource AncestorType=Window}}"
    ItemsSource="{Binding GridView}"
    AutoGenerateColumns="True"
    Loaded="dataGrid1_Loaded"
    Margin="0,2,0,-2" Grid.ColumnSpan="2">
    <DataGrid.Columns>
        <DataGridTextColumn Header="EmployeeId" Width="175" Binding="{Binding Id}"></DataGridTextColumn>
        <DataGridTextColumn Header="Title" Width="175" Binding="{Binding Title}"></DataGridTextColumn>
        <DataGridTextColumn Header="WorkStatus" Width="175" Binding="{Binding WorkStatus}"></DataGridTextColumn>
        <DataGridTextColumn Header="FullName" Width="175" Binding="{Binding FullName}"></DataGridTextColumn>
    </DataGrid.Columns>
</DataGrid>

This is the click event that is being fired from a separate window (? could this be causing any problems?) in the xaml.cs file

public partial class MainMenu : Window
{
    WpfSampleEntities2 _context = new WpfSampleEntities2();

    public MainMenu()
    {
        InitializeComponent();
    }

    private void Button_Click_1(object sender, RoutedEventArgs e)
    {
        EmployeeDetails ed = new EmployeeDetails();
        ed.DataContext = ed.DomainEmployees;
        Binding bin = new Binding("GridView");
        bin.Source = ed.DomainEmployees;

        foreach (var item in ed.DomainEmployees)
        {
            bin.Path.PathParameters.Add(item);
        }

        ed.Show();
    }

}

And here is the EmployeeDetails.cs class/vm:

[TypeConverter(typeof(DataGridTextColumn))]
public class MVVMEmployee : Employee
{
    public int Id { get; set; }
    public string FullName { get; set; }
    public string Title { get; set; }
    public string WorkStatus { get; set; }

    public MVVMEmployee() { }
    public MVVMEmployee(int id, string fullName, string title, string workStatus)
    {
        this.Id = id;
        this.FullName = fullName;
        this.Title = title;
        this.WorkStatus = workStatus;
    }
}

I've also tried with the XAML as:

<DataGrid
    x:Name="DataGridEmployees"
    DataContext="{Binding RelativeSource={RelativeSource AncestorType=Window}}"
    ItemsSource="{Binding GridView}"
    AutoGenerateColumns="True"
    Loaded="dataGrid1_Loaded"
    Margin="0,2,0,-2" Grid.ColumnSpan="2">
    <DataGrid.Columns>
        <DataGridTextColumn Header="EmployeeId" Width="175" Binding="{Binding ElementName=Id}" ></DataGridTextColumn>
        <DataGridTextColumn Header="Title" Width="175" Binding="{Binding ElementName=Title}"></DataGridTextColumn>
        <DataGridTextColumn Header="WorkStatus" Width="175" Binding="{Binding ElementName=WorkStatus}"></DataGridTextColumn>
        <DataGridTextColumn Header="FullName" Width="175" Binding="{Binding ElementName=FullName}"></DataGridTextColumn>
    </DataGrid.Columns>
</DataGrid>

Upvotes: 22

Views: 51270

Answers (4)

Khalil Hidri
Khalil Hidri

Reputation: 1

Try adding Property to your View model With same property binding in your Xaml "GridView" then , this property Type should be Iobservablecollection that raises the RaisePropertyChanged() method Example :

        private ObservableCollection<Employee> _GridView = new 
        ObservableCollection<Employee>();
        public ObservableCollection<Employee> Publishers
        {
            get { return _GridView; }
            set { _GridView = value; RaisePropertyChanged(); }
        }

Please notice that you have to implement the INotifyPropertyChanged interface in you ViewModel and set the DataContext Of you View To your ViewModel like this :

ViewModel WM = new ViewModel ();
     this.DataContext = WM ;

Upvotes: 0

A. Dzebo
A. Dzebo

Reputation: 646

How you tried to implement it is simply not the way to go. First you need to separate the concerns and avoid mixing view and ViewModel. In the ViewModel create an ObservableCollection of your object (in your case MVVMEmployee ) which shall be implemented as a separate Model with NotifyPropertyChanged Event implemented and attached to your properties. Then simply create in your Window.cs constructor an instance of your ViewModel (let's call it vm) and set this.DataContext = vm; And then Bind the ItemsSource of the DataGrid to your collection from your viewModel like ItemsSource = {Binding MyEmployeesCollection} (no RelativeSource needed). Then bind each Text Column like i.e. Binding = {Binding FullName}. And don't forget to Implement INotifyPropertyChanged both on your model and on your ViewModel. That is one of the ways to implement your task in a clean MVVM manner. There are also other clean ways. I.e. You could Bind the DataContext to an instance of your ViewModel direct in the Window.xaml.

Upvotes: 0

t2solve
t2solve

Reputation: 928

I would suggest to use the ICollectionView interface im my Window or better in my modelview class

Here is a example MainWindow.xaml.cs class, which demonstrates how to add data to such interface Class in via code-behind:

using System.Collections.Generic;
using System.ComponentModel;
using System.Windows;
using System.Windows.Data;
using System.Windows.Input;

namespace WpfAppTest
{
    public partial class MainWindow : Window
    {
        public ICollectionView MyMVVMEmployeeList { get; private set; }

        public MainWindow()
        {
            InitializeComponent();
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            List<MVVMEmployee> list = new List<MVVMEmployee>();
            list.Add(new MVVMEmployee(23, "foomaster", "dr", "busy"));
            list.Add(new MVVMEmployee(42, "author", "mister", "dead"));

            MyMVVMEmployeeList = CollectionViewSource.GetDefaultView(list);

            //we call update gui //not needed when using modelview in pure mvvm 
            DataContext = this; 
        }
    }
}

The Binding in the MainWindow.xaml should then looks like:

<Window x:Class="WpfAppTest.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:local="clr-namespace:WpfAppTest"
        mc:Ignorable="d"
        DataContext="MainWindow"
        Title="MainWindow" Height="450" Width="800">
    <!-- for mvvm pattern using the model for datacontext deps e.g. like -->
    <!--  DataContext="{Binding Main,Source={StaticResource Locator}}"> -->
    <Grid>
        <StackPanel Orientation="Vertical">
            <DataGrid x:Name="DataGridEmployees"
                    ItemsSource="{Binding MyMVVMEmployeeList }"
                    AutoGenerateColumns="False">
                <DataGrid.Columns>
                    <DataGridTextColumn Header="EmployeeId" Width="175" Binding="{Binding Id}" ></DataGridTextColumn>
                    <DataGridTextColumn Header="Title" Width="175" Binding="{Binding Title}"></DataGridTextColumn>
                    <DataGridTextColumn Header="WorkStatus" Width="175" Binding="{Binding WorkStatus}"></DataGridTextColumn>
                    <DataGridTextColumn Header="FullName" Width="175" Binding="{Binding FullName}"></DataGridTextColumn>
                </DataGrid.Columns>
            </DataGrid>
            <Button Content="add" HorizontalAlignment="Left" Click="Button_Click"/>
        </StackPanel>
    </Grid>
</Window>

To make it fully runnable here your data class MVVMEmployee.cs again without refereing the base class:

namespace WpfAppTest
{
    public class MVVMEmployee 
    {
        public int Id { get; set; }
        public string FullName { get; set; }
        public string Title { get; set; }
        public string WorkStatus { get; set; }

        public MVVMEmployee() { }
        public MVVMEmployee(int id, string fullName, string title, string workStatus)
        {
            this.Id = id;
            this.FullName = fullName;
            this.Title = title;
            this.WorkStatus = workStatus;
        }
    }
}

Please change the namepspace WpfAppTest while including the example above. I would also suggest not use the code behind and use the MyMVVMEmployeeList the same way in your modelview class to follow more the mvvm pattern.

Upvotes: 2

user1656632
user1656632

Reputation:

myWindow w = new myWindow();
         w.DataContext = myViewModel;
         w.Show();

DataContext="{Binding RelativeSource={RelativeSource AncestorType=Window}}"

OR

<Window x:Name="MyWindow" />
    //DataGrid
    {Binding DataContext, ElementName=MyWindow}
    ItemsSource="{Binding MyViewModel.MyList}"

Upvotes: 0

Related Questions