拙网论坛

 找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 224|回复: 0

Simple ObservableCollection WPF MVVM example

[复制链接]

949

主题

1001

帖子

3736

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
3736
发表于 2020-4-1 10:37:38 | 显示全部楼层 |阅读模式


Monday, February 17, 2014Simple ObservableCollection WPF MVVM example

Using ObservableCollection has its benefit. Whenever any element changes (added, deleted or updated or entire list being replaced) within the ObservableCollection instatnce, the bound UI element automatically reflects the changes.


If you would like to know more details of ObservableCollection, please read from the API link below.

http://msdn.microsoft.com/en-us/library/ms668604%28v=vs.110%29.aspx


We can use ObservableCollection object and bindable property in a View Model class and bind this to a UI control such as DataGrid's ItemsSource property. Whenever anything changes in the ObservableCollection, bound grid will automatically reflect the changes in the UI.

ViewModel class as follows:



    public class TradesViewModel : BaseViewModel, ITradeViewModel
    {
        private ObservableCollection<Trade> _trades = new ObservableCollection<Trade>();

        private ICommand _saveCommand;
        private ICommand _loadCommand;

        public TradesViewModel()
        {
            _saveCommand = new SaveTradesCommand();
            _loadCommand = new LoadTradesCommand();
            _trades = GetTrades();
        }

        public ObservableCollection<Trade> Trades { get {return _trades;} }

        public ObservableCollection<Trade> GetTrades()
        {
            if (_trades == null || _trades.Count == 0)
                _loadCommand.Execute(_trades);
            return _trades;
        }
    }



Lets say _loadCommand's code populates the _trades ( ObservableCollection). For demonstrating live updates we have made a infinite loop in the loading where every 2 seconds it loads new trades with quantity and price being different. Below is the code loading trades data every 2 seconds.



public void Execute(object parameter)
        {
            var loadedTrades = parameter as ObservableCollection<Trade>;
            if (loadedTrades != null)
            {
                TaskFactory taskfac = new TaskFactory();
                taskfac.StartNew(() =>
                    {
                        while (true)
                        {
                            var tradelist = Trades.LoadTradesFromDataSource();
                            App.Current.Dispatcher.Invoke(new Action(() =>
                            {
                                loadedTrades.Clear();
                                foreach (var trade in tradelist)
                                    loadedTrades.Add(trade);
                            }));

                            Thread.Sleep(2000);
                        }
                    });
            }
        }


Trade and load trades code:



public class Trade : ITrade   
{
        private string _qty;
        public string Side { get; set; }
        public string Ticker { get; set; }
        public string Qty { get; set; }
        public string Price { get; set; }
        public string Trader { get; set; }
        public string Sales { get; set; }
       }





public class Trades
       {
        public static IEnumerable<Trade> LoadTradesFromDataSource()
        {
            var pricetmp = DateTime.Now.Second; // just to get some number
            var qtytmp = (DateTime.Now.Second + 5) * 1000; // just to get some
number

            return new List<Trade>()
            {
                new Trade(){Side="B", Price=pricetmp.ToString(), Ticker="aol",
Trader="tom", Sales="harry", Qty=qtytmp.ToString()},
                new Trade(){Side="B", Price=pricetmp.ToString(), Ticker="gm",
Trader="tom", Sales="harry", Qty=qtytmp.ToString()},
                new Trade(){Side="B", Price=pricetmp.ToString(), Ticker="ge",
Trader="tom", Sales="harry", Qty=qtytmp.ToString()},
            };
        }
       }



XAML code as below binds the ItemsSource property of the DataGrid to our ViewModel's ObservableCollection property called Trades.


<Grid.DataContext>
            <viewmodel:TradesViewModel/>
        </Grid.DataContext>
        <DataGrid
                AutoGenerateColumns="True"
                HorizontalAlignment="Stretch" Name="dataGrid1" VerticalAlignment="Top"
                ItemsSource="{Binding Trades}"
                />


When we run this application, we see a window coming up with trades populated like below:




and every two seconds it will automatically show new trades data like below:




So as soon as the ObservableCollection data is being updated it is reflecting real-time on the DataGrid.


Notice three things:

Notice 1: I created a new "task" to run the infinite loop to update data every two seconds and therefore had to update using App.Current.Dispatcher.Invoke since ObservableCollection object was instantiated in UI thread. (see details here http://wpfgrid.blogspot.com/2014/02/wpf-using-dispatcher-in-viewmodel.html)

Notice 2:
Also if we simply make _trades = new ObservableCollection ...  it will not wok. Rather we need to clear the collection and add new instances of Trade objects.

Notice 3:
Since in this exmaple (only) we are replacing the enter list (by clearing and add all elements), we did not need to implement INotofyPropertyChanged niterface in "Trade" class. However, we should implement that interface in Trade class and have each property raise property changed event, that way when any property value changes (instead of entire list being changed as shown in this example), it will reflect the change of that particular cell in the DataGrid automatically.



















回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|抱朴守拙BBS

GMT+8, 2025-5-26 03:31 , Processed in 0.194074 second(s), 18 queries .

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表