WPF UI多任务 [英] WPF UI multitasking

查看:75
本文介绍了WPF UI多任务的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在以编程方式创建一些涉及大量处理的UI.基本上,我想要的是在构建UI或将其添加到窗口时运行加载程序动画. 添加的UI是一些网格和一些图像加载到其中.

I'm creating some UI programmatically which involves some heavy processing. Basically what i want is to run a loader animation while my UI is being built/added to the window. The UI being added are some Grids and some images being loaded into them.

到目前为止,我已经尝试过BackgroundWorker,但是由于我需要使用UI线程来添加正在构建的UI,因此加载器在添加完UI之前不会启动/动画化.

So far i've tried BackgroundWorker but since i need to use the UI thread to add the UI i'm building, the loader won't start/animate until the UI being added is finished.

我也尝试了一些异步方法,但没有任何结果. 我的最后一次尝试是这样的,但是它仍然需要访问UI线程,该线程最终将冻结UI动画,直到完成工作

I've also tried some async methods without any results. My last attempt was something like this, but it still need to access the UI thread which would eventually freeze the UI animation until the work is done

   private async void begin()
    {

        await this.LongRunOpAsync();

    }

    public Task LongRunOpAsync()
    {
        return Task.Run(() =>
        {
            InitGrid();
            stopLoadingScreen();
        });
    }

我可能会丢失一些东西,但是我不知道是什么,而且我也没有做到这一点的想法. 任何帮助将不胜感激.

I might be missing something, but i don't know what and i'm also out of ideas to do this. Any help would be appreciated.

工作繁重的方法

private void makeIgrid()
        {
            Grid hostgrid = new Grid();
            hostgrid.Name = "imagesHostGrid";
            hostgrid.Width = 700;
            hostgrid.VerticalAlignment = VerticalAlignment.Top;
            hostgrid.HorizontalAlignment = HorizontalAlignment.Center;
            hostgrid.SetValue(Canvas.ZIndexProperty, 0);
            this.RegisterName(hostgrid.Name, hostgrid);

            Grid imagegrid = new Grid();
            imagegrid.Name = "imagegrid";
            imagegrid.Height = height2;
            //imagegrid.Width = 700;
            imagegrid.SetValue(Canvas.ZIndexProperty, 0);
            imagegrid.VerticalAlignment = VerticalAlignment.Top;
            imagegrid.HorizontalAlignment = HorizontalAlignment.Center;
            imagegrid.Margin = new Thickness(0, height1, 0, 0);//(left,top,right,bottom)

            RowDefinition iRow1 = new RowDefinition();
            iRow1.Height = new GridLength(2, GridUnitType.Star);
            imagegrid.RowDefinitions.Add(iRow1);

            RowDefinition iRow2 = new RowDefinition();
            iRow2.Height = new GridLength(70, GridUnitType.Star);
            imagegrid.RowDefinitions.Add(iRow2);

            ScrollViewer sv = new ScrollViewer
            {
                CanContentScroll = true,
                HorizontalScrollBarVisibility = ScrollBarVisibility.Hidden,
                VerticalScrollBarVisibility = ScrollBarVisibility.Disabled
            };

            for (int i = 0; i < images.Length; i++)
            {
                ColumnDefinition columns = new ColumnDefinition();
                columns.MinWidth = 100;
                columns.Width = new GridLength(100, GridUnitType.Star);
                imagegrid.ColumnDefinitions.Add(columns);

                BitmapImage bmp = new BitmapImage();
                bmp.BeginInit();
                bmp.UriSource = new Uri(currentDirectory + "//Media//Images//" + selectedFolder + "//" + System.IO.Path.GetFileName(images[i].ToString()), UriKind.Relative);
                bmp.CacheOption = BitmapCacheOption.OnLoad;
                Debug.WriteLine("Loading: " + currentDirectory + "//Media//Images//" + selectedFolder + "//" + System.IO.Path.GetFileName(images[i].ToString()));
                bmp.EndInit();

                Image img = new Image();

                img.Name = System.IO.Path.GetFileNameWithoutExtension(images[i].ToString());
                img.Source = bmp;
                img.VerticalAlignment = VerticalAlignment.Center;
                img.HorizontalAlignment = HorizontalAlignment.Center;
                img.TouchDown += addImagetoScreen;
                img.Width = 94;
                img.Stretch = Stretch.Uniform;
                img.SetValue(Canvas.ZIndexProperty, 0);
                this.RegisterName(img.Name, img);

                Border border = new Border();
                border.SetResourceReference(Control.BackgroundProperty, "MenuSelected");
                border.SetValue(Canvas.ZIndexProperty, 0);

                Grid.SetRow(border, 0);
                Grid.SetColumn(border, i);

                Grid.SetRow(img, 1);
                Grid.SetColumn(img, i);

                imagegrid.Children.Add(border);
                imagegrid.Children.Add(img);

            }
            sv.Content = imagegrid;
            sv.SetValue(Canvas.ZIndexProperty, 0);
            hostgrid.Children.Add(sv);
            mainGrid.Children.Add(hostgrid);



        }

推荐答案

好.删除所有代码,然后重新开始.

Ok. Delete all your code and start all over.

这是您在WPF中执行的操作:

This is how you do that in WPF:

<Window x:Class="WpfApplication14.ItemsControlSample2"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="ItemsControlSample2" WindowState="Maximized">
    <ItemsControl ItemsSource="{Binding}">
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <Border Background="DarkGray" BorderBrush="Black" BorderThickness="1" CornerRadius="5"
                        Width="100" Height="100" Margin="10" >
                    <Grid>
                        <Image x:Name="img" Source="{Binding ImageSource}" Margin="2"/>

                        <TextBlock x:Name="txt" Text="Loading..." FontWeight="Bold"
                               VerticalAlignment="Center" HorizontalAlignment="Center"
                               Visibility="Collapsed" Foreground="AliceBlue"/>
                    </Grid>
                </Border>

                <DataTemplate.Triggers>
                    <DataTrigger Binding="{Binding IsLoading}" Value="True">
                        <Setter TargetName="img" Property="Source" Value="{x:Null}"/>
                        <Setter TargetName="txt" Property="Visibility" Value="Visible"/>
                    </DataTrigger>
                </DataTemplate.Triggers>
            </DataTemplate>
        </ItemsControl.ItemTemplate>

        <ItemsControl.Template>
            <ControlTemplate TargetType="ItemsControl">
                <ScrollViewer>
                    <WrapPanel IsItemsHost="True"/>
                </ScrollViewer>
            </ControlTemplate>
        </ItemsControl.Template>
    </ItemsControl>
</Window>

后面的代码:

public partial class ItemsControlSample2 : Window
{
    public ItemsControlSample2()
    {
        InitializeComponent();

        //Make sure you change this path to a valid path in your PC where you have JPG files
        var path = @"F:\Media\Images\My Drums";

        var images = Directory.GetFiles(path,"*.jpg")
                              .Select(x => new ImageViewModel()
                                           {
                                               Path = x,
                                           });
        DataContext = images.ToList();
    }
}

数据项:

public class ImageViewModel : INotifyPropertyChanged
{
    private bool _isLoading;
    public bool IsLoading
    {
        get { return _isLoading; }
        set
        {
            _isLoading = value;
            OnPropertyChanged("IsLoading");
        }
    }

    private ImageSource _imageSource;
    public ImageSource ImageSource
    {
        get { return _imageSource; }
        set
        {
            _imageSource = value;
            OnPropertyChanged("ImageSource");
        }
    }

    private string _path;
    public string Path
    {
        get { return _path; }
        set
        {
            _path = value;
            OnPropertyChanged("Path");

            LoadImageAsync();
        }
    }

    private void LoadImageAsync()
    {
        IsLoading = true;

        var UIScheduler = TaskScheduler.FromCurrentSynchronizationContext();

        Task.Factory.StartNew(() =>
        {
            var bmp = new BitmapImage();
            bmp.BeginInit();
            bmp.UriSource = new Uri(Path, UriKind.Relative);
            bmp.CacheOption = BitmapCacheOption.OnLoad;
            bmp.EndInit();
            bmp.Freeze();
            return bmp;
        }).ContinueWith(x =>
        {
            ImageSource = x.Result;
            IsLoading = false;
        },UIScheduler);
    }

    #region INotifyPropertyChanged
    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged(string propertyName)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
    }
    #endregion
}

结果:

  • 请注意,我如何在XAML中以声明方式定义,而不是在C#代码中以程序方式创建.这是一种更干净的方法,因为它可以让WPF做好工作

  • Notice how I'm declaratively defining the UI in XAML as opposed to procedurally creating it in C# code. This is a much cleaner approach because it lets WPF do it's job

我正在使用 ItemsControl 是WPF中所有基于项目"的UI的适当方法.不管它们的外观如何.

I'm using an ItemsControl which is the appropiate approach for all "items"-based UIs in WPF. Regardless of their visual appearance.

还要注意我如何利用

Also notice how I'm leveraging DataBinding in order to populate the UI with actual data and also DataTriggers in order to create a basic stateful behavior.

  • 正在加载图像(IsLoading == true)时,Image.Source为空,并且显示TextBlock.
  • 当图像完成加载(IsLoading == false)时,Image.Source绑定到ViewModel数据,并且TextBlock隐藏.
  • While the image is loading (IsLoading == true), the Image.Source is null and the TextBlock is shown.
  • When the image finished loading (IsLoading == false), the Image.Source is bound to the ViewModel data and the TextBlock is hidden.

查看我如何使用 WrapPanel 进行布局,而不是手动放置这几项.这使您具有类似资源管理器"的行为.尝试调整窗口的大小以查看结果.

See how I'm using a WrapPanel for layout instead of manually placing the items. This gives you an "Explorer-like" behavior. Try resizing the Window to see the results.

我强烈建议您阅读以上链接的文档,主要是ItemsControl资料,以及Rachel的 WPF意识帖子.

I strongly suggest you read the above linked documentation, mostly the ItemsControl stuff and also Rachel's WPF Mentality post.

WPF Rocks..只需将我的代码复制并粘贴到File -> New Project -> WPF Application中,然后亲自查看结果.

WPF Rocks. Just copy and paste my code in a File -> New Project -> WPF Application and see the results for yourself.

我正在使用C#4.0和.Net 4.0,所以我没有async/await.您应该能够删除所有基于Task的代码,并使用这种更新的,更简洁的异步方法来替换它们.

I'm Using C# 4.0 and .Net 4.0, so I don't have async/await. You should be able to remove all the Task based code and replace that by this newer, cleaner async approach.

让我知道是否需要进一步的帮助.

Let me know if you need further help.

这篇关于WPF UI多任务的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆