Observable() 操作后删除文件
Delete files after Observable() Operations
我在集合 (Dictionary>) 上进行了一些可观察的操作 运行,其中字符串是作业名称,列表是与该作业名称相关的文件。
如果我将 List 转换为 Observable,它将 运行 所有操作都按列表元素的数量进行。因此,在所有操作之后我可以删除文件。
为了避免这种情况,我将 Dictionary 键转换为另一个 observable。但是当我这样做时,我无法删除与键相关的文件(值(列表))。
有什么解决方法吗?我知道一旦所有操作完成,它就会点击订阅。但是因为它 运行 超过了密钥(所以它不会重复)我没有要删除的有效文件。
我正在发布尽可能详细的代码。
欢迎任何意见。
谢谢
if (TIFFFiles.Count > 0 && ThreadRunning == false) //If there are files to be processed and nothing is already running
{
ThreadRunning = true;
var toObservable = TIFFFiles.ToObservable(); //Converting the current file list to an observable
cmb_ColorDelimiter.UIThread(() => cmb_tiffSelectedIndex = cmb_ColorDelimiter.SelectedIndex); //An int value
var ColorSeparator = new ColorSeparatorDefiner(cmb_tiffSelectedIndex).Delimiter;//An string value
var InfoFromFiles = new List<CMYKJobInformationForDictionarySorting>();//List for sorting
Dictionary<string, List<string>> AvailableJobsDictionary = new Dictionary<string, List<string>>(); //The dictionary where i sort the files received on TIFFFiles
for (int i = 0; i < TIFFFiles.Count; i++)
{
AvailableJobsDictionary = BuildJobsDict(TIFFFiles[i], ColorSeparator, AvailableJobsDictionary,InfoFromFiles); //The method that sorts the files from TIFFFiles
}
var observableKeys = AvailableJobsDictionary.Keys.ToObservable(); //Converting the dictiobary keys to an observable
foreach(var item in AvailableJobsDictionary) //Looping trough sorted jobs
{
//By iterating over the keys i can iterate only one time per job. If iterate over all TIFFFiles it will run operations by the number of elements available in TIFFFiles.
IObservable<string> query = from file in observableKeys
from WriteDefaultXML in Observable.Start(() => new PPFConverter.writeFinalXml(item.Key, tb_TIFFtoXMLOutputFolder.Text))
from ImageListSorted in Observable.Start(() => ImageBuilder(item.Value, ColorSeparator))
from DPI in Observable.Start(() => new ObtainDPI(item.Value.ElementAt(0)))
from IZDataInfo in Observable.Start(() => new IZAreaDataInfo(izAreaSettings.FrmIZArea_numberOfZones, izAreaSettings.FrmIZArea_zoneWidth,
izAreaSettings.FrmIZArea_firstZoneWidth, izAreaSettings.FrmIZArea_lastZoneWidth, izAreaSettings.FrmIZArea_zoneAreaWidth, izAreaSettings.FrmIZArea_zoneAreaHeight, DPI.DPI))
from RotateCMYK in Observable.Start(() => Rotate(ImageListSorted.CMYKmages, tiffToXmlpngPreviewSettings.FrmTiffPng_imageRotationCount))
from RotateImposition in Observable.Start(() => Rotate(ImageListSorted.ImposedImages, tiffToXmlpngPreviewSettings.FrmTiffPng_imageRotationCount))
from IZDraw in Observable.Start(() => InkZoneAreaImage(IZDataInfo.IzArea_ZoneAreaWidth, IZDataInfo.IzArea_ZoneAreaHeight))
from CMYKIZCalculation in Observable.Start(() => LevelCalc(IZDataInfo.IzArea_ZoneWidth, DPI.DPI, RotateCMYK.RotatedImgs, IZDraw.ZoneImage, tiffToXmlpngPreviewSettings.FrmTiffPng_imageOrientationCont))
from ImposedIZCalculation in Observable.Start(() => LevelCalc(IZDataInfo.IzArea_ZoneWidth, DPI.DPI, RotateImposition.RotatedImgs, IZDraw.ZoneImage, tiffToXmlpngPreviewSettings.FrmTiffPng_imageOrientationCont))
from CMYKResize in Observable.Start(() => ResizeCollection(RotateCMYK.RotatedImgs, tiffToXmlpngPreviewSettings.FrmTiffPng_imagePreviewWidth, tiffToXmlpngPreviewSettings.FrmTiffPng_imagePreviewHeight))
from ImpositionResize in Observable.Start(() => ResizeCollection(RotateImposition.RotatedImgs, tiffToXmlpngPreviewSettings.FrmTiffPng_imagePreviewWidth, tiffToXmlpngPreviewSettings.FrmTiffPng_imagePreviewHeight))
from CombineTHumbnail in Observable.Start(() => CombineImages(CMYKResize.ResizedImages, (bool)Properties.Settings.Default["TIFFtoXML_NegateImage"]))
from CreateComposedImage in Observable.Start(() => new SpotImageComposer(CombineTHumbnail.FinalCombinedImage, ImpositionResize.ResizedImages, tiffToXmlpngPreviewSettings.FrmTiffPng_imageOrientationCont, ColorSeparator, tiffToXmlpngPreviewSettings.TIffToXml_UnknownSpotcolorHandling))
from FinalXMLWrite in Observable.Start(() => new WriteXMLData(WriteDefaultXML.finalXmlName,WriteDefaultXML.OutputFolder,CMYKIZCalculation,ImposedIZCalculation,CreateComposedImage.FinalImage,WriteDefaultXML.xmlDoc,InfoFromFiles,ColorSeparator,item.Value))
select file;
if((bool)Properties.Settings.Default["TIFFtoXML_DeleteInput"])
{
_subscription = query.Subscribe(f => System.IO.File.Delete(f)); //Wanted to delete the files
}
TIFFFiles.Clear();
ThreadRunning = false;
}
}
更新代码:
public partial class Form1
{
Dictionary<string, List<string>> sortedJobs;
Subject<List<string>> jobsToRun;
private int cmb_tiffSelectedIndex;
public Form1()
{
InitializeComponent();
jobsToRun = new Subject<List<string>>();
sortedJobs = new Dictionary<string, List<string>>();
}
private void SecondElapsed(object sender, EventArgs e)
{
counter--;
if (counter == 0)
{
timer1.Stop();
counter = Int32.Parse(internalSettings.TIFFtoXML_MainTimer);
cmb_ColorDelimiter.UIThread(() => cmb_tiffSelectedIndex = cmb_ColorDelimiter.SelectedIndex); //An int value
foreach (var item in sortedJobs.Values) //Each list string contains information about an job and its respective files
{
jobsToRun.OnNext(item);
IObservable<List<string>> query = from currItem in jobsToRun
let ColorSeparator = new ColorSeparatorDefiner(cmb_tiffSelectedIndex).Delimiter
let JobInfo = new CMYKJobInformationForDictionarySorting(item.ElementAt(0), ColorSeparator)
let file = JobInfo.ConventionName
select currItem;
_subscription = query.Subscribe(x =>
{
if ((bool)Properties.Settings.Default["TIFFtoXML_DeleteInput"])
{
foreach (var currFile in x)
File.Delete(currFile);
//Wanted to delete the files
}
});
string r = string.Empty;
}
timer1.Start();
}
tb_MainTimer.Text = counter.ToString();
}
private void TIFFtoXMLEventHandler(object sender, FileSystemEventArgs e)
{
string fNameExt = Path.GetExtension(e.FullPath).ToUpper();
if (new GetAvailableFile(e.FullPath).fileReady)
{
if (fNameExt.Contains(".TIF"))
{
SortFilesOnArrival(e.FullPath, cmb_tiffSelectedIndex);
}
else if (fNameExt.Contains(".CIP") || fNameExt.Contains(".PPF"))
{
}
}
counter = Int32.Parse(internalSettings.TIFFtoXML_MainTimer);
// timer1.Stop();
timer1.Start();
}
private void SortFilesOnArrival(string currFile, int ColorDelimiterIndex)
{
var colorSeparator = new ColorSeparatorDefiner(ColorDelimiterIndex).Delimiter;
CMYKJobInformationForDictionarySorting InfoFromFiles = new CMYKJobInformationForDictionarySorting(currFile, colorSeparator);
if (sortedJobs.ContainsKey(InfoFromFiles.ConventionName))
{
sortedJobs[InfoFromFiles.ConventionName].Add(InfoFromFiles.OriginalFileName);
}
else
{
sortedJobs.Add(InfoFromFiles.ConventionName, new List<string>() { InfoFromFiles.OriginalFileName });
}
FilesCopiedInfo.Add(InfoFromFiles);
}
}
更新:
我已经编辑以包含我所做的一切的最终代码=)!它最终起作用了,现在我只是设置了一些细节(更多关于业务逻辑和工作流)。我知道这远非好事,但现在这是我决定要做的。我的下一个目标是对所有类型的文件进行单一订阅,并处理查询本身的不同情况;它会让事情变得更容易,并允许我用更少的代码做同样的事情。
并提前感谢您的帮助。这就像对我的 Reactive Extensions 的介绍,嘿,我开始阅读和挖掘它。
public partial class Form1 : AsyncBaseDialog
{
private IDisposable CIP3Subscription = null;
static System.Windows.Forms.Timer timer1; //The timer is used but just for visual purposes - nothing is related to him
IObservable<FileSystemEventArgs> TIFFFilesCreated;
IObservable<FileSystemEventArgs[]> TIFFGroupFiles;
IObservable<FileSystemEventArgs> CIP3FilesCreated;
IObservable<FileSystemEventArgs[]> CIP3GroupFiles;
bool currStatus = (bool)Properties.Settings.Default["TIFFtoXML_EnabledConversion"]; //If the enable conversion checkbox is enabled, fire the observable
if(currStatus)
{
EnableTIFFtoXMLWatcher(currStatus);
EnableCIP3toTIFFWatcher(currStatus);
}
timer1 = new System.Windows.Forms.Timer();
timer1.Tick += new EventHandler(SecondElapsed);
timer1.Enabled = currStatus;
counter = Convert.ToInt32(Properties.Settings.Default.TIFFtoXML_MainTimer);
}
#region timerStuff
DateTime start;
double s;
private void CountDown()
{
start = DateTime.Now;
s = (double)counter;
timer1.Start();
}
private void SecondElapsed(object sender, EventArgs e)
{
double remainingSeconds = s - (DateTime.Now - start).TotalSeconds;
if (remainingSeconds <= 0)
{
timer1.Stop();
timer1.Interval = (int)counter;
timer1.Start();
CountDown();
}
var x = TimeSpan.FromSeconds(remainingSeconds);
tb_MainTimer.Text = x.Seconds.ToString();
}
#endregion
#region ObservableMethods //Methods i built in order to handle the observable behaviour
private IObservable<FileSystemEventArgs[]> CreateObjectForConvertAll(string inputFolder, string extension)
{
//I've a checkbox where the user selects "Convert all", and it will convert everything in the folder. Since i didn't wanted to repeat
//code by calling all methods again, this method returns me an object i can query
List<FileSystemEventArgs> tempList = new List<FileSystemEventArgs>(Directory.GetFiles(tb_TIFFtoXMLInputFolder.Text, extension, SearchOption.TopDirectoryOnly).ToList()
.Select(x => new FileSystemEventArgs(WatcherChangeTypes.Created, "", x)));
List<FileSystemEventArgs[]> fswArgsArrayList = new List<FileSystemEventArgs[]>();
fswArgsArrayList.Add(tempList.ToArray());
var finalObservable = fswArgsArrayList.ToArray();
var finalObservableNotArray = finalObservable.ToArray().ToObservable();
return finalObservableNotArray;
}
private IObservable<FileSystemEventArgs> CreateReactiveFSWInstance(string inputFolder, string fileFilter, bool checkBoxStatus)
{
//Creates the Reactive FSW instance
//checkBoxStatus => Enabled or not ; if the user enables the conversion, EnableRaisingEvents will be true
IObservable<FileSystemEventArgs> filesCreated =
Observable
.Using(
() =>
{
var fsw = new FileSystemWatcher(inputFolder)
{
EnableRaisingEvents = checkBoxStatus,
Filter = fileFilter
};
return fsw;
},
fsw => Observable.FromEventPattern
<FileSystemEventHandler, FileSystemEventArgs>(
h => fsw.Created += h,
h => fsw.Created -= h))
.Delay(TimeSpan.FromSeconds(0.1))
.Select(x => x.EventArgs);
return filesCreated;
}
private IObservable<FileSystemEventArgs[]> TIFFPublish(IObservable<FileSystemEventArgs> observable)
{
var GroupFiles =
observable
.Publish(fc =>
from w in fc.Window(() => fc.Throttle(TimeSpan.FromSeconds((double)counter)))
from fcs in w.ToArray()
select fcs);
return GroupFiles;
}
#endregion
private void StartCIP3ProcessingQuery(IObservable<FileSystemEventArgs[]> Files)
{
//query goes here...
}
private void StartTIFFProcessingQuery(IObservable<FileSystemEventArgs[]> Files)
{
//query goes here...
}
private void EnableTIFFtoXMLWatcher(bool status)
{
//Enable the reactive watcher for TIF files
TIFFFilesCreated = CreateReactiveFSWInstance(tb_TIFFtoXMLInputFolder.Text, "*.tif", status);
TIFFGroupFiles = TIFFPublish(TIFFFilesCreated);
StartTIFFProcessingQuery(TIFFGroupFiles);
}
private void EnableCIP3toTIFFWatcher(bool status)
{
//Enable the reactive watcher for CIP3 files
CIP3FilesCreated = CreateReactiveFSWInstance(tb_TIFFtoXMLInputFolder.Text, "*.*", status);
CIP3GroupFiles = TIFFPublish(CIP3FilesCreated);
StartCIP3ProcessingQuery(CIP3GroupFiles, false);
}
private void SubscriptionDisposal()
{
//Disposal methods
TIFFSubscription.Dispose();
CIP3Subscription.Dispose();
}
//Enable or disable the conversio, or convert all
private void CheckboxChangedEventHandler(object sender, EventArgs e)
{
CheckBox CurrChk = sender as CheckBox;
bool status = CurrChk.Checked;
switch (CurrChk.Name)
{
case "TIFFtoXML_chkConvertAll":
{
if(status)
{
cb_enableTIFFtoXML.Checked = true; //Enabling this checkbox triggers the other case and fires the FSW
var convertAllTIFFObj = CreateObjectForConvertAll(tb_TIFFtoXMLInputFolder.Text, "*.tif");
StartTIFFProcessingQuery(convertAllTIFFObj);
var convertAllCIP3Obj = CreateObjectForConvertAll(tb_TIFFtoXMLInputFolder.Text, "*.*");
StartCIP3ProcessingQuery(convertAllCIP3Obj,true);
CurrChk.Checked = false;
}
break;
}
case "cb_enableTIFFtoXML":
{
if (status)
{
EnableCIP3toTIFFWatcher(status);
EnableTIFFtoXMLWatcher(status);
CountDown();
}
else
{
//If the user disables the conversion, it will just dispose objects.
TIFFSubscription.Dispose();
CIP3Subscription.Dispose();
timer1.Stop();
}
break;
}
}
}
下面是您的代码的更接近版本:
IObservable<string> query =
from item in TIFFFiles // TIFFFiles = new Subject<string>()
let ColorSeparator = new ColorSeparatorDefiner(cmb_tiffSelectedIndex).Delimiter
let jobInfo = new CMYKJobInformationForDictionarySorting(currFile, ColorSeparator)
let file = jobInfo.ConventionName
from WriteDefaultXML in Observable.Start(() => new PPFConverter.writeFinalXml(item.Key, tb_TIFFtoXMLOutputFolder.Text))
from ImageListSorted in Observable.Start(() => ImageBuilder(item.Value, ColorSeparator))
from DPI in Observable.Start(() => new ObtainDPI(item.Value.ElementAt(0)))
from IZDataInfo in Observable.Start(() => new IZAreaDataInfo(izAreaSettings.FrmIZArea_numberOfZones, izAreaSettings.FrmIZArea_zoneWidth, izAreaSettings.FrmIZArea_firstZoneWidth, izAreaSettings.FrmIZArea_lastZoneWidth, izAreaSettings.FrmIZArea_zoneAreaWidth, izAreaSettings.FrmIZArea_zoneAreaHeight, DPI.DPI))
from RotateCMYK in Observable.Start(() => Rotate(ImageListSorted.CMYKmages, tiffToXmlpngPreviewSettings.FrmTiffPng_imageRotationCount))
from RotateImposition in Observable.Start(() => Rotate(ImageListSorted.ImposedImages, tiffToXmlpngPreviewSettings.FrmTiffPng_imageRotationCount))
from IZDraw in Observable.Start(() => InkZoneAreaImage(IZDataInfo.IzArea_ZoneAreaWidth, IZDataInfo.IzArea_ZoneAreaHeight))
from CMYKIZCalculation in Observable.Start(() => LevelCalc(IZDataInfo.IzArea_ZoneWidth, DPI.DPI, RotateCMYK.RotatedImgs, IZDraw.ZoneImage, tiffToXmlpngPreviewSettings.FrmTiffPng_imageOrientationCont))
from ImposedIZCalculation in Observable.Start(() => LevelCalc(IZDataInfo.IzArea_ZoneWidth, DPI.DPI, RotateImposition.RotatedImgs, IZDraw.ZoneImage, tiffToXmlpngPreviewSettings.FrmTiffPng_imageOrientationCont))
from CMYKResize in Observable.Start(() => ResizeCollection(RotateCMYK.RotatedImgs, tiffToXmlpngPreviewSettings.FrmTiffPng_imagePreviewWidth, tiffToXmlpngPreviewSettings.FrmTiffPng_imagePreviewHeight))
from ImpositionResize in Observable.Start(() => ResizeCollection(RotateImposition.RotatedImgs, tiffToXmlpngPreviewSettings.FrmTiffPng_imagePreviewWidth, tiffToXmlpngPreviewSettings.FrmTiffPng_imagePreviewHeight))
from CombineTHumbnail in Observable.Start(() => CombineImages(CMYKResize.ResizedImages, (bool)Properties.Settings.Default["TIFFtoXML_NegateImage"]))
from CreateComposedImage in Observable.Start(() => new SpotImageComposer(CombineTHumbnail.FinalCombinedImage, ImpositionResize.ResizedImages, tiffToXmlpngPreviewSettings.FrmTiffPng_imageOrientationCont, ColorSeparator, tiffToXmlpngPreviewSettings.TIffToXml_UnknownSpotcolorHandling))
from FinalXMLWrite in Observable.Start(() => new WriteXMLData(WriteDefaultXML.finalXmlName, WriteDefaultXML.OutputFolder, CMYKIZCalculation, ImposedIZCalculation, CreateComposedImage.FinalImage, WriteDefaultXML.xmlDoc, InfoFromFiles, ColorSeparator, item.Value))
select file;
_subscription =
query
.Subscribe(f =>
{
if ((bool)Properties.Settings.Default["TIFFtoXML_DeleteInput"])
{
System.IO.File.Delete(f); //Wanted to delete the files
}
}, () =>
{
/* code to execute when observable finishes */
/* You must call `TIFFFiles.OnCompleted()` */
});
请不要使用任何计时器、线程或任务。如果你说出原因,我可以帮助你解决你需要的问题。
所有这些都会在您调用时触发:TIFFFiles.OnNext(filename);
。
下面是观察文件系统的代码,然后根据 TimeSpan.FromSeconds(30.0)
没有进一步添加文件的情况将更改分组在一起:
IObservable<FileSystemEventArgs> filesCreated =
Observable
.Using(
() =>
{
var fsw = new FileSystemWatcher(@"C:\Users\james\Temporary\Testing");
fsw.EnableRaisingEvents = true;
return fsw;
},
fsw => Observable.FromEventPattern
<FileSystemEventHandler, FileSystemEventArgs>(
h => fsw.Created += h,
h => fsw.Created -= h))
.Delay(TimeSpan.FromSeconds(0.1))
.Select(x => x.EventArgs);
IObservable<FileSystemEventArgs[]> batchesOfFilesCreated =
filesCreated
.Publish(fc =>
from w in fc.Window(() => fc.Throttle(TimeSpan.FromSeconds(30.0)))
from fcs in w.ToArray()
select fcs);
现在您的查询如下所示:
var ColorSeparator = new ColorSeparatorDefiner(cmb_tiffSelectedIndex).Delimiter;
var query =
from gfcs in batchesOfFilesCreated.GroupBy(x => new CMYKJobInformationForDictionarySorting(currFile, ColorSeparator).ConventionName)
let file = gfcs.Key
from gfc in gfcs
from WriteDefaultXML in Observable.Start(() => new PPFConverter.writeFinalXml(item.Key, tb_TIFFtoXMLOutputFolder.Text))
from ImageListSorted in Observable.Start(() => ImageBuilder(item.Value, ColorSeparator))
from DPI in Observable.Start(() => new ObtainDPI(item.Value.ElementAt(0)))
from IZDataInfo in Observable.Start(() => new IZAreaDataInfo(izAreaSettings.FrmIZArea_numberOfZones, izAreaSettings.FrmIZArea_zoneWidth, izAreaSettings.FrmIZArea_firstZoneWidth, izAreaSettings.FrmIZArea_lastZoneWidth, izAreaSettings.FrmIZArea_zoneAreaWidth, izAreaSettings.FrmIZArea_zoneAreaHeight, DPI.DPI))
from RotateCMYK in Observable.Start(() => Rotate(ImageListSorted.CMYKmages, tiffToXmlpngPreviewSettings.FrmTiffPng_imageRotationCount))
from RotateImposition in Observable.Start(() => Rotate(ImageListSorted.ImposedImages, tiffToXmlpngPreviewSettings.FrmTiffPng_imageRotationCount))
from IZDraw in Observable.Start(() => InkZoneAreaImage(IZDataInfo.IzArea_ZoneAreaWidth, IZDataInfo.IzArea_ZoneAreaHeight))
from CMYKIZCalculation in Observable.Start(() => LevelCalc(IZDataInfo.IzArea_ZoneWidth, DPI.DPI, RotateCMYK.RotatedImgs, IZDraw.ZoneImage, tiffToXmlpngPreviewSettings.FrmTiffPng_imageOrientationCont))
from ImposedIZCalculation in Observable.Start(() => LevelCalc(IZDataInfo.IzArea_ZoneWidth, DPI.DPI, RotateImposition.RotatedImgs, IZDraw.ZoneImage, tiffToXmlpngPreviewSettings.FrmTiffPng_imageOrientationCont))
from CMYKResize in Observable.Start(() => ResizeCollection(RotateCMYK.RotatedImgs, tiffToXmlpngPreviewSettings.FrmTiffPng_imagePreviewWidth, tiffToXmlpngPreviewSettings.FrmTiffPng_imagePreviewHeight))
from ImpositionResize in Observable.Start(() => ResizeCollection(RotateImposition.RotatedImgs, tiffToXmlpngPreviewSettings.FrmTiffPng_imagePreviewWidth, tiffToXmlpngPreviewSettings.FrmTiffPng_imagePreviewHeight))
from CombineTHumbnail in Observable.Start(() => CombineImages(CMYKResize.ResizedImages, (bool)Properties.Settings.Default["TIFFtoXML_NegateImage"]))
from CreateComposedImage in Observable.Start(() => new SpotImageComposer(CombineTHumbnail.FinalCombinedImage, ImpositionResize.ResizedImages, tiffToXmlpngPreviewSettings.FrmTiffPng_imageOrientationCont, ColorSeparator, tiffToXmlpngPreviewSettings.TIffToXml_UnknownSpotcolorHandling))
from FinalXMLWrite in Observable.Start(() => new WriteXMLData(WriteDefaultXML.finalXmlName, WriteDefaultXML.OutputFolder, CMYKIZCalculation, ImposedIZCalculation, CreateComposedImage.FinalImage, WriteDefaultXML.xmlDoc, InfoFromFiles, ColorSeparator, item.Value))
select file;
_subscription =
query
.Subscribe(f =>
{
if ((bool)Properties.Settings.Default["TIFFtoXML_DeleteInput"])
{
System.IO.File.Delete(f); //Wanted to delete the files
}
}, () =>
{
/* code to execute when observable finishes */
/* You must call `TIFFFiles.OnCompleted()` */
});
注意:这消除了计时器和代码中线程的使用。您应该能够设置一次并保留它 运行。只要记得在你想让它停止时调用 _subscription.Dispose()
运行.
更新:我已经编辑以包含我所做的一切的最终代码 =)!它最终起作用了,现在我只是设置了一些细节(更多关于业务逻辑和工作流)。我知道这远非好事,但现在我决定这样做。
我的下一个目标是对所有类型的文件进行单一订阅,并处理查询本身的不同情况;它会让事情变得更容易,并允许我用更少的代码做同样的事情。并提前感谢您的帮助。这就像对我的 Reactive Extensions 的介绍嘿,我开始阅读和挖掘它。
public partial class Form1 : AsyncBaseDialog
{
private IDisposable CIP3Subscription = null;
static System.Windows.Forms.Timer timer1; //The timer is used but just for visual purposes - nothing is related to him
IObservable<FileSystemEventArgs> TIFFFilesCreated;
IObservable<FileSystemEventArgs[]> TIFFGroupFiles;
IObservable<FileSystemEventArgs> CIP3FilesCreated;
IObservable<FileSystemEventArgs[]> CIP3GroupFiles;
bool currStatus = (bool)Properties.Settings.Default["TIFFtoXML_EnabledConversion"]; //If the enable conversion checkbox is enabled, fire the observable
if(currStatus)
{
EnableTIFFtoXMLWatcher(currStatus);
EnableCIP3toTIFFWatcher(currStatus);
}
timer1 = new System.Windows.Forms.Timer();
timer1.Tick += new EventHandler(SecondElapsed);
timer1.Enabled = currStatus;
counter = Convert.ToInt32(Properties.Settings.Default.TIFFtoXML_MainTimer);
}
#region timerStuff
DateTime start;
double s;
private void CountDown()
{
start = DateTime.Now;
s = (double)counter;
timer1.Start();
}
private void SecondElapsed(object sender, EventArgs e)
{
double remainingSeconds = s - (DateTime.Now - start).TotalSeconds;
if (remainingSeconds <= 0)
{
timer1.Stop();
timer1.Interval = (int)counter;
timer1.Start();
CountDown();
}
var x = TimeSpan.FromSeconds(remainingSeconds);
tb_MainTimer.Text = x.Seconds.ToString();
}
#endregion
#region ObservableMethods //Methods i built in order to handle the observable behaviour
private IObservable<FileSystemEventArgs[]> CreateObjectForConvertAll(string inputFolder, string extension)
{
//I've a checkbox where the user selects "Convert all", and it will convert everything in the folder. Since i didn't wanted to repeat
//code by calling all methods again, this method returns me an object i can query
List<FileSystemEventArgs> tempList = new List<FileSystemEventArgs>(Directory.GetFiles(tb_TIFFtoXMLInputFolder.Text, extension, SearchOption.TopDirectoryOnly).ToList()
.Select(x => new FileSystemEventArgs(WatcherChangeTypes.Created, "", x)));
List<FileSystemEventArgs[]> fswArgsArrayList = new List<FileSystemEventArgs[]>();
fswArgsArrayList.Add(tempList.ToArray());
var finalObservable = fswArgsArrayList.ToArray();
var finalObservableNotArray = finalObservable.ToArray().ToObservable();
return finalObservableNotArray;
}
private IObservable<FileSystemEventArgs> CreateReactiveFSWInstance(string inputFolder, string fileFilter, bool checkBoxStatus)
{
//Creates the Reactive FSW instance
//checkBoxStatus => Enabled or not ; if the user enables the conversion, EnableRaisingEvents will be true
IObservable<FileSystemEventArgs> filesCreated =
Observable
.Using(
() =>
{
var fsw = new FileSystemWatcher(inputFolder)
{
EnableRaisingEvents = checkBoxStatus,
Filter = fileFilter
};
return fsw;
},
fsw => Observable.FromEventPattern
<FileSystemEventHandler, FileSystemEventArgs>(
h => fsw.Created += h,
h => fsw.Created -= h))
.Delay(TimeSpan.FromSeconds(0.1))
.Select(x => x.EventArgs);
return filesCreated;
}
private IObservable<FileSystemEventArgs[]> TIFFPublish(IObservable<FileSystemEventArgs> observable)
{
var GroupFiles =
observable
.Publish(fc =>
from w in fc.Window(() => fc.Throttle(TimeSpan.FromSeconds((double)counter)))
from fcs in w.ToArray()
select fcs);
return GroupFiles;
}
#endregion
private void StartCIP3ProcessingQuery(IObservable<FileSystemEventArgs[]> Files)
{
//query goes here...
}
private void StartTIFFProcessingQuery(IObservable<FileSystemEventArgs[]> Files)
{
//query goes here...
}
private void EnableTIFFtoXMLWatcher(bool status)
{
//Enable the reactive watcher for TIF files
TIFFFilesCreated = CreateReactiveFSWInstance(tb_TIFFtoXMLInputFolder.Text, "*.tif", status);
TIFFGroupFiles = TIFFPublish(TIFFFilesCreated);
StartTIFFProcessingQuery(TIFFGroupFiles);
}
private void EnableCIP3toTIFFWatcher(bool status)
{
//Enable the reactive watcher for CIP3 files
CIP3FilesCreated = CreateReactiveFSWInstance(tb_TIFFtoXMLInputFolder.Text, "*.*", status);
CIP3GroupFiles = TIFFPublish(CIP3FilesCreated);
StartCIP3ProcessingQuery(CIP3GroupFiles, false);
}
private void SubscriptionDisposal()
{
//Disposal methods
TIFFSubscription.Dispose();
CIP3Subscription.Dispose();
}
//Enable or disable the conversio, or convert all
private void CheckboxChangedEventHandler(object sender, EventArgs e)
{
CheckBox CurrChk = sender as CheckBox;
bool status = CurrChk.Checked;
switch (CurrChk.Name)
{
case "TIFFtoXML_chkConvertAll":
{
if(status)
{
cb_enableTIFFtoXML.Checked = true; //Enabling this checkbox triggers the other case and fires the FSW
var convertAllTIFFObj = CreateObjectForConvertAll(tb_TIFFtoXMLInputFolder.Text, "*.tif");
StartTIFFProcessingQuery(convertAllTIFFObj);
var convertAllCIP3Obj = CreateObjectForConvertAll(tb_TIFFtoXMLInputFolder.Text, "*.*");
StartCIP3ProcessingQuery(convertAllCIP3Obj,true);
CurrChk.Checked = false;
}
break;
}
case "cb_enableTIFFtoXML":
{
if (status)
{
EnableCIP3toTIFFWatcher(status);
EnableTIFFtoXMLWatcher(status);
CountDown();
}
else
{
//If the user disables the conversion, it will just dispose objects.
TIFFSubscription.Dispose();
CIP3Subscription.Dispose();
timer1.Stop();
}
break;
}
}
}
我在集合 (Dictionary>) 上进行了一些可观察的操作 运行,其中字符串是作业名称,列表是与该作业名称相关的文件。
如果我将 List 转换为 Observable,它将 运行 所有操作都按列表元素的数量进行。因此,在所有操作之后我可以删除文件。
为了避免这种情况,我将 Dictionary 键转换为另一个 observable。但是当我这样做时,我无法删除与键相关的文件(值(列表))。
有什么解决方法吗?我知道一旦所有操作完成,它就会点击订阅。但是因为它 运行 超过了密钥(所以它不会重复)我没有要删除的有效文件。
我正在发布尽可能详细的代码。
欢迎任何意见。 谢谢
if (TIFFFiles.Count > 0 && ThreadRunning == false) //If there are files to be processed and nothing is already running
{
ThreadRunning = true;
var toObservable = TIFFFiles.ToObservable(); //Converting the current file list to an observable
cmb_ColorDelimiter.UIThread(() => cmb_tiffSelectedIndex = cmb_ColorDelimiter.SelectedIndex); //An int value
var ColorSeparator = new ColorSeparatorDefiner(cmb_tiffSelectedIndex).Delimiter;//An string value
var InfoFromFiles = new List<CMYKJobInformationForDictionarySorting>();//List for sorting
Dictionary<string, List<string>> AvailableJobsDictionary = new Dictionary<string, List<string>>(); //The dictionary where i sort the files received on TIFFFiles
for (int i = 0; i < TIFFFiles.Count; i++)
{
AvailableJobsDictionary = BuildJobsDict(TIFFFiles[i], ColorSeparator, AvailableJobsDictionary,InfoFromFiles); //The method that sorts the files from TIFFFiles
}
var observableKeys = AvailableJobsDictionary.Keys.ToObservable(); //Converting the dictiobary keys to an observable
foreach(var item in AvailableJobsDictionary) //Looping trough sorted jobs
{
//By iterating over the keys i can iterate only one time per job. If iterate over all TIFFFiles it will run operations by the number of elements available in TIFFFiles.
IObservable<string> query = from file in observableKeys
from WriteDefaultXML in Observable.Start(() => new PPFConverter.writeFinalXml(item.Key, tb_TIFFtoXMLOutputFolder.Text))
from ImageListSorted in Observable.Start(() => ImageBuilder(item.Value, ColorSeparator))
from DPI in Observable.Start(() => new ObtainDPI(item.Value.ElementAt(0)))
from IZDataInfo in Observable.Start(() => new IZAreaDataInfo(izAreaSettings.FrmIZArea_numberOfZones, izAreaSettings.FrmIZArea_zoneWidth,
izAreaSettings.FrmIZArea_firstZoneWidth, izAreaSettings.FrmIZArea_lastZoneWidth, izAreaSettings.FrmIZArea_zoneAreaWidth, izAreaSettings.FrmIZArea_zoneAreaHeight, DPI.DPI))
from RotateCMYK in Observable.Start(() => Rotate(ImageListSorted.CMYKmages, tiffToXmlpngPreviewSettings.FrmTiffPng_imageRotationCount))
from RotateImposition in Observable.Start(() => Rotate(ImageListSorted.ImposedImages, tiffToXmlpngPreviewSettings.FrmTiffPng_imageRotationCount))
from IZDraw in Observable.Start(() => InkZoneAreaImage(IZDataInfo.IzArea_ZoneAreaWidth, IZDataInfo.IzArea_ZoneAreaHeight))
from CMYKIZCalculation in Observable.Start(() => LevelCalc(IZDataInfo.IzArea_ZoneWidth, DPI.DPI, RotateCMYK.RotatedImgs, IZDraw.ZoneImage, tiffToXmlpngPreviewSettings.FrmTiffPng_imageOrientationCont))
from ImposedIZCalculation in Observable.Start(() => LevelCalc(IZDataInfo.IzArea_ZoneWidth, DPI.DPI, RotateImposition.RotatedImgs, IZDraw.ZoneImage, tiffToXmlpngPreviewSettings.FrmTiffPng_imageOrientationCont))
from CMYKResize in Observable.Start(() => ResizeCollection(RotateCMYK.RotatedImgs, tiffToXmlpngPreviewSettings.FrmTiffPng_imagePreviewWidth, tiffToXmlpngPreviewSettings.FrmTiffPng_imagePreviewHeight))
from ImpositionResize in Observable.Start(() => ResizeCollection(RotateImposition.RotatedImgs, tiffToXmlpngPreviewSettings.FrmTiffPng_imagePreviewWidth, tiffToXmlpngPreviewSettings.FrmTiffPng_imagePreviewHeight))
from CombineTHumbnail in Observable.Start(() => CombineImages(CMYKResize.ResizedImages, (bool)Properties.Settings.Default["TIFFtoXML_NegateImage"]))
from CreateComposedImage in Observable.Start(() => new SpotImageComposer(CombineTHumbnail.FinalCombinedImage, ImpositionResize.ResizedImages, tiffToXmlpngPreviewSettings.FrmTiffPng_imageOrientationCont, ColorSeparator, tiffToXmlpngPreviewSettings.TIffToXml_UnknownSpotcolorHandling))
from FinalXMLWrite in Observable.Start(() => new WriteXMLData(WriteDefaultXML.finalXmlName,WriteDefaultXML.OutputFolder,CMYKIZCalculation,ImposedIZCalculation,CreateComposedImage.FinalImage,WriteDefaultXML.xmlDoc,InfoFromFiles,ColorSeparator,item.Value))
select file;
if((bool)Properties.Settings.Default["TIFFtoXML_DeleteInput"])
{
_subscription = query.Subscribe(f => System.IO.File.Delete(f)); //Wanted to delete the files
}
TIFFFiles.Clear();
ThreadRunning = false;
}
}
更新代码:
public partial class Form1
{
Dictionary<string, List<string>> sortedJobs;
Subject<List<string>> jobsToRun;
private int cmb_tiffSelectedIndex;
public Form1()
{
InitializeComponent();
jobsToRun = new Subject<List<string>>();
sortedJobs = new Dictionary<string, List<string>>();
}
private void SecondElapsed(object sender, EventArgs e)
{
counter--;
if (counter == 0)
{
timer1.Stop();
counter = Int32.Parse(internalSettings.TIFFtoXML_MainTimer);
cmb_ColorDelimiter.UIThread(() => cmb_tiffSelectedIndex = cmb_ColorDelimiter.SelectedIndex); //An int value
foreach (var item in sortedJobs.Values) //Each list string contains information about an job and its respective files
{
jobsToRun.OnNext(item);
IObservable<List<string>> query = from currItem in jobsToRun
let ColorSeparator = new ColorSeparatorDefiner(cmb_tiffSelectedIndex).Delimiter
let JobInfo = new CMYKJobInformationForDictionarySorting(item.ElementAt(0), ColorSeparator)
let file = JobInfo.ConventionName
select currItem;
_subscription = query.Subscribe(x =>
{
if ((bool)Properties.Settings.Default["TIFFtoXML_DeleteInput"])
{
foreach (var currFile in x)
File.Delete(currFile);
//Wanted to delete the files
}
});
string r = string.Empty;
}
timer1.Start();
}
tb_MainTimer.Text = counter.ToString();
}
private void TIFFtoXMLEventHandler(object sender, FileSystemEventArgs e)
{
string fNameExt = Path.GetExtension(e.FullPath).ToUpper();
if (new GetAvailableFile(e.FullPath).fileReady)
{
if (fNameExt.Contains(".TIF"))
{
SortFilesOnArrival(e.FullPath, cmb_tiffSelectedIndex);
}
else if (fNameExt.Contains(".CIP") || fNameExt.Contains(".PPF"))
{
}
}
counter = Int32.Parse(internalSettings.TIFFtoXML_MainTimer);
// timer1.Stop();
timer1.Start();
}
private void SortFilesOnArrival(string currFile, int ColorDelimiterIndex)
{
var colorSeparator = new ColorSeparatorDefiner(ColorDelimiterIndex).Delimiter;
CMYKJobInformationForDictionarySorting InfoFromFiles = new CMYKJobInformationForDictionarySorting(currFile, colorSeparator);
if (sortedJobs.ContainsKey(InfoFromFiles.ConventionName))
{
sortedJobs[InfoFromFiles.ConventionName].Add(InfoFromFiles.OriginalFileName);
}
else
{
sortedJobs.Add(InfoFromFiles.ConventionName, new List<string>() { InfoFromFiles.OriginalFileName });
}
FilesCopiedInfo.Add(InfoFromFiles);
}
}
更新: 我已经编辑以包含我所做的一切的最终代码=)!它最终起作用了,现在我只是设置了一些细节(更多关于业务逻辑和工作流)。我知道这远非好事,但现在这是我决定要做的。我的下一个目标是对所有类型的文件进行单一订阅,并处理查询本身的不同情况;它会让事情变得更容易,并允许我用更少的代码做同样的事情。 并提前感谢您的帮助。这就像对我的 Reactive Extensions 的介绍,嘿,我开始阅读和挖掘它。
public partial class Form1 : AsyncBaseDialog
{
private IDisposable CIP3Subscription = null;
static System.Windows.Forms.Timer timer1; //The timer is used but just for visual purposes - nothing is related to him
IObservable<FileSystemEventArgs> TIFFFilesCreated;
IObservable<FileSystemEventArgs[]> TIFFGroupFiles;
IObservable<FileSystemEventArgs> CIP3FilesCreated;
IObservable<FileSystemEventArgs[]> CIP3GroupFiles;
bool currStatus = (bool)Properties.Settings.Default["TIFFtoXML_EnabledConversion"]; //If the enable conversion checkbox is enabled, fire the observable
if(currStatus)
{
EnableTIFFtoXMLWatcher(currStatus);
EnableCIP3toTIFFWatcher(currStatus);
}
timer1 = new System.Windows.Forms.Timer();
timer1.Tick += new EventHandler(SecondElapsed);
timer1.Enabled = currStatus;
counter = Convert.ToInt32(Properties.Settings.Default.TIFFtoXML_MainTimer);
}
#region timerStuff
DateTime start;
double s;
private void CountDown()
{
start = DateTime.Now;
s = (double)counter;
timer1.Start();
}
private void SecondElapsed(object sender, EventArgs e)
{
double remainingSeconds = s - (DateTime.Now - start).TotalSeconds;
if (remainingSeconds <= 0)
{
timer1.Stop();
timer1.Interval = (int)counter;
timer1.Start();
CountDown();
}
var x = TimeSpan.FromSeconds(remainingSeconds);
tb_MainTimer.Text = x.Seconds.ToString();
}
#endregion
#region ObservableMethods //Methods i built in order to handle the observable behaviour
private IObservable<FileSystemEventArgs[]> CreateObjectForConvertAll(string inputFolder, string extension)
{
//I've a checkbox where the user selects "Convert all", and it will convert everything in the folder. Since i didn't wanted to repeat
//code by calling all methods again, this method returns me an object i can query
List<FileSystemEventArgs> tempList = new List<FileSystemEventArgs>(Directory.GetFiles(tb_TIFFtoXMLInputFolder.Text, extension, SearchOption.TopDirectoryOnly).ToList()
.Select(x => new FileSystemEventArgs(WatcherChangeTypes.Created, "", x)));
List<FileSystemEventArgs[]> fswArgsArrayList = new List<FileSystemEventArgs[]>();
fswArgsArrayList.Add(tempList.ToArray());
var finalObservable = fswArgsArrayList.ToArray();
var finalObservableNotArray = finalObservable.ToArray().ToObservable();
return finalObservableNotArray;
}
private IObservable<FileSystemEventArgs> CreateReactiveFSWInstance(string inputFolder, string fileFilter, bool checkBoxStatus)
{
//Creates the Reactive FSW instance
//checkBoxStatus => Enabled or not ; if the user enables the conversion, EnableRaisingEvents will be true
IObservable<FileSystemEventArgs> filesCreated =
Observable
.Using(
() =>
{
var fsw = new FileSystemWatcher(inputFolder)
{
EnableRaisingEvents = checkBoxStatus,
Filter = fileFilter
};
return fsw;
},
fsw => Observable.FromEventPattern
<FileSystemEventHandler, FileSystemEventArgs>(
h => fsw.Created += h,
h => fsw.Created -= h))
.Delay(TimeSpan.FromSeconds(0.1))
.Select(x => x.EventArgs);
return filesCreated;
}
private IObservable<FileSystemEventArgs[]> TIFFPublish(IObservable<FileSystemEventArgs> observable)
{
var GroupFiles =
observable
.Publish(fc =>
from w in fc.Window(() => fc.Throttle(TimeSpan.FromSeconds((double)counter)))
from fcs in w.ToArray()
select fcs);
return GroupFiles;
}
#endregion
private void StartCIP3ProcessingQuery(IObservable<FileSystemEventArgs[]> Files)
{
//query goes here...
}
private void StartTIFFProcessingQuery(IObservable<FileSystemEventArgs[]> Files)
{
//query goes here...
}
private void EnableTIFFtoXMLWatcher(bool status)
{
//Enable the reactive watcher for TIF files
TIFFFilesCreated = CreateReactiveFSWInstance(tb_TIFFtoXMLInputFolder.Text, "*.tif", status);
TIFFGroupFiles = TIFFPublish(TIFFFilesCreated);
StartTIFFProcessingQuery(TIFFGroupFiles);
}
private void EnableCIP3toTIFFWatcher(bool status)
{
//Enable the reactive watcher for CIP3 files
CIP3FilesCreated = CreateReactiveFSWInstance(tb_TIFFtoXMLInputFolder.Text, "*.*", status);
CIP3GroupFiles = TIFFPublish(CIP3FilesCreated);
StartCIP3ProcessingQuery(CIP3GroupFiles, false);
}
private void SubscriptionDisposal()
{
//Disposal methods
TIFFSubscription.Dispose();
CIP3Subscription.Dispose();
}
//Enable or disable the conversio, or convert all
private void CheckboxChangedEventHandler(object sender, EventArgs e)
{
CheckBox CurrChk = sender as CheckBox;
bool status = CurrChk.Checked;
switch (CurrChk.Name)
{
case "TIFFtoXML_chkConvertAll":
{
if(status)
{
cb_enableTIFFtoXML.Checked = true; //Enabling this checkbox triggers the other case and fires the FSW
var convertAllTIFFObj = CreateObjectForConvertAll(tb_TIFFtoXMLInputFolder.Text, "*.tif");
StartTIFFProcessingQuery(convertAllTIFFObj);
var convertAllCIP3Obj = CreateObjectForConvertAll(tb_TIFFtoXMLInputFolder.Text, "*.*");
StartCIP3ProcessingQuery(convertAllCIP3Obj,true);
CurrChk.Checked = false;
}
break;
}
case "cb_enableTIFFtoXML":
{
if (status)
{
EnableCIP3toTIFFWatcher(status);
EnableTIFFtoXMLWatcher(status);
CountDown();
}
else
{
//If the user disables the conversion, it will just dispose objects.
TIFFSubscription.Dispose();
CIP3Subscription.Dispose();
timer1.Stop();
}
break;
}
}
}
下面是您的代码的更接近版本:
IObservable<string> query =
from item in TIFFFiles // TIFFFiles = new Subject<string>()
let ColorSeparator = new ColorSeparatorDefiner(cmb_tiffSelectedIndex).Delimiter
let jobInfo = new CMYKJobInformationForDictionarySorting(currFile, ColorSeparator)
let file = jobInfo.ConventionName
from WriteDefaultXML in Observable.Start(() => new PPFConverter.writeFinalXml(item.Key, tb_TIFFtoXMLOutputFolder.Text))
from ImageListSorted in Observable.Start(() => ImageBuilder(item.Value, ColorSeparator))
from DPI in Observable.Start(() => new ObtainDPI(item.Value.ElementAt(0)))
from IZDataInfo in Observable.Start(() => new IZAreaDataInfo(izAreaSettings.FrmIZArea_numberOfZones, izAreaSettings.FrmIZArea_zoneWidth, izAreaSettings.FrmIZArea_firstZoneWidth, izAreaSettings.FrmIZArea_lastZoneWidth, izAreaSettings.FrmIZArea_zoneAreaWidth, izAreaSettings.FrmIZArea_zoneAreaHeight, DPI.DPI))
from RotateCMYK in Observable.Start(() => Rotate(ImageListSorted.CMYKmages, tiffToXmlpngPreviewSettings.FrmTiffPng_imageRotationCount))
from RotateImposition in Observable.Start(() => Rotate(ImageListSorted.ImposedImages, tiffToXmlpngPreviewSettings.FrmTiffPng_imageRotationCount))
from IZDraw in Observable.Start(() => InkZoneAreaImage(IZDataInfo.IzArea_ZoneAreaWidth, IZDataInfo.IzArea_ZoneAreaHeight))
from CMYKIZCalculation in Observable.Start(() => LevelCalc(IZDataInfo.IzArea_ZoneWidth, DPI.DPI, RotateCMYK.RotatedImgs, IZDraw.ZoneImage, tiffToXmlpngPreviewSettings.FrmTiffPng_imageOrientationCont))
from ImposedIZCalculation in Observable.Start(() => LevelCalc(IZDataInfo.IzArea_ZoneWidth, DPI.DPI, RotateImposition.RotatedImgs, IZDraw.ZoneImage, tiffToXmlpngPreviewSettings.FrmTiffPng_imageOrientationCont))
from CMYKResize in Observable.Start(() => ResizeCollection(RotateCMYK.RotatedImgs, tiffToXmlpngPreviewSettings.FrmTiffPng_imagePreviewWidth, tiffToXmlpngPreviewSettings.FrmTiffPng_imagePreviewHeight))
from ImpositionResize in Observable.Start(() => ResizeCollection(RotateImposition.RotatedImgs, tiffToXmlpngPreviewSettings.FrmTiffPng_imagePreviewWidth, tiffToXmlpngPreviewSettings.FrmTiffPng_imagePreviewHeight))
from CombineTHumbnail in Observable.Start(() => CombineImages(CMYKResize.ResizedImages, (bool)Properties.Settings.Default["TIFFtoXML_NegateImage"]))
from CreateComposedImage in Observable.Start(() => new SpotImageComposer(CombineTHumbnail.FinalCombinedImage, ImpositionResize.ResizedImages, tiffToXmlpngPreviewSettings.FrmTiffPng_imageOrientationCont, ColorSeparator, tiffToXmlpngPreviewSettings.TIffToXml_UnknownSpotcolorHandling))
from FinalXMLWrite in Observable.Start(() => new WriteXMLData(WriteDefaultXML.finalXmlName, WriteDefaultXML.OutputFolder, CMYKIZCalculation, ImposedIZCalculation, CreateComposedImage.FinalImage, WriteDefaultXML.xmlDoc, InfoFromFiles, ColorSeparator, item.Value))
select file;
_subscription =
query
.Subscribe(f =>
{
if ((bool)Properties.Settings.Default["TIFFtoXML_DeleteInput"])
{
System.IO.File.Delete(f); //Wanted to delete the files
}
}, () =>
{
/* code to execute when observable finishes */
/* You must call `TIFFFiles.OnCompleted()` */
});
请不要使用任何计时器、线程或任务。如果你说出原因,我可以帮助你解决你需要的问题。
所有这些都会在您调用时触发:TIFFFiles.OnNext(filename);
。
下面是观察文件系统的代码,然后根据 TimeSpan.FromSeconds(30.0)
没有进一步添加文件的情况将更改分组在一起:
IObservable<FileSystemEventArgs> filesCreated =
Observable
.Using(
() =>
{
var fsw = new FileSystemWatcher(@"C:\Users\james\Temporary\Testing");
fsw.EnableRaisingEvents = true;
return fsw;
},
fsw => Observable.FromEventPattern
<FileSystemEventHandler, FileSystemEventArgs>(
h => fsw.Created += h,
h => fsw.Created -= h))
.Delay(TimeSpan.FromSeconds(0.1))
.Select(x => x.EventArgs);
IObservable<FileSystemEventArgs[]> batchesOfFilesCreated =
filesCreated
.Publish(fc =>
from w in fc.Window(() => fc.Throttle(TimeSpan.FromSeconds(30.0)))
from fcs in w.ToArray()
select fcs);
现在您的查询如下所示:
var ColorSeparator = new ColorSeparatorDefiner(cmb_tiffSelectedIndex).Delimiter;
var query =
from gfcs in batchesOfFilesCreated.GroupBy(x => new CMYKJobInformationForDictionarySorting(currFile, ColorSeparator).ConventionName)
let file = gfcs.Key
from gfc in gfcs
from WriteDefaultXML in Observable.Start(() => new PPFConverter.writeFinalXml(item.Key, tb_TIFFtoXMLOutputFolder.Text))
from ImageListSorted in Observable.Start(() => ImageBuilder(item.Value, ColorSeparator))
from DPI in Observable.Start(() => new ObtainDPI(item.Value.ElementAt(0)))
from IZDataInfo in Observable.Start(() => new IZAreaDataInfo(izAreaSettings.FrmIZArea_numberOfZones, izAreaSettings.FrmIZArea_zoneWidth, izAreaSettings.FrmIZArea_firstZoneWidth, izAreaSettings.FrmIZArea_lastZoneWidth, izAreaSettings.FrmIZArea_zoneAreaWidth, izAreaSettings.FrmIZArea_zoneAreaHeight, DPI.DPI))
from RotateCMYK in Observable.Start(() => Rotate(ImageListSorted.CMYKmages, tiffToXmlpngPreviewSettings.FrmTiffPng_imageRotationCount))
from RotateImposition in Observable.Start(() => Rotate(ImageListSorted.ImposedImages, tiffToXmlpngPreviewSettings.FrmTiffPng_imageRotationCount))
from IZDraw in Observable.Start(() => InkZoneAreaImage(IZDataInfo.IzArea_ZoneAreaWidth, IZDataInfo.IzArea_ZoneAreaHeight))
from CMYKIZCalculation in Observable.Start(() => LevelCalc(IZDataInfo.IzArea_ZoneWidth, DPI.DPI, RotateCMYK.RotatedImgs, IZDraw.ZoneImage, tiffToXmlpngPreviewSettings.FrmTiffPng_imageOrientationCont))
from ImposedIZCalculation in Observable.Start(() => LevelCalc(IZDataInfo.IzArea_ZoneWidth, DPI.DPI, RotateImposition.RotatedImgs, IZDraw.ZoneImage, tiffToXmlpngPreviewSettings.FrmTiffPng_imageOrientationCont))
from CMYKResize in Observable.Start(() => ResizeCollection(RotateCMYK.RotatedImgs, tiffToXmlpngPreviewSettings.FrmTiffPng_imagePreviewWidth, tiffToXmlpngPreviewSettings.FrmTiffPng_imagePreviewHeight))
from ImpositionResize in Observable.Start(() => ResizeCollection(RotateImposition.RotatedImgs, tiffToXmlpngPreviewSettings.FrmTiffPng_imagePreviewWidth, tiffToXmlpngPreviewSettings.FrmTiffPng_imagePreviewHeight))
from CombineTHumbnail in Observable.Start(() => CombineImages(CMYKResize.ResizedImages, (bool)Properties.Settings.Default["TIFFtoXML_NegateImage"]))
from CreateComposedImage in Observable.Start(() => new SpotImageComposer(CombineTHumbnail.FinalCombinedImage, ImpositionResize.ResizedImages, tiffToXmlpngPreviewSettings.FrmTiffPng_imageOrientationCont, ColorSeparator, tiffToXmlpngPreviewSettings.TIffToXml_UnknownSpotcolorHandling))
from FinalXMLWrite in Observable.Start(() => new WriteXMLData(WriteDefaultXML.finalXmlName, WriteDefaultXML.OutputFolder, CMYKIZCalculation, ImposedIZCalculation, CreateComposedImage.FinalImage, WriteDefaultXML.xmlDoc, InfoFromFiles, ColorSeparator, item.Value))
select file;
_subscription =
query
.Subscribe(f =>
{
if ((bool)Properties.Settings.Default["TIFFtoXML_DeleteInput"])
{
System.IO.File.Delete(f); //Wanted to delete the files
}
}, () =>
{
/* code to execute when observable finishes */
/* You must call `TIFFFiles.OnCompleted()` */
});
注意:这消除了计时器和代码中线程的使用。您应该能够设置一次并保留它 运行。只要记得在你想让它停止时调用 _subscription.Dispose()
运行.
更新:我已经编辑以包含我所做的一切的最终代码 =)!它最终起作用了,现在我只是设置了一些细节(更多关于业务逻辑和工作流)。我知道这远非好事,但现在我决定这样做。
我的下一个目标是对所有类型的文件进行单一订阅,并处理查询本身的不同情况;它会让事情变得更容易,并允许我用更少的代码做同样的事情。并提前感谢您的帮助。这就像对我的 Reactive Extensions 的介绍嘿,我开始阅读和挖掘它。
public partial class Form1 : AsyncBaseDialog
{
private IDisposable CIP3Subscription = null;
static System.Windows.Forms.Timer timer1; //The timer is used but just for visual purposes - nothing is related to him
IObservable<FileSystemEventArgs> TIFFFilesCreated;
IObservable<FileSystemEventArgs[]> TIFFGroupFiles;
IObservable<FileSystemEventArgs> CIP3FilesCreated;
IObservable<FileSystemEventArgs[]> CIP3GroupFiles;
bool currStatus = (bool)Properties.Settings.Default["TIFFtoXML_EnabledConversion"]; //If the enable conversion checkbox is enabled, fire the observable
if(currStatus)
{
EnableTIFFtoXMLWatcher(currStatus);
EnableCIP3toTIFFWatcher(currStatus);
}
timer1 = new System.Windows.Forms.Timer();
timer1.Tick += new EventHandler(SecondElapsed);
timer1.Enabled = currStatus;
counter = Convert.ToInt32(Properties.Settings.Default.TIFFtoXML_MainTimer);
}
#region timerStuff
DateTime start;
double s;
private void CountDown()
{
start = DateTime.Now;
s = (double)counter;
timer1.Start();
}
private void SecondElapsed(object sender, EventArgs e)
{
double remainingSeconds = s - (DateTime.Now - start).TotalSeconds;
if (remainingSeconds <= 0)
{
timer1.Stop();
timer1.Interval = (int)counter;
timer1.Start();
CountDown();
}
var x = TimeSpan.FromSeconds(remainingSeconds);
tb_MainTimer.Text = x.Seconds.ToString();
}
#endregion
#region ObservableMethods //Methods i built in order to handle the observable behaviour
private IObservable<FileSystemEventArgs[]> CreateObjectForConvertAll(string inputFolder, string extension)
{
//I've a checkbox where the user selects "Convert all", and it will convert everything in the folder. Since i didn't wanted to repeat
//code by calling all methods again, this method returns me an object i can query
List<FileSystemEventArgs> tempList = new List<FileSystemEventArgs>(Directory.GetFiles(tb_TIFFtoXMLInputFolder.Text, extension, SearchOption.TopDirectoryOnly).ToList()
.Select(x => new FileSystemEventArgs(WatcherChangeTypes.Created, "", x)));
List<FileSystemEventArgs[]> fswArgsArrayList = new List<FileSystemEventArgs[]>();
fswArgsArrayList.Add(tempList.ToArray());
var finalObservable = fswArgsArrayList.ToArray();
var finalObservableNotArray = finalObservable.ToArray().ToObservable();
return finalObservableNotArray;
}
private IObservable<FileSystemEventArgs> CreateReactiveFSWInstance(string inputFolder, string fileFilter, bool checkBoxStatus)
{
//Creates the Reactive FSW instance
//checkBoxStatus => Enabled or not ; if the user enables the conversion, EnableRaisingEvents will be true
IObservable<FileSystemEventArgs> filesCreated =
Observable
.Using(
() =>
{
var fsw = new FileSystemWatcher(inputFolder)
{
EnableRaisingEvents = checkBoxStatus,
Filter = fileFilter
};
return fsw;
},
fsw => Observable.FromEventPattern
<FileSystemEventHandler, FileSystemEventArgs>(
h => fsw.Created += h,
h => fsw.Created -= h))
.Delay(TimeSpan.FromSeconds(0.1))
.Select(x => x.EventArgs);
return filesCreated;
}
private IObservable<FileSystemEventArgs[]> TIFFPublish(IObservable<FileSystemEventArgs> observable)
{
var GroupFiles =
observable
.Publish(fc =>
from w in fc.Window(() => fc.Throttle(TimeSpan.FromSeconds((double)counter)))
from fcs in w.ToArray()
select fcs);
return GroupFiles;
}
#endregion
private void StartCIP3ProcessingQuery(IObservable<FileSystemEventArgs[]> Files)
{
//query goes here...
}
private void StartTIFFProcessingQuery(IObservable<FileSystemEventArgs[]> Files)
{
//query goes here...
}
private void EnableTIFFtoXMLWatcher(bool status)
{
//Enable the reactive watcher for TIF files
TIFFFilesCreated = CreateReactiveFSWInstance(tb_TIFFtoXMLInputFolder.Text, "*.tif", status);
TIFFGroupFiles = TIFFPublish(TIFFFilesCreated);
StartTIFFProcessingQuery(TIFFGroupFiles);
}
private void EnableCIP3toTIFFWatcher(bool status)
{
//Enable the reactive watcher for CIP3 files
CIP3FilesCreated = CreateReactiveFSWInstance(tb_TIFFtoXMLInputFolder.Text, "*.*", status);
CIP3GroupFiles = TIFFPublish(CIP3FilesCreated);
StartCIP3ProcessingQuery(CIP3GroupFiles, false);
}
private void SubscriptionDisposal()
{
//Disposal methods
TIFFSubscription.Dispose();
CIP3Subscription.Dispose();
}
//Enable or disable the conversio, or convert all
private void CheckboxChangedEventHandler(object sender, EventArgs e)
{
CheckBox CurrChk = sender as CheckBox;
bool status = CurrChk.Checked;
switch (CurrChk.Name)
{
case "TIFFtoXML_chkConvertAll":
{
if(status)
{
cb_enableTIFFtoXML.Checked = true; //Enabling this checkbox triggers the other case and fires the FSW
var convertAllTIFFObj = CreateObjectForConvertAll(tb_TIFFtoXMLInputFolder.Text, "*.tif");
StartTIFFProcessingQuery(convertAllTIFFObj);
var convertAllCIP3Obj = CreateObjectForConvertAll(tb_TIFFtoXMLInputFolder.Text, "*.*");
StartCIP3ProcessingQuery(convertAllCIP3Obj,true);
CurrChk.Checked = false;
}
break;
}
case "cb_enableTIFFtoXML":
{
if (status)
{
EnableCIP3toTIFFWatcher(status);
EnableTIFFtoXMLWatcher(status);
CountDown();
}
else
{
//If the user disables the conversion, it will just dispose objects.
TIFFSubscription.Dispose();
CIP3Subscription.Dispose();
timer1.Stop();
}
break;
}
}
}