Infii
Infii

Reputation: 91

Automatically Get Data from DataBase in ObservableCollection : WPF MVVM Caliburn Micro

I am working on Data Management project which was designed in WinForms and not I am redesigning it in WPF(MVVM) I am using caliburn micro obviously to reduce development time and flexibility, I came across a huddle where I want to refresh the Data Grid as soon as I save the data into Database. Here is explanation of what i want to achieve.

1) GameModel : Contains 5 properties same as Database(GameID,GameName,GameCategory,GameCompany,GamePrice)

private string _gameID;
    private string _gameName;
    private string _gameComp;
    private string _gameCat;
    private int _gamePrice;

    public int GamePrice
    {
        get { return _gamePrice; }
        set
        {
            _gamePrice = value;
            NotifyOfPropertyChange(() => GamePrice);
        }
    }
    public string GameCat
    {
        get { return _gameCat; }
        set { _gameCat = value;
            NotifyOfPropertyChange(() => GameCat);
        }
    }
    public string GameComp
    {
        get { return _gameComp; }
        set { _gameComp = value;
            NotifyOfPropertyChange(() => GameComp);
        }
    }
    public string GameName
    {
        get { return _gameName; }
        set { _gameName = value;
            NotifyOfPropertyChange(() => GameName);
        }
    }
    public string GameID
    {
        get { return _gameID; }
        set { _gameID = value;
            NotifyOfPropertyChange(() => GameID);
        }
    }

2) GameData (DataAccessLayer): Contains method to Add data into database for sake of simplicity I am using DataTable for this example to get the answer.

DataTable dt;
    public GameData()
    {
         dt = new DataTable("gameMaster");
        DataColumn col1 = new DataColumn("Srno", typeof(int));
        col1.AutoIncrement = true;
        col1.AutoIncrementSeed = 1;
        dt.Columns.Add(col1);
        dt.Columns.Add("GameID", typeof(string));
        dt.Columns.Add("GameName", typeof(string));
        dt.Columns.Add("GameComp", typeof(string));
        dt.Columns.Add("GameCat", typeof(string));
        dt.Columns.Add("GamePrice", typeof(int));
    }
    public bool AddNewGame(GameModel gm)
    {
        try
        {
            dt.Rows.Add(null, gm.GameID, gm.GameName, gm.GameComp, gm.GameCat, gm.GamePrice);
            return true;
        }
        catch (Exception e)
        {
            MessageBox.Show(e.ToString());
            return false;
        }
    }

    public List<GameModel> GetAllGames()
    {
        var gameList = new List<GameModel>();
        foreach(DataRow row in dt.Rows)
        {
            var game = new GameModel
            {
                GameID = row[1].ToString(),
                GameName = row[2].ToString(),
                GameComp= row[3].ToString(),
                GameCat= row[4].ToString(),
                GamePrice= (int)row[5],
            };
            gameList.Add(game);
        }
        return gameList;
    }

3) GameViewModel : Contains ObservableCollection which gets data from GameData : GetAllGames method.

public GameData _gameData;
    public GameModel _gameModel;
    public GameViewModel()
    {
        GameCat.Add("Action");
        GameCat.Add("Arcade");
        GameCat.Add("Racing");
        GameCat.Add("Puzzle");
        GameCat.Add("Other");
        GameComp.Add("EA");
        GameComp.Add("EA Sports");
        GameComp.Add("Ubisoft");
        _gameData = new GameData();
        RefreshGames();
    }
    private ObservableCollection<GameModel> _allGames;
    public ObservableCollection<GameModel> AllGames
    {
        get { return _allGames; }
        set
        {
            _allGames = value;
            NotifyOfPropertyChange(() => AllGames);
        }
    }

    public void AddNewGame(string gameID, string gameName, string gameCat, string gameComp, int gamePrice)
    {
        _gameModel = new GameModel
        {
            GameID = gameID,
            GameName = gameName,
            GameCat = gameCat,
            GameComp = gameComp,
            GamePrice = gamePrice
        };

        if (_gameData.AddNewGame(_gameModel))
        {
            RefreshGames();
            MessageBox.Show("Game Added succesfully !");
        }
    }
    public void RefreshGames()
    {
        var obj = new ObservableCollection<GameModel>(_gameData.GetAllGames());
        AllGames = obj;
    }

Here I've to use another method in order to Refresh the ObservableCollection or you can say to populate data from DB. I want that whenever I add any data this should be automatically done. How to make it aware that any insertion was done.

And for reference I am sharing the last portion of the code View as follow :

<!--row1-->
    <TextBox Grid.Row="1" Grid.Column="1" materialDesign:HintAssist.Hint="GameID" materialDesign:HintAssist.IsFloating="True" x:Name="GameID"/>
    <!--row2-->
    <TextBox Grid.Row="2" Grid.Column="1" x:Name="GameName"/>
    <!--row3-->
    <ComboBox Grid.Row="3" Grid.Column="1" x:Name="GameCat" SelectedIndex="0"/>
    <!--row4-->
    <ComboBox Grid.Row="4" Grid.Column="1" x:Name="GameComp" SelectedIndex="0"/>
    <!--row5-->
    <TextBox Grid.Row="5" Grid.Column="1" x:Name="GamePrice"/>
    <!--row6-->
    <StackPanel Orientation="Horizontal" Grid.Row="6" Grid.Column="1" HorizontalAlignment="Right">
        <Button Content="Save" Width="60" x:Name="AddNewGame"/>
        <Button Content="Exit" Width="60" x:Name="Exit"/>
    </StackPanel>
    <!--row7-->
    <ListView Grid.Column="1" Grid.Row="7" ItemsSource="{Binding Path=AllGames}">
        <ListView.View>
            <GridView>
                <GridViewColumn Header="GameID" Width="Auto" DisplayMemberBinding="{Binding Path=GameID}"/>
                <GridViewColumn Header="GameName" Width="Auto" DisplayMemberBinding="{Binding Path=GameName}"/>
                <GridViewColumn Header="Category" Width="Auto" DisplayMemberBinding="{Binding Path=GameComp}"/>
                <GridViewColumn Header="Company" Width="Auto" DisplayMemberBinding="{Binding Path=GameCat}"/>
                <GridViewColumn Header="Price" Width="Auto" DisplayMemberBinding="{Binding Path=GamePrice}"/>
            </GridView>
        </ListView.View>
    </ListView>

Binding Works Fine, Data is showing fine but I want it to be done Automatically, Please let me know how can i do this without calling the RefreshGames method.

Thank you in Advance and sorry if this question is long but for sake of understanding i had to put everything.

if any one wants to share their review on Code please share it.

Upvotes: 0

Views: 2301

Answers (1)

Andy
Andy

Reputation: 12276

An observablecollection notifies collection changed when you add or remove entries from it. You seem to be talking about

public ObservableCollection<GameModel> AllGames

Which is in the same viewmodel as AddNewGame. If you just do

AllGames.Add(_gameModel);

In AddNewGame.
Then your ListView will show the new game as a new row.

An assumption here is that the one user is adding and viewing the games.
In a situation where other users could insert a new game and you want to see that appear then the simple solution is to poll the database every few minutes.
That isn't practical if you have a LOT of users and a lot of data changing but this doesn't look like that sort of a requirement.

Upvotes: 0

Related Questions