gpt4 book ai didi

c# - 不确定进度条

转载 作者:行者123 更新时间:2023-12-03 10:36:38 25 4
gpt4 key购买 nike

当前,我有一个按钮,当用户单击它时,它会寻找已准备就绪且包含文件的特定CD-ROM驱动器。有时,当用户单击一个按钮时,鼠标单击将使按钮单击,并且程序将挂起一段不确定的时间,直到计算机读取CD-ROM驱动器。

我进入了进度栏,但发现了一些问题:

1)在调用检查CD驱动器的方法之前,程序会挂起/冻结。因此,我无法设置进度条在调用该方法时显示。似乎在单击按钮时以及用户同时放入CD时程序挂起。单击按钮并且鼠标仍然向下/直到系统检测到CD驱动器后,如何显示进度栏?

2)我对如何实现后台工作程序感到困惑。我看了喜欢的示例,但没有一个示例具有使用MVVM(不确定代码)方法的不确定进度条。

3)操作完成后如何使窗口消失?目前,我有一个取消按钮(绝对没有用)。

到目前为止,这是我设置的内容。不确定如何继续:

进度条:

<Grid>
<Border BorderBrush="Black" BorderThickness="2" CornerRadius="4" Background="#EEEEEE" HorizontalAlignment="Left" Height="110" VerticalAlignment="Top" Width="295" />
<StackPanel>
<Label x:Name="lblProgress"/>
<ProgressBar x:Name="progress" Height="25" Width="270" IsIndeterminate="True" Foreground="Green"></ProgressBar>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Left" Margin="225,10,0,0" RenderTransformOrigin="0.083,0.526">
<Button x:Name="btnCancel" Width="60" Content="Cancel" Command="{Binding CloseCommand}"/>
</StackPanel>
</StackPanel>
</Grid>

我有一个ProgressBarViewModel,其中包含允许用户取消进度窗口的命令。此外,我还有另一个ViewModel需要在内部调用progressBar对话框,但是我不确定在哪里调用它,因为如果我在内部调用它方法,按钮仍然挂起而不显示进度条。

我注意到是否在codebehind中使用Button_PreviewMouseDown方法,但是,当鼠标按下时进度条会正确显示,并且系统的确显示了进度条,但是我不想使用codebehind,因为我在另一个 View 中都有进度条。

当前,对于我的导入按钮,所有附加的命令是调用一种方法,该方法在驱动器中搜索CD-ROM驱动器。

MainViewModel:
 public ICommand ImportCDFilePathCommand
{
get
{
return new RelayCommand(ImportCDFilePath, null);
}

}

private void ImportCDFilePath()
{
// dialogService.ShowDialog("Progress", progressBarWindow); <---Does not get called until the operation is done


//Gets all the drives
DriveInfo[] allDrives = DriveInfo.GetDrives();

//checks if any CD-Rom exists in the drives
var cdRomExists = allDrives.Any(x => x.DriveType == DriveType.CDRom);

// Get all the cd roms
var cdRoms = allDrives.Where(x=>x.DriveType==DriveType.CDRom && allDrives.Any(y=>y.IsReady));

//.... There is other code that is commented out too long and not necessary

}

编辑:

使用BackgroundWorker的一些尝试:
static BackgroundWorker _bw = new BackgroundWorker();

//constructor
MainViewModel() {


_bw.DoWork += bw_DoWork;
_bw.RunWorkerAsync("Message to worker");
}

void bw_DoWork(object sender, DoWorkEventArgs e)
{
// This is called on the worker thread
Console.WriteLine(e.Argument); // writes "Message to worker"
// Perform time-consuming task...
ImportCDFilePath();
}

错误我得到:
The calling thread must be STA, because many UI components require this.

最佳答案

嗨,我在这里有点快,您所使用的方法没有任何异步等待重载。因此,您可以使用旧的BackgroundWorker。我在这里为您提供了一个非常简单的示例,可以快速制作(制作食物)。 (未运行的)示例将仅报告进度0或100,但不会冻结UI。报告进度时,您发送一个int(进度)和一个userstate对象,这可能是您想要发送的任何对象。只需将其转换,然后执行您想要的操作即可:)

public class TestViewModel : INotifyPropertyChanged
{
private int progress;
private BackgroundWorker bgWorker;
private bool isBusy;
private readonly Dispatcher dispatcher;
private ObservableCollection<DriveInfo> cdRoms;

public Int32 Progress
{
get { return progress; }
set
{
if (value == progress) return;
progress = value;
OnPropertyChanged();
}
}

public bool IsBusy
{
get { return isBusy; }
set
{
if (value.Equals(isBusy)) return;
isBusy = value;
OnPropertyChanged();
}
}

public ICommand ImportCDFilePathCommand
{
get
{
return new RelayCommand(ImportReagentLotFilePath);
}
}


public ObservableCollection<DriveInfo> CdRoms
{
get { return cdRoms; }
set
{
if (Equals(value, cdRoms)) return;
cdRoms = value;
OnPropertyChanged();
}
}

// This one made your app crash if you defined it directly in the xaml as datacontext and not were using a viewmodellocator
public TestViewModel(Dispatcher dispatcher) // ugh I'm sure there is an interface for this, feed your UI dispatcher here
{
this.dispatcher = dispatcher;
}

// Add this one!
public TestViewModel()
{
this.dispatcher = App.Current.Dispatcher; // Bad pie
}


private void ImportReagentLotFilePath()
{

IsBusy = true;
Progress = 0;
bgWorker = new BackgroundWorker { WorkerReportsProgress = true, WorkerSupportsCancellation = true };
bgWorker.DoWork += bgWorker_DoWork;
bgWorker.ProgressChanged += bgWorker_ProgressChanged;
bgWorker.RunWorkerCompleted += bgWorker_RunWorkerCompleted;
bgWorker.RunWorkerAsync(/*whatever parameter you want goes here*/);
}

void bgWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
// you are done!
Progress = 100;
CdRoms = new ObservableCollection<DriveInfo>(e.UserState as IEnumerable<DriveInfo>);
}

void bgWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
// Notifty your gui changes here forinstance, this method will be called on the gui thread. Just cast/parse what you feed
Progress = e.ProgressPercentage;
if (Progress == 100)
IsBusy = false;
}

void bgWorker_DoWork(object sender, DoWorkEventArgs e)
{
try
{
DriveInfo[] allDrives = DriveInfo.GetDrives();
bool cdRomExists = allDrives.Any(x => x.DriveType == DriveType.CDRom);
IEnumerable<DriveInfo> cdroms = allDrives.Where(x => x.DriveType == DriveType.CDRom && allDrives.Any(y => y.IsReady));

// reports the progress on the ui thread....
bgWorker.ReportProgress(Progress,cdroms);
}
catch (Exception ex)
{
// errror handling + cancel run
dispatcher.BeginInvoke((Action) (() => { IsBusy = false; Progress = 0; }));
}
}

public event PropertyChangedEventHandler PropertyChanged;

[NotifyPropertyChangedInvocator] // remove if you are not using R#
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}

使用任务:
    // Alternatively use a task.....

public ICommand TaskTestCommand
{
get
{
return new RelayCommand(DoStuffAsync);
}
}


public Task DoStuffAsync()
{
Task tcs = Task.Factory.StartNew(() =>
{
try
{
// No awaits... please note that anything bound in the gui must be changed on the dispatcher
DriveInfo[] allDrives = DriveInfo.GetDrives();
bool cdRomExists = allDrives.Any(x => x.DriveType == DriveType.CDRom);
IEnumerable<DriveInfo> cdroms = allDrives.Where(x => x.DriveType == DriveType.CDRom && allDrives.Any(y => y.IsReady));
}
catch (Exception ex)
{
// handle your errors here. Note that you must check the innerexception for the real fault
System.Diagnostics.Trace.WriteLine(ex.ToString());
}
}).ContinueWith((e) => { // this code is run when the task is completed...
if(e.Exception!=null)
{
// hande error.. /
}
else
{
// complete.. do whatever here
}
});
return tcs;
}

希望它能帮助您朝正确的方向前进!我实际上对您使用的方法没有async-await重载感到有些惊讶,因为它将允许您使用漂亮的async-await“statemachine-auto footer”。

干杯,

施蒂安

关于c# - 不确定进度条,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25021838/

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