0

I have the following xaml, as you can see the DataGrids are being populated via DataProviders.

<Window x:Class="MobileDeviceAuthenticator.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:MobileDeviceAuthenticator"
        Title="Device Authorization" Height="381" Width="879" AllowDrop="True">
    <Window.Resources>
        <!-- create an instance of our DataProvider class -->
        <ObjectDataProvider x:Key="MobileManagerDataProvider" ObjectType="{x:Type local:MobileManagerDataProvider}"/>
        <!-- define the method which is invoked to obtain our data -->
        <ObjectDataProvider x:Key="MOBILE_MANAGER" ObjectInstance="{StaticResource MobileManagerDataProvider}" MethodName="GetDevices"/>
        <!-- create an instance of our DataProvider class -->
        <ObjectDataProvider x:Key="MobileRequestDataProvider" ObjectType="{x:Type local:MobileRequestDataProvider}"/>
        <!-- define the method which is invoked to obtain our data -->
        <ObjectDataProvider x:Key="MOBILE_REQUESTS" ObjectInstance="{StaticResource MobileRequestDataProvider}" MethodName="GetDevices"/>
    </Window.Resources>
    <Grid Name="GridContainer" >
        <Grid>
            <DataGrid Name="dgAuthorization" 
                      HorizontalAlignment="Stretch"
                      VerticalAlignment="Stretch" 
                      DataContext="{Binding Source={StaticResource MOBILE_MANAGER}}" 
                      ItemsSource="{Binding}" 
                      AutoGenerateColumns="False" >
                <DataGrid.Columns>
                    <DataGridTextColumn Binding="{Binding Path=DESCRIPTION}" Header="Description" />
                    <DataGridTextColumn Binding="{Binding Path=DEVICE_TYPE}" Header="Device Type" IsReadOnly="True" />
                    <DataGridTextColumn Binding="{Binding Path=DEVICE_ID}" Header="Device ID" IsReadOnly="True" />
                </DataGrid.Columns>
            </DataGrid>
        </Grid>
        <Grid>
            <DataGrid Name="dgRequest" 
                      SelectionMode="Single" 
                      HorizontalAlignment="Stretch"
                      VerticalAlignment="Stretch"
                      DataContext="{Binding Source={StaticResource MOBILE_REQUESTS}}"
                      ItemsSource="{Binding}"  
                      AutoGenerateColumns="False" >
                <DataGrid.Columns>
                    <DataGridTextColumn Binding="{Binding Path=DESCRIPTION}" Header="Description" />
                    <DataGridTextColumn Binding="{Binding Path=DEVICE_TYPE}" Header="Device Type" IsReadOnly="True" />
                    <DataGridTextColumn Binding="{Binding Path=DEVICE_ID}" Header="Device ID" IsReadOnly="True" />
                    <DataGridTextColumn Binding="{Binding Path=REQUEST_DATE}" Header="Request Date" />
                </DataGrid.Columns>
            </DataGrid>
        </Grid>
    </Grid>
</Window>

Here is the DataProvider class code

public class MobileManagerDataProvider
{
    private MobileManagerDataSetTableAdapters.MOBILE_MANAGERTableAdapter mmAdapter;
    private MobileManagerDataSet mmDataSet;

    public MobileManagerDataProvider()
    {
        mmDataSet = new MobileManagerDataSet();
        mmAdapter = new MobileManagerDataSetTableAdapters.MOBILE_MANAGERTableAdapter();
        mmAdapter.Fill(mmDataSet.MOBILE_MANAGER);

        mmDataSet.MOBILE_MANAGER.MOBILE_MANAGERRowChanged += new MobileManagerDataSet.MOBILE_MANAGERRowChangeEventHandler(AuthenticationRowModified);
        mmDataSet.MOBILE_MANAGER.MOBILE_MANAGERRowDeleted += new MobileManagerDataSet.MOBILE_MANAGERRowChangeEventHandler(AuthenticationRowModified);
    }

    public DataView GetDevices()
    {
        return mmDataSet.MOBILE_MANAGER.DefaultView;
    }

    void AuthenticationRowModified(object sender, MobileManagerDataSet.MOBILE_MANAGERRowChangeEvent e)
    {
        mmAdapter.Update(mmDataSet.MOBILE_MANAGER);
    }
}

In the code-behind I'd like to setup a Timer ticking away every minute refreshing the DataGrids.

The Timer is easy enough, however to refresh the data is eluding me. I've tried some of the following statements.

ObjectDataProvider dataProvider = this.TryFindResource("MobileManagerDataProvider") as ObjectDataProvider;
dataProvider.Refresh();

dgAuthorization.Items.Refresh();

CollectionViewSource.GetDefaultView(dgAuthorization.ItemsSource).Refresh();

To no avail, how can I achieve this?

Gopi
  • 236
  • 2
  • 6
  • 20
Hank
  • 2,456
  • 3
  • 35
  • 83
  • 1
    If you create 'ObservableCollection' object and bind it to the DataGrid, it will automatically updated in the DataGrid. – Gopi Dec 15 '17 at 06:03
  • Could you provide an example of how I could implement this into my project – Hank Dec 15 '17 at 06:39
  • The reason I ask is that my updates and so on, occur through the DataProvider and would have to get reflected in the ObservableCollection. So I wondering how I piece it all together. – Hank Dec 15 '17 at 08:35
  • I am assuming you are getting the data in DataSet, so you can copy it into ObservableCollection using foreach or for loop – Gopi Dec 15 '17 at 10:00
  • I replied with an example binding new data to the DataGrid every time you select an item in it, you can expand that case so every time your collection changes it will reflect in your DataGrid automatically – Celso Lívero Dec 15 '17 at 12:56

1 Answers1

1

this is a complete working example, every time you select an item (not same item twice) it will add a new random value as a new line in the DataGrid

I've responded with an example binding new data to the DataGrid every time you select an item in it, you can expand that case, so each time your collection changes, it will reflect in your DataGrid automatically, so whenever your data changes you just pass to the GridData property they will be updated in the view

MainWindow.xaml

<Window x:Class="BindingDataGrid.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:BindingDataGrid"
        Title="MainWindow" Height="350" Width="525">

        <Window.DataContext>
            <local:MainViewModel />
        </Window.DataContext>
    <Grid>
        <DataGrid  ColumnWidth="*" 
                    IsReadOnly="True"
                    AutoGenerateColumns="False"
                    SelectionMode="Single" 
                    HorizontalContentAlignment="Center" 
                    ItemsSource="{Binding GridData}"
                    SelectedItem="{Binding SelectedData, UpdateSourceTrigger=PropertyChanged}"
                    CanUserResizeRows="False"
                    ScrollViewer.CanContentScroll="True"
                    ScrollViewer.VerticalScrollBarVisibility="Auto"
                    ScrollViewer.HorizontalScrollBarVisibility="Auto">
            <DataGrid.Columns>
                <DataGridTextColumn Header="Column 01" Binding="{Binding Column1}"   Width="*"/>
                <DataGridTextColumn Header="Column 02" Binding="{Binding Column2}"   Width="*"/>
            </DataGrid.Columns>
        </DataGrid>
    </Grid>
</Window>

MainWindow.xaml.cs Nothing here, just remove unused references

using System.Windows;

namespace BindingDataGrid  //`BindingDataGrid` is my namespace
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }
    }
}

all references you need in your MainViewModel

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;

MainViewModel

public class MainViewModel: INotifyPropertyChanged
{
    Random _rnd = new Random();
    private MyGridData _selectedData;
    private ObservableCollection<MyGridData> _gridData;
    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    public MainViewModel()
    {
        var newData = new List<MyGridData>
        {
            new MyGridData { Column1 = "AAAAAA 01", Column2 = "aaaaaaaa 02" },
            new MyGridData { Column1 = "BBBBBB 01", Column2 = "bbbbbbbb 02" },
            new MyGridData { Column1 = "CCCCCC 01", Column2 = "cccccccc 02" },
        };
        GridData = new ObservableCollection<MyGridData>(newData);
    }

    public MyGridData SelectedData
    {
        get { return _selectedData; }
        set
        {
            if (value == _selectedData) //if same item selected
                return;
            _selectedData = value;
            OnPropertyChanged();

            DoSomethingWhenValueChanged(); // Will add a new line
        }
    }
    public ObservableCollection<MyGridData> GridData
    {
        get { return _gridData; }
        set
        {
            if (value == _gridData)
                return;
            _gridData = value;
            OnPropertyChanged();
        }
    }

    private void DoSomethingWhenValueChanged()
    {
        var newData = GridData.ToList();
        newData.Add(new MyGridData { Column1 = (_rnd.Next(100)).ToString(), Column2 = (_rnd.Next(1000)).ToString() }); //Add new random item

        GridData = new ObservableCollection<MyGridData>(newData);  //update your DataGrid
    }
}

public class MyGridData
{
    public string Column1 { get; set; }
    public string Column2 { get; set; }
}
Celso Lívero
  • 716
  • 2
  • 14
  • 18
  • [PropertyChanged?.Invoke] design time is error on this part. – Hank Dec 17 '17 at 03:49
  • Do I surround it by "if (PropertyChanged != null)" and delete the question mark? – Hank Dec 17 '17 at 03:50
  • However that's pretty understandable as far as view and viewmodel and populating the ObservableCollection. What I'm having trouble understanding now is, how to recognize when a row has been added, deleted or updated, I populate the OC by calling GetDevices() and copy each DataRowView, when I select a row, edit a column and then select a new row it updates automatically through the DataProvider, it used to do this automatically for adding or deleting a row as well. In fact the add row has disappeared even with CanUserAddRows=True. How do I accomplish this now? – Hank Dec 17 '17 at 04:28
  • "Do I surround it by "if (PropertyChanged != null)" and delete the question mark?" yes. this is C# version 6 – Celso Lívero Dec 18 '17 at 09:26
  • here you can see how to add rows using MVVM - https://stackoverflow.com/q/20195808/5605739 – Celso Lívero Dec 18 '17 at 09:34
  • @Hank This can also help you. https://stackoverflow.com/q/4617810/5605739 – Celso Lívero Dec 18 '17 at 09:40