i searched for embedding custom drag and drop cursor in my wpf app. i ended up with an article which i have no idea of ONE LINE in the code suggested in (it is highlighted with the comments):
private void textBlock2_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
TextBlock btn = (TextBlock)sender;
GiveFeedbackEventHandler handler = new GiveFeedbackEventHandler(DragSource_GiveFeedback);
btn.GiveFeedback += handler;
DataObject dataObj = new DataObject(btn.Text);
DragDrop.DoDragDrop(btn, dataObj, DragDropEffects.Move);
btn.GiveFeedback -= handler;
}
void DragSource_GiveFeedback(object sender, GiveFeedbackEventArgs e)
{
try
{
if (_allOpsCursor == null)
{
////////////////////////////////////////THE UNKOWN ONE LINE STARTS HERE
using (Stream cursorStream = System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream("SimplestDragDrop.DDIcon.cur")) // AND ENDS HERE
{
_allOpsCursor = new Cursor(cursorStream);
}
}
Mouse.SetCursor(_allOpsCursor);
e.UseDefaultCursors = false;
e.Handled = true;
}
finally { }
}
i checked GetManifestResourceStream, but i still have no idea what a mainfest resource is how could it be handled and where to start to get this caching idea (mentioned in the main article) to work.
Your assembly is loaded into memory as part of the AppDomain executing under the CLR. Because of this, if the resource is embedded into the assembly as part of the compilation process, using a stream to read an in-memory byte array is faster than having to go to disk to open a file, read its contents, close the file.
Alternatives are to store a byte array representing the resource within the source code, though more or less you're arriving at the same place using GetManifestResourceStream.
Related
I am trying to write a practice Drag and Drop program.
This program will display a picture (JPG or PNG or Bitmap) when one is dropped on it. It will play a music file when dropped on it and it will play a video when a video file is dropped on it.
I would like the drop Icon to indicate what kind of file is about to be dropped when the DragOver event is fired. And if the file type is not compatible with my program I want the Icon to be able to indicate that as well.
I have been going through the DragEventArgs class for weeks trying to figure out a way of being able to tell the difference between the 3 types of media file but I have come up empty. Can anyone help with this?
You can use the DragUIOverride to customize the look of the dragged object.
You can set it with the DragOver event on the target element:
private async void Grid_DragOver(object sender, DragEventArgs e)
{
e.DragUIOverride.Caption = "Some caption";
e.DragUIOverride.IsCaptionVisible = true;
e.DragUIOverride.IsContentVisible = true;
e.DragUIOverride.IsGlyphVisible = true;
e.AcceptedOperation = DataPackageOperation.Copy;
//check the type of the file
var items = await e.DataView.GetStorageItemsAsync();
if (items.Any())
{
var storageFile = items[0] as StorageFile;
if ( storageFile.FileType == ".jpg" )
{
e.DragUIOverride.SetContentFromBitmapImage(
new BitmapImage(new Uri("ms-appx:///Assets/jpgIcon.png")));
}
else if ( storageFile.FileType == "png" )
{
e.DragUIOverride.SetContentFromBitmapImage(
new BitmapImage(new Uri("ms-appx:///Assets/pngIcon.png")));
}
//...
else
{
//for disallowed file types
e.AcceptedOperation = DataPackageOperation.None;
e.DragUIOverride.SetContentFromBitmapImage(
new BitmapImage(new Uri("ms-appx:///Assets/errorIcon.png")));
}
}
}
I asked in a previous question how to "Threading 2 forms to use simultaneously C#".
I realize now that I was not explicit enough and was asking the wrong question.
Here is my scenario:
I have some data, that I receive from a local server, that I need to write to a file.
This data is being sent at a constant time rate that I cant control.
What I would like to do is to have one winform for the initial setup of the tcp stream and then click on a button to start reading the tcp stream and write it to a file, and at the same time launch another winform with multiple check-boxes that I need to check the checked state and add that info simultaneously to the same file.
This processing is to be stopped when a different button is pressed, closing the stream, the file and the second winform. (this button location is not specifically mandatory to any of the winforms).
Because of this cancel button (and before I tried to implement the 2nd form) I used a background worker to be able to asynchronously cancel the do while loop used to read the stream and write the file.
private void bRecord_Click(object sender, EventArgs e)
{
System.IO.StreamWriter file = new System.IO.StreamWriter(AppDomain.CurrentDomain.BaseDirectory + DateTime.Now.ToString("yyyy-dd-M--HH-mm-ss") + ".xml", true);
data_feed = client.GetStream();
data_write = new StreamWriter(data_feed);
data_write.Write("<SEND_DATA/>\r\n");
data_write.Flush();
exit_state = false;
string behavior = null;
//code to launch form2 with the checkboxes
//...
worker = new BackgroundWorker();
worker.WorkerSupportsCancellation = true;
worker.DoWork += new DoWorkEventHandler((state, args) =>
{
do
{
int var = data_feed.ReadByte();
if (var != -1)
{
data_in += (char)var;
if (data_in.IndexOf("\r\n") != -1)
{
//code to check the checkboxes state in form2
//if (form2.checkBox1.Checked) behavior = form2.checkBox1.Text;
//if (form2.checkBoxn.Checked) behavior = form2.checkBoxn.Text;
file.WriteLine(data_in + behavior);
data_in = "";
}
}
}
while (exit_state == false);
});
worker.RunWorkerAsync();
}
private void bStop_Click(object sender, EventArgs e)
{
exit_state = true;
worker.CancelAsync();
}
I hope I've been clearer now.
I not experienced in event programming and just started in C# so please try to provide some simple examples in the answers if possible.
At first would it be enough to use one Winform? Disable all checkboxes, click a button which enables the checkboxes and start reading the tcpstream? If you need two Forms for other reasons let me know, but i think this isn't needed from what i can see in your question.
Then i would suggest you to use the Task Library from .Net. This is the "modern" way to handle multithreading. BackgroundWorker is kind of old school. If you just able to run on .Net 2.0 you have to use BackgroundWorker, but don't seem to be the case (example follows).
Further if you want to cancel a BackgroundWorker operation this isn't only call CancelAsync();. You also need to handle the e.Cancelled flag.
backgroundWorker.WorkerSupportsCancellation = true;
private void CancelBW()
{
backgroundWorker.CancelAsync();
}
private void backgroundWorker_DoWork += ((sender, args)
{
//Handle the cancellation (in your case do this in your loop for sure)
if (e.Cancelled) //Flag is true if someone call backgroundWorker.CancelAsync();
return;
//Do your stuff.
});
There is no common way to directly cancel the backgroundWorker
operation. You always need to handle this.
Now let's change your code to the modern TAP-Pattern and make some stuff you want to have.
private void MyForm : Form
{
private CancellationTokenSource ct;
public MyForm()
{
InitializeComponent();
checkbox1.Enable = false;
//Disable all checkboxes here.
ct = new CancellationTokenSource();
}
//Event if someone click your start button
private void buttonStart_Click(object sender, EventArgs e)
{
//Enable all checkboxes here
//This will be called if we get some progress from tcp
var progress = new Progress<string>(value =>
{
//check the behaviour of the checkboxes and write to file
file.WriteLine(value + behavior);
});
Task.Factory.StartNew(() => ListenToTcp(ct, progress as IProgress<string)); //starts the tcp listening async
}
//Event if someone click your stop button
private void buttonStop_Click(object sender, EventArgs e)
{
ct.Cancel();
//Disable all checkboxes (better make a method for this :D)
}
private void ListenToTcp(CancellationToken ct, IProgess<string> progress)
{
do
{
if (ct.IsCancellationRequested)
return;
int temp = data_feed.ReadByte(); //replaced var => temp because var is keyword
if (temp != -1)
{
data_in += (char)temp;
if (data_in.IndexOf("\r\n") != -1)
{
if (progress != null)
progress.Report(data_in); //Report the tcp-data to form thread
data_in = string.empty;
}
}
while (exit_state == false);
}
}
This snippet should do the trick. I don't test it so some syntax error maybe occur :P, but the principle will work.
The most important part is that you are not allowed to access gui
components in another thread then gui thread. You tried to access the
checkboxes within your BackgroundWorker DoWork which is no possible
and throw an exception.
So I use a Progress-Object to reuse the data we get in the Tcp-Stream, back to the Main-Thread. There we can access the checkboxes, build our string and write it to the file. More about BackgroundWorker vs. Task and the Progress behaviour you can find here.
Let me know if you have any further questions.
Yes there are many similar questions but none of them address my unique situation.
There is a separate c++ process writing the file using c++ printf and fprintf.
filename i am trying to watch is info_20160525.log
My fileSystemWatcher in winform C# application gets notification when the writer process writes to the file AND I physically access the file i-e F5 the folder or have it open in textpad and click the opened file or right click the file but I never get any event notification when I dont physically interact with the file.
Also, when I shutdown the writer application I do get the notification.
Here is my code.
public bool StartUp(string fullfilepath, int linenumber)
{
if (!File.Exists(fullfilepath))
return false;
if (!LogClass.CheckPathExists(m_applicationPath))
return false;
try
{
FileInfo info = new FileInfo(fullfilepath);
m_filename = fullfilepath;
m_fileWatcher = new FileSystemWatcher(info.DirectoryName, info.Name);
m_fileWatcher.NotifyFilter = NotifyFilters.Attributes | NotifyFilters.LastAccess
| NotifyFilters.LastWrite | NotifyFilters.Size ;
m_fileWatcher.Changed += m_fileWatcher_Changed;
m_fileWatcher.Error += m_fileWatcher_Error;
m_fileWatcher.Created += m_fileWatcher_Created;
m_fileWatcher.Deleted += m_fileWatcher_Deleted;
m_fileWatcher.Disposed += m_fileWatcher_Disposed;
m_fileWatcher.Renamed += m_fileWatcher_Renamed;
m_linesRead = linenumber;
m_fileWatcher.EnableRaisingEvents = true;
}
catch(Exception e)
{
LogClass.LogError(e, "Trouble accessing the file" + fullfilepath, m_applicationPath);
}
return true;
}
These are the handlers. I have breakpoints in each one of them but I never get a trigger unless ofcourse I physically interact with the file.
void m_fileWatcher_Renamed(object sender, RenamedEventArgs e)
{
string S = "";
}
void m_fileWatcher_Disposed(object sender, EventArgs e)
{
string S = "";
}
void m_fileWatcher_Deleted(object sender, FileSystemEventArgs e)
{
string S = "";
}
void m_fileWatcher_Created(object sender, FileSystemEventArgs e)
{
string S = "";
}
void m_fileWatcher_Error(object sender, ErrorEventArgs e)
{
string S = "";
}
void m_fileWatcher_Changed(object sender, FileSystemEventArgs args)
{
if (args.ChangeType == WatcherChangeTypes.Changed)
{
while (ParseFile(args.FullPath))
{
}
}
}
I bet this thread has your answer --> FileSystemWatcher changed event (for “LastWrite”) is unreliable
The FileSystemWatcher uses an update to the LastWrite attribute of a file to fire events, however, the LastWrite is not updated in real time and should not be relied upon as trigger for an event.
If you have enough time and resources on your hands then you probably want to look into File System Filters and the simpler approach of a Filter Manager and Minifilter Driver. It is driver type development, however, it is a sure file way to accomplish your objective.
It is dug down a little deeper by system policy but gives you a wide array of events to latch onto. If I was doing this for anything like pci compliance or similar tasks then I would not use the FileSystemWatcher.
Make sure you set IncludeSubdirectories to true.
https://msdn.microsoft.com/en-us/library/system.io.filesystemwatcher(v=vs.110).aspx
I was trying to delete an Image from the view Model after some modification but I'm getting this error message IOException was unhandled
I disposed the current bitmap currImgHandler.CurrentBitmap.Dispose();and also made the Image Source to be null ViewedPhoto.Source = null;
if i click on the button which has the Rotate function (90°) once and clikcing on the delete function which produces the error IOException was unhandled
If i clcik on the button Roate function twicethen click on Delete function; I don't get any error and it deletes image without any problem.
What is the mistake am I doing here? Thank you
Selecting an Image from ListView:
private string saveFilname;
private void showImage(object sender, SelectionChangedEventArgs args)
{
ListBox list = ((ListBox)sender);
if (list != null)
{
int index = list.SelectedIndex;
if (index >= 0)
{
ImageFileViewModel image = imageListBox.SelectedItem as ImageFileViewModel;
if ((image != null))
{
saveFilname = image.FileName.ToString();
currImgHandler.CurrentFileHandler.Load(image.FileName);
PaintImage();
}
}
}
}
Delete Function:
private void bDeletePhoto_Click(object sender, RoutedEventArgs e)
{
ImageFileCollectionViewModel viewModel = imageListBox.DataContext as ImageFileCollectionViewModel;
if (viewModel != null)
{
ImageFileViewModel image = imageListBox.SelectedItem as ImageFileViewModel;
if (image != null)
{
//remove physical file from disk:
currImgHandler.CurrentBitmap.Dispose();
ViewedPhoto.Source = null;
File.Delete(image.FileName);
//remove item from ObservableCollection:
viewModel.AllImages.Remove(image);
}
}
}
//Rotate Function:
private void Button_Click(object sender, RoutedEventArgs e)//Rotate
{
currImgHandler.CurrentRotationHandler.Flip(RotateFlipType.Rotate90FlipNone);
PaintImage();
}
private void PaintImage()
{
System.IO.MemoryStream stream = new System.IO.MemoryStream();
currImgHandler.CurrentBitmap.Save(stream, System.Drawing.Imaging.ImageFormat.Bmp);
stream.Position = 0;
byte[] data = new byte[stream.Length];
stream.Read(data, 0, Convert.ToInt32(stream.Length));
BitmapImage bmapImage = new BitmapImage();
bmapImage.BeginInit();
bmapImage.CacheOption = BitmapCacheOption.OnLoad;
bmapImage.StreamSource = stream;
bmapImage.EndInit();
ViewedPhoto.Source = bmapImage; //ImageBox
ViewedPhoto.Stretch = Stretch.Uniform;
}
Error message:
Your application is throwing an IOException. Likely culprit:
File.Delete(image.FileName);
IMO You should avoid making calls like this directly in event handlers for the reason demonstrated here - it is hard to catch exceptions thrown directly from an event handler.
If implementing MVVM this doesn't tend to occur.
Perhaps the account privileges under which your application is running are not sufficient to let you delete the file. Please check the credentials of this account against operations on the file you want to delete.
It's only a supposition though, it's hard to be sure without the IOEXception content, and it could also be because the path you're using doesn't exist, etc...
After Drew Rsuggestion i have added a method in the MVVM itself:
public void RemoveOldPhotoItem(ImageFileViewModel imageFile)
{
this._allImages.Remove(imageFile);
this.DataItemsCount++;
File.Delete(imageFile.FileName);
}
I need to dispose the image which was used by a 3rd party .dll....which i disposed properly.
Sorry guys it was my mistake. Thank you for your support!
I have a refresh button to update news in my WP7 application. When I double or triple click on the refresh button I am getting an error
"WebClient does not support concurrent I/O operations" .
I think thats because It is sending the request triple times and making it crash. Here is my Click code.
private void NewsRefresh_Click(object sender, RoutedEventArgs e)
{
var vm = this.DataContext as MainPageViewModel;
if (vm != null)
{
vm.UpdateNews();
}
}
How can I turn it as "if It is busy cancel the process".
WebClient isn't very flexible but if you really want to use it you can make use of the IsBusy property and then cancel ongoing operation. Then, once it's cancelled you can restart it. There is important problem with synchronization. The operation which consists of checking IsBusy and invoking CancelAsync isn't atomic. Luckily DownloadStringCompleted is dispatched to the UI thread so you don't need to bother about synchronization. The snippet below shows how can you achieve it. For simplicity it's Windows Forms.
public partial class Form1 : Form
{
WebClient _WebClient;
bool _UpdateNews;
public Form1()
{
InitializeComponent();
_WebClient = new WebClient();
_WebClient.DownloadStringCompleted += new DownloadStringCompletedEventHandler(_WebClient_DownloadStringCompleted);
_UpdateNews = false;
}
void _WebClient_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
if (_UpdateNews)
{
_UpdateNews = false;
UpdateNews();
}
else if (e.Error != null)
{
// Report error
}
else
{
MessageBox.Show(e.Result);
}
}
private void button1_Click(object sender, EventArgs e)
{
if (_WebClient.IsBusy)
{
_WebClient.CancelAsync();
_UpdateNews = true;
}
else
{
UpdateNews();
}
}
private void UpdateNews()
{
_WebClient.DownloadStringAsync(new Uri("http://stackoverflow.com/questions/7084948/c-concurrent-i-o-operations-exception"));
}
}
The 'easy' way (though not bullet proof):
private void NewsRefresh_Click(object sender, RoutedEventArgs e)
{
try
{
NewsRefresh.Enabled = false;
var vm = this.DataContext as MainPageViewModel;
if (vm != null)
{
vm.UpdateNews();
}
}
finally
{
NewsRefresh.Enabled = true;
}
}
The more difficult approach would require more details on what exactly a MainPageViewModel is, and what UpdateNews() does. Basically you need to store a state value wherever you are storing the WebClient instance. Before using the WebClient you need check to see if you are already using it. The issue comes when multiple threads may operate on a single instance, or if you multiple operations (other than UpdateNews). When multiple threads are involved the easiest thing is to surround the usage of the WebClient with a Mutex.
Of course the other option is to not reuse the WebClient instance, rather create a new one for each new request.
UPDATE
Well, well, using DownloadStringAsync is certainly going to make things fun. The above code Disabling the UI will not work unless you move the re-enabling code. It would be easiest to go with my last suggestion and just create a new instance of WebClient. I'm not real fond of WebClient myself and prefer using WebRequest.Create.