wpf listview 大数据界面刷新

最近公司在做一个Windows项目,其中主界面需要实时更新数据,大概是0.5秒刷一次数据。一开始想用winform做的,思路是使用winform把界面画出来然后显示。但是觉得比较复制而且麻烦,后来查看了网上资料,感觉使用wpf就不用那么麻烦,而且代码都比较少而且清晰,而且支持更改数据就能刷新界面,决定试验一把。
网上关于listview的资料不少,但是都是片面的,或者不全。
好了,现在开始,新建wpf项目,添加用户控件,在用户控件里添加listview控件,并添加数据模板。
定义数据模型:

public class DataModelValueList : ObservableCollection<DataModelValue>

{

}

public class DataModelValue : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    public int ID { get; set; }

    private string no;
    public string No
    {
        get { return no; }
        set
        {
            if (no != value)
            {
                no = value;
                if (this.PropertyChanged != null)
                {

                    this.PropertyChanged.Invoke(this, new PropertyChangedEventArgs("No"));
                }
            }
        }
    }

    private string name;
    public string Name
    {
        get { return name; }
        set
        {
            if (name != value)
            {
                name = value;
                if (this.PropertyChanged != null)
                {

                    this.PropertyChanged.Invoke(this, new PropertyChangedEventArgs("Name"));
                }
            }
        }
    }

    private string v;
    public string V
    {
        get { return v; }
        set
        {
            if (v != value)
            {
                v = value;
                if (this.PropertyChanged != null)
                {

                    this.PropertyChanged.Invoke(this, new PropertyChangedEventArgs("V"));
                }
            }
        }
    }
    private string i;
    public string I
    {
        get { return i; }
        set
        {
            if (i != value)
            {
                i = value;
                if (this.PropertyChanged != null)
                {

                    this.PropertyChanged.Invoke(this, new PropertyChangedEventArgs("I"));
                }
            }
        }
    }
    private string c;
    public string C
    {
        get { return c; }
        set
        {
            if (c != value)
            {
                c = value;
                if (this.PropertyChanged != null)
                {

                    this.PropertyChanged.Invoke(this, new PropertyChangedEventArgs("C"));
                }
            }
        }
    }
    private string t;
    public string T
    {
        get { return t; }
        set
        {
            if (t != value)
            {
                t = value;
                if (this.PropertyChanged != null)
                {

                    this.PropertyChanged.Invoke(this, new PropertyChangedEventArgs("T"));
                }
            }
        }
    }
}

然后给用户控件添加属性:

    private DataModelValueList dataModelValueList;
    public DataModelValueList DataModelValueList
    {
        get { return dataModelValueList; }
        set
        {
            dataModelValueList = value;
            lv.ItemsSource = dataModelValueList;
        }
    }

给该属性赋值的时候会自动更新界面,注意,只有数据更改才会刷新,而且是局部刷新。
在主界面窗体添加:

修改主窗体类如下:
public MainWindow()
{
InitializeComponent();

        InitialListViewData();
        var userControl1 = new UserControl1();
        userControl1.DataModelValueList = dataModelValueList;
        listViewContainer.Children.Add(userControl1);
        Task.Factory.StartNew(Begin);
    }


    private static DataModelValueList dataModelValueList = new DataModelValueList();
    private readonly TaskScheduler _syncContextTaskScheduler = TaskScheduler.FromCurrentSynchronizationContext();
    private readonly TaskScheduler _syncContextTaskSchedulerTest = TaskScheduler.FromCurrentSynchronizationContext();
    private static int count = 1;
    private static int totalCount = 512 * 2;
    private static int initialCompletedCount = 0;

    private void InitialListViewData()
    {
        var temp = "0";

        for (var i = 0; i < 1024; i++)
        {
            dataModelValueList.Add(new DataModelValue() { ID = i, No = temp, Name = temp, C = temp, V = temp, I = temp, T = temp }); ;
        }
    }

    private void Begin()
    {
        while (true)
        {
            Thread.Sleep(500);
            Task.Factory.StartNew(() => RefreshData(), new CancellationTokenSource().Token, TaskCreationOptions.None, _syncContextTaskScheduler).Wait();
        }
    }

    private void RefreshData()
    {
        //return;
        count += 1;
        var temp = count.ToString();

        for (var i = 0; i < totalCount; i++)
        {
            dataModelValueList[i].Name = temp;
            dataModelValueList[i].No = temp;
            dataModelValueList[i].C = temp;
            dataModelValueList[i].I = temp;
            dataModelValueList[i].T = temp;
            dataModelValueList[i].V = temp;
        }
    }

程序运行起来后如图:
在这里插入图片描述 要是操作一下,比如拉动滚动条,感觉有点卡顿,因为是刷新全部数据,1024个数据,要是数据更多,比如几千个,那会更卡。
怎么办?
能不能只刷新屏幕可见范围内的数据?因为屏幕可见数据也就几十个,相比刷新1000个,那就太好了!相干就干!
首先要获取到屏幕第一个可见数据,然后根据每个数据的长宽就可以计算出可见屏幕里装的数据。到网上搜获取listview可见数据,好像没有完整方案,只查到获取第一个可见数据的,这就离成功不远了啊。
在用户控件里增加代码:

    public Tuple<int, int> Test()
    {
        int startIndex = -1;
        int endIndex = -1;

        HitTestResult hitTest = VisualTreeHelper.HitTest(lv, new Point(5, 5));
        System.Windows.Controls.ListViewItem item = GetListViewItemFromEvent(null, hitTest.VisualHit) as System.Windows.Controls.ListViewItem;
        startIndex = ((DataModelValue)item.DataContext).ID;
        endIndex = startIndex;

        endIndex += (int)Math.Ceiling((lv.ActualWidth / item.ActualWidth + 1) * (lv.ActualHeight / item.ActualHeight + 1));

        return new Tuple<int, int>(startIndex, endIndex);
    }

    System.Windows.Controls.ListViewItem GetListViewItemFromEvent(object sender, object originalSource)
    {
        DependencyObject depObj = originalSource as DependencyObject;
        if (depObj != null)
        {
            // go up the visual hierarchy until we find the list view item the click came from  
            // the click might have been on the grid or column headers so we need to cater for this  
            DependencyObject current = depObj;
            while (current != null && current != lv)
            {
                System.Windows.Controls.ListViewItem ListViewItem = current as System.Windows.Controls.ListViewItem;
                if (ListViewItem != null)
                {
                    return ListViewItem;
                }
                current = VisualTreeHelper.GetParent(current);
            }
        }

        return null;
    }

然后主界面修改更新数据函数:
private void RefreshData()
{
var a = ((UserControl1)listViewContainer.Children[0]).Test();
//return;
count += 1;
var temp = count.ToString();

        for (var i = 0; i < totalCount; i++)
        {
            if (i < a.Item1 || a.Item2 < i)
            {
                continue;
            }
            dataModelValueList[i].Name = temp;
            dataModelValueList[i].No = temp;
            dataModelValueList[i].C = temp;
            dataModelValueList[i].I = temp;
            dataModelValueList[i].T = temp;
            dataModelValueList[i].V = temp;
        }
    }

然后程序跑起来,现在随便拖拉滚动条,也不卡顿了,万岁!
最后,要是数据量很大,比如几千条,那么程序启动的时候就会比较慢,有可能需要一段时间,比如20秒,这个感觉也不大好,因为启动这段时间里,界面是空白的,用户会任务程序死掉了。解决办法是:启动时,开启一个新的线程,然后定时加载数据,比如每隔3秒加载500条数据,如果总共是5000条,那么就要加载30秒,程序启动过程中就能看到数据,而且滚动条会不断变短,但是还是会有点卡,没办法啦。等加载完数据就不卡了。
最后呈上代码:
链接:https://pan.baidu.com/s/1KgoC5nSzQCpZ1m4cb_ZaYA
提取码:1234

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值