WPF 異步加載數據


發個從網上找到代碼,供參考吧。

private void Window_Loaded(object sender, RoutedEventArgs e)
{
  var Loads= this.Dispatcher.BeginInvoke(new Action(() =>
  {
  // 這里執行其它耗時操作 
  }));
  Loads.Completed += new EventHandler(Loads_Completed);
}

void Loads_Completed(object sender, EventArgs e)
{
//執行完成后的操作,如隱藏加載提示文字,顯示加載完成后的數據等
}

出處:https://blog.csdn.net/ht_zhaoliubin/article/details/45482203

=================================================================================

加載某個界面時,需要獲取數據,而數據返回的時間比較長,這個時候可以異步加載界面。

1、在該窗體的加載事件(Load)中編寫以下代碼:
 new Thread(p=>{DataBinding();}).Start();
2、界面加載時獲取數據和綁定數據都寫在DataBinding()方法中
private void DataBinding()
{
this.Dispatcher.BeginInvoke(new Action(()=>{
//編寫獲取數據並顯示在界面的代碼
}));
}

 

出處:https://www.cnblogs.com/xiaomianyang/p/6416074.html

=================================================================================

前言:以前使用數據庫搜數據后直接傳到前台設置,后來學會了綁定,界面結合部分總算是有了點經驗,But....有時候搜數據沒那么快,要等待數據返回的時候界面假死,白屏,很崩潰,后來使用了幾種方法 :1.延遲加載先出來界面,在賦值數據 ,2.利用多線程加載,但是一開始的時候會是空白(可以預先初始化來解決),然后搭配complate事件;3.邏輯控制,就是自己想一些辦法讓程序看起來是正常的,比如加載頁,延時,鎖死等..;

然而:我今天要講的是異步加載,並且包含綁定部分的代碼;

下面這一部分是 在一個匯總類(class)里 需要收集 值的方法  並且在每一個屬性值賦值的時候通知前台頁面改變

如果不需要報告進度 一段一段顯示 可以直接等最終結果;

不說了上代碼;

public async Task MyMethodAsync(IProgress<TaskCallBackValue> progress)
        {
            TaskCallBackValue percentCompleate = new TaskCallBackValue();
            if (progress == null)
            {
                throw new Exception("必須實現報告進度方法!");
            }
 
            await Task.Delay(TimeSpan.FromSeconds(3));//模擬卡頓效果 
            Task<int> T1 = SugarBase.DB.Queryable<property_house_info>().CountAsync(x => x.take_effect != 2);
           
            progress.Report(new TaskCallBackValue { Name = "TotalHouseNumber", Value = T1.Result });
           
 
            await Task.Delay(TimeSpan.FromSeconds(2));//模擬卡頓效果
            Task<int> T2 = SugarBase.DB.Queryable<property_house_info>().CountAsync(x => x.take_effect == 0);
           
            progress.Report(new TaskCallBackValue { Name = "TotalInuseHouseNumber", Value = T2.Result });
        }
 
        public class TaskCallBackValue
        {
            public string Name { get; set; }
            public object Value { get; set; }
 
        }

 

這一段 其實有點類似 BackgroundWork 里的ProgressChanged 事件 這是第一個部分

那么在頁面搜索方法中少不了 this.DataContext =this 這樣的綁定 

《textBlock  text{binding  Youdata.Data1}.....

《textBlock  text{binding  Youdata.Data2}.....

public void CallMyMethodAsync()
        {
            var progress = new Progress<TaskCallBackValue>();
            progress.ProgressChanged += (sender, e) =>
            {
                Type t = typeof(HomeSummary);
                var Pr = t.GetProperty(e.Name);
                if (Pr != null)
                {
                    Pr.SetValue(CurrentSummaryData, e.Value, null);
                   
//CurrentSummaryData.OnChange(e.Name);//本來想開放PropertyChange事件沒想到居然不需要也能觸發界面刷新               
 }
 
            };
            MyMethodAsync(progress);
 
        }

 

這個地方就要說一說了,我傳出來的是屬性名稱 和屬性的值,但是總不能  class.name1=value ;class.name2=value 這樣賦值

所以找了反射的代碼利用PropertyInfo的方法給我的匯總類里面的屬性賦值 這樣 從小方法里發回的異步通知就具有了通用性

 

在前台的效果是 預設界面直接顯示無卡頓,  兩個TextBlock的值 分別是第3秒和第5秒顯示在了界面上

值的提到的是 這個方法里如果有一個出現了 錯誤那么整個方法都會異常,所以做好異常處理是很有必要的

並且 不能在主線程里await 可能會出現主線程屏蔽初始化,一點界面都沒有

綜上綜上 只是為了 一進界面不卡而已。 

方法摘自 :《C#並發編程經典實例》

 

出處:https://blog.csdn.net/sinat_30224769/article/details/81160142

=================================================================================

如何在WPF中加載大批量數據,並且不會阻塞UI線程,尤其是加載大量圖片時,這活兒一直是很多朋友都相當關注的。世上沒有最完美的解決之道,咱們但求相對較優的方案。

經過一些試驗和對比,老周找到了一種算是不錯的方案,重點是這個方案比較簡單,無須闖五關斬六將,只要你對數據綁定有些基礎就好了。

好,F話少扯,咱們開始吧。

老周手里沒有那么多照片,那就用同一張圖片做測試吧。假設我要在應用程序運行時加載 2 萬張圖片,我想2W張應該可以了,沒見過誰會傻到要加載100W張那么變態。

大致情況是:數據源集合是一個 ObservableCollection<Uri>, 也就是說集合中放的是圖像的URI,為什么不放BitmapSource 呢,因為 DependencyObject 是不能跨線程操作的,只能在UI線程上創建。默認情況下,ObservableCollection<T>也不能在非UI線程上操作,不過,我可以通過調用以下方法來讓它可以跨線程操作:

public static void EnableCollectionSynchronization(IEnumerable collection, object lockObject)

這個方法是 BindingOperations 類公開的靜態方法,可以在窗口的構造函數中調用它,而且一定要在操作集合之前調用。調用時,把 ObservableCollection 集合傳遞給 collection 參數,第二個參數lockObject 是一個自定義對象,它指的是可以在線程間同步時引用的對象,在異步代碼中,可以把這個對象寫在一個 lock 語句塊中。主要用途是防止UI訪問集合的過程中,集合被其他線程意外修改。

下面代碼開啟跨線程訪問集合支持:

            images = new ObservableCollection<Uri>();
            ……
            lbImages.SetBinding(ItemsControl.ItemsSourceProperty, b);

            // 這一句很關鍵,開啟集合的異步訪問支持
            BindingOperations.EnableCollectionSynchronization(images, lockobj);

 

然后在窗口的構造函數中,執行一個新 Task,用一個新線程來加載數據。

復制代碼
            Task.Run(() =>
            {
                // 代碼寫在 lock 塊中
                lock (lockobj)
                {
                    for (int i = 0; i < 20000; i++)
                    {
                        Uri u = new Uri("0.jpg", UriKind.Relative);
                        images.Add(u);
                    }
                }
            });
復制代碼

開始一個新Task是為了讓主線程不受阻止,可以繼續響應UI操作。

 

由於集合中都是 URI,而界面上顯示的是圖像,可以弄一個自定義的數據轉換器,轉換為位圖。

復制代碼
    public sealed class UriToBitmapConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            Uri uri = (Uri)value;
            BitmapImage bmp = new BitmapImage();
            bmp.DecodePixelHeight = 250; // 確定解碼高度,寬度不同時設置
            bmp.BeginInit();
            // 延遲,必要時創建
            bmp.CreateOptions = BitmapCreateOptions.DelayCreation;
            bmp.CacheOption = BitmapCacheOption.OnLoad;
            bmp.UriSource = uri;
            bmp.EndInit(); //結束初始化
            return bmp;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return null;
        }
    }
復制代碼

因為是單向轉換,所以ConvertBack就免了。

注意,在實例化BitmapImage時,DecodePixelHeight 和 DecodePixelWidth 屬性只能設置任意一個,不要同時設置,不然圖片的比例會變形。如果我們界面用的圖不需要很大,就設一個小的值,比如200像素,這樣可以節約性能。

還可以把 CreateOptions 屬性設為 DelayCreation ,這樣只在圖像需要時才會創建,也省了一些性能。

 

為了讓這個轉換器能在XAML代碼中訪問,需要把它的實例聲明在UI的資源列表中。

        <Grid.Resources>
            <local:UriToBitmapConverter x:Key="tobmpcvt"/>
        </Grid.Resources>

 

接下來就是用Binding了,實現界面綁定。

復制代碼
        <ListBox Name="lbImages" ScrollViewer.IsDeferredScrollingEnabled="False"
                 ScrollViewer.HorizontalScrollBarVisibility="Disabled">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <Image Height="200" Width="200" Source="{Binding IsAsync=True,Converter={StaticResource tobmpcvt}}"/>
                </DataTemplate>
            </ListBox.ItemTemplate>
            <ListBox.ItemsPanel>
                <ItemsPanelTemplate>
                    <WrapPanel Orientation="Horizontal"/>
                </ItemsPanelTemplate>
            </ListBox.ItemsPanel>
        </ListBox>
復制代碼

 

使用 Binding 時,把 IsAsync 屬性設為 True,這樣允許界面使用輔助線程來綁定數據,記得,記得。

 

這樣就完成了,然后我們可以運行,讓程序加載 2萬個圖像。這時候會發現,程序運行后不會卡住了,而且把滾動往下拖動時,會自動加載數據。

 

如何?這效果不錯吧。

示例源代碼下載地址

 

出處:https://www.cnblogs.com/tcjiaan/p/5532104.html

=================================================================================

 

我推薦使用BackgroundWork 進行異步數據下載,然后在完成事件里綁定數據。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM