gpt4 book ai didi

c# - WPF UI 多任务处理

转载 作者:太空狗 更新时间:2023-10-29 23:57:19 26 4
gpt4 key购买 nike

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

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

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

   private async void begin()
{

await this.LongRunOpAsync();

}

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

我可能遗漏了一些东西,但我不知道是什么,而且我也没有办法做到这一点。任何帮助将不胜感激。

编辑:工作繁重的方法

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);



}

最佳答案

好的。删除所有代码并重新开始。

这是你在 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
}

结果:

enter image description here

  • 请注意我是如何在 XAML 中以声明方式定义 UI,而不是在 C# 代码中以程序方式创建它。这是一种更简洁的方法,因为它让 WPF 完成它的工作

  • 我使用的是 ItemsControl ,它适用于 WPF 中所有基于“项目”的 UI。不管他们的外观如何。

  • 另请注意我如何利用 DataBinding 用实际数据填充 UI,以及如何利用 DataTriggers 创建基本的有状态行为。

    • 当加载图像 ( IsLoading == true ) 时,Image.Source 为空并显示 TextBlock
    • 当图像完成加载 (IsLoading == false) 时,Image.Source 将绑定(bind)到 ViewModel 数据,TextBlock 将被隐藏。
  • 看看我如何使用 WrapPanel 进行布局而不是手动放置项目。这为您提供了“类似资源管理器”的行为。尝试调整窗口大小以查看结果。

  • 我强烈建议您阅读上面链接的文档,主要是关于 ItemsControl 的内容以及 Rachel 的 WPF Mentality 帖子。

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

  • 我使用的是 C# 4.0 和 .Net 4.0,所以我没有 async/await 。您应该能够删除所有基于 Task 的代码,并用这种更新、更清晰的异步方法替换它。

  • 如果您需要进一步的帮助,请告诉我。

关于c# - WPF UI 多任务处理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21002165/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com