I want to get the text input of the CoreTextServicesManager, but the TextUpdating event is not even triggered. In my UWP project, it is working fine.
This is how I create the Service:
CoreTextServicesManager manager = CoreTextServicesManager.GetForCurrentView();
CoreTextEditContext EditContext = manager.CreateEditContext();
EditContext.InputPaneDisplayPolicy = CoreTextInputPaneDisplayPolicy.Manual;
EditContext.InputScope = CoreTextInputScope.Text;
EditContext.TextRequested += delegate { };
EditContext.SelectionRequested += delegate { };
EditContext.TextUpdating += EditContext_TextUpdating;
EditContext.FocusRemoved += EditContext_FocusRemoved;
EditContext.NotifyFocusEnter();
Here are my events:
private void EditContext_TextUpdating(CoreTextEditContext sender,
CoreTextTextUpdatingEventArgs args)
{
Debug.WriteLine(args.Text);
}
private void EditContext_FocusRemoved(CoreTextEditContext sender, object args)
{
Debug.WriteLine("Lost focus");
}
Why does the TextUpdating event not trigger? what am I doing wrong?
I'm not sure if you've already seen this (late reply after I found this question by Google), but support for some UWP APIs was unfortunately dropped. This article suggests some replacements and workarounds for some of them.
https://learn.microsoft.com/en-gb/windows/apps/desktop/modernize/desktop-to-uwp-supported-api
We have it working in our UWP app. Make sure you're on the main thread
imeInputPane = CoreInputView.GetForCurrentView();
imeInputPane.PrimaryViewShowing += ImeInputPane_PrimaryViewShowing;
imeInputPane.PrimaryViewHiding += ImeInputPane_PrimaryViewHiding;
imeTextContext = CoreTextServicesManager.GetForCurrentView().CreateEditContext();
// Manually control when soft keyboard shows. When hard keyboard is attached, the
// soft keyboard will never show.
imeTextContext.InputPaneDisplayPolicy = CoreTextInputPaneDisplayPolicy.Manual;
// the default keyboard is general purpose soft keyboard, has no affect with hard keyboard
imeTextContext.InputScope = CoreTextInputScope.Text;
imeTextContext.TextRequested += IMETextContext_TextRequested;
imeTextContext.SelectionRequested += IMETextContext_SelectionRequested;
imeTextContext.FocusRemoved += IMETextContext_FocusRemoved;
imeTextContext.TextUpdating += IMETextContext_TextUpdating;
imeTextContext.SelectionUpdating += IMETextContext_SelectionUpdating;
imeTextContext.FormatUpdating += IMETextContext_FormatUpdating;
imeTextContext.LayoutRequested += IMETextContext_LayoutRequested;
imeTextContext.CompositionStarted += IMETextContext_CompositionStarted;
imeTextContext.CompositionCompleted += IMETextContext_CompositionCompleted;
...
private void IMETextContext_TextUpdating(CoreTextEditContext sender, CoreTextTextUpdatingEventArgs args)
{
string origText = imeText;
CoreTextRange range = args.Range;
CoreTextRange newSelection = args.NewSelection;
//Modify the internal text store for the IME
imeText = imeText.Substring(0, range.StartCaretPosition)
+ args.Text
+ imeText.Substring(Math.Min(imeText.Length,
range.EndCaretPosition));
newSelection.EndCaretPosition = newSelection.StartCaretPosition;
Debug.WriteLine(string.Format("IME SendReplaceText Orig Text '{0}' New Text '{1}' StartCaret '{2}' EndCaret '{3}'", origText, imeText, imeSelection.StartCaretPosition, imeSelection.EndCaretPosition - imeSelection.StartCaretPosition));
// Do something with the text
SendReplaceText(args.Text // new text
, range.StartCaretPosition // start position
, range.EndCaretPosition - range.StartCaretPosition // length of former text that is being replaced
, args.Text.Length); // length of the modified text
imeSelection = newSelection;
args.Result = CoreTextTextUpdatingResult.Succeeded;
}
private void IMEBypassControl_OnShowKeyboard(object sender, IMEBypassShowKeyboardEventArgs e)
{
try
{
if (e.Visible)
{
Task.Run(async () =>
{
if (MiscUtils.AreWeOnMainUIThread)
{
try
{
LOG.LogV(string.Format("IME Show Keyboard '{0}' Start '{1}' Total Size '{2}", e.Text, e.CursorPosition, e.FetchSize));
//Debug.WriteLine(string.Format("IME Show Keyboard '{0}' Start '{1}' Total Size '{2}", e.Text, e.CursorPosition, e.FetchSize));
imeTextContext.InputScope = CoreTextInputScope.Text;
imeText = e.Text;
imeSelection.StartCaretPosition = e.CursorPosition;
imeSelection.EndCaretPosition = e.CursorPosition;
imeTextContext.NotifyTextChanged(imeSelection, e.Text.Length, imeSelection);
SetFocus();
}
catch (Exception ex)
{
LOG.LogE(ex);
}
}
else
{
await MiscUtils.CallOnMainViewUiThreadAsync(() =>
{
try
{
LOG.LogV(string.Format("IME Show Keyboard '{0}' Start '{1}' Total Size '{2}", e.Text, e.CursorPosition, e.FetchSize));
//Debug.WriteLine(string.Format("IME Show Keyboard '{0}' Start '{1}' Total Size '{2}", e.Text, e.CursorPosition, e.FetchSize));
imeTextContext.InputScope = CoreTextInputScope.Text;
imeText = e.Text;
imeSelection.StartCaretPosition = e.CursorPosition;
imeSelection.EndCaretPosition = e.CursorPosition;
imeTextContext.NotifyTextChanged(imeSelection, e.Text.Length, imeSelection);
SetFocus();
}
catch (Exception ex)
{
LOG.LogE(ex);
}
});
}
}).GetAwaiter().GetResult();
}
else
{
RemoveFocus();
}
}
catch (Exception ex)
{
LOG.LogE(ex);
}
}
else
{
RemoveFocus();
}
}
private void SetFocus()
{
imeTextContext.NotifyFocusEnter();
}
public void RemoveFocus()
{
if (MiscUtils.AreWeOnMainUIThread)
{
imeTextContext.NotifyFocusLeave();
imeInputPane.TryHide();
}
else
{
Task.Run(async () =>
{
await MiscUtils.CallOnMainViewUiThreadAsync(() =>
{
imeTextContext.NotifyFocusLeave();
imeInputPane.TryHide();
});
}).GetAwaiter().GetResult();
}
}
Related
Everyone!!!
I am studying BluetoothLE. Can you give me some advice if you can’t help me?
Studying the example source of BluetoothLE in Windows 10 Universal Windows:Character_ValueChanged () does not respond to the Characteristic function. In the example source, the value change is called a function recall, but it does not respond to WinForm.
Please….
private GattCharacteristic registeredCharacteristic;
Hi.
I am studying BluetoothLE. And then I looked at the data and then I saw the blog. Can you give me some advice if you can’t help me?
Studying the example source of BluetoothLE in Windows 10 Universal Windows:Character_ValueChanged () does not respond to the Characteristic function. In the example source, the value change is called a function recall, but it does not respond to WinForm.
Please….
private GattCharacteristic registeredCharacteristic;
.
.
private async void BTN_Change_SubscribeToggle_Click(object sender, EventArgs e)
{
if (!subscribedForNotifications)
{
// initialize status
GattCommunicationStatus status = GattCommunicationStatus.Unreachable;
var cccdValue = GattClientCharacteristicConfigurationDescriptorValue.None;
if (selectedCharacteristic.CharacteristicProperties.HasFlag(GattCharacteristicProperties.Indicate))
{
cccdValue = GattClientCharacteristicConfigurationDescriptorValue.Indicate;
}
else if (selectedCharacteristic.CharacteristicProperties.HasFlag(GattCharacteristicProperties.Notify))
{
cccdValue = GattClientCharacteristicConfigurationDescriptorValue.Notify;
}
Debug.WriteLine("[ cccdValue = {0} ]", cccdValue);
try
{
// BT_Code: Must write the CCCD in order for server to send indications.
// We receive them in the ValueChanged event handler.
status = await selectedCharacteristic.WriteClientCharacteristicConfigurationDescriptorAsync(cccdValue);
Debug.WriteLine("[ status = {0} ]", status);
if (status == GattCommunicationStatus.Success)
{
AddValueChangedHandler();
Notify_User("Successfully subscribed for value changes", NotifyType.StatusMessage);
}
else
{
Notify_User("Error registering for value changes : " + status.ToString(), NotifyType.ErrorMessage);
}
}
catch (UnauthorizedAccessException ex)
{
// This usually happens when a device reports that it support indicate, but it actually doesn't.
Notify_User(ex.Message, NotifyType.ErrorMessage);
}
} // if(!subscribedForNotifications)
else
{
try
{
// BT_Code: Must write the CCCD in order for server to send notifications.
// We receive them in the ValueChanged event handler.
// Note that this sample configures either Indicate or Notify, but not both.
var result = await
selectedCharacteristic.WriteClientCharacteristicConfigurationDescriptorAsync(
GattClientCharacteristicConfigurationDescriptorValue.None);
Debug.WriteLine("[ result = {0} ]", result);
if (result == GattCommunicationStatus.Success)
{
subscribedForNotifications = false;
RemoveValueChangedHandler();
Notify_User("Successfully un-registered for notifications", NotifyType.StatusMessage);
}
else
{
Notify_User("Error un-registered for notifications : " + result, NotifyType.ErrorMessage);
}
}
catch (UnauthorizedAccessException ex)
{
Notify_User(ex.Message, NotifyType.ErrorMessage);
}
} // else
}
private void AddValueChangedHandler()
{
Debug.WriteLine("[ AddValueChangedHandler() ]");
Debug.WriteLine("[ subscribedForNotifications = {0} ]", subscribedForNotifications);
BTN_Change_SubscribeToggle.Text = "Unsubscribe from value changes";
if (!subscribedForNotifications)
{
registeredCharacteristic = selectedCharacteristic;
registeredCharacteristic.ValueChanged += Characteristic_ValueChanged;
subscribedForNotifications = true;
CTR_Update_Visible(LB_Value, true);
CTR_Update_Msg(LB_Value, "test");
}
}
private async void Characteristic_ValueChanged(GattCharacteristic sender, GattValueChangedEventArgs args)
{
// BT_Code: An Indicate or Notify reported that the value has changed.
// Display the new value with a timestamp.
//var reader = DataReader.FromBuffer(args.CharacteristicValue);
Debug.WriteLine("[ Characteristic_ValueChanged ]");
var newValue = FormatValueByPresentation(args.CharacteristicValue, presentationFormat);
var message = string.Format("Value at {0} : \r\n\t {1}", DateTime.Now.ToString("HH:mm:ss.FFF"), newValue);
}
All I could understand is this:
the value change is called a function recall, but it does not respond to WinForm.
To fix it try removing the Async from the button click:
private async void BTN_Change_SubscribeToggle_Click(object sender, EventArgs e)
{
I have a function to detect a textfield to recognize a barcode scanner input or human input in my winform application:
DateTime lastKeyPress = DateTime.Now;
private void searchContent_TextChanged(object sender, EventArgs e)
{
TimeSpan elapsed = (DateTime.Now - lastKeyPress);
if (elapsed.TotalMilliseconds > 10)
{
cartBarcode.Text = "not barcode";
}
else
{
cartBarcode.Text = "is barcode";
//after the last character was printed
addBarcodeProductToCart ();
}
lastKeyPress = DateTime.Now;
}
private void addBarcodeProductToCart ()
{
cartGridView.Rows[0].Selected = true;
}
The problem of above is that after 2 characters was printed, addBarcodeProductToCart is already executed. How to detect last character was typed in above function?
As per my main comment. Why not delay for a second or two?
however detecting a barcode is typically done by calculating the check digit
How do I validate a UPC or EAN code?
private CancelationTokenSource _cancellationTokenSource= new CancelationTokenSource();
private void searchContent_TextChanged(object sender, EventArgs e)
{
Task.Run(async () =>
{
_cancellationTokenSource.Cancel();
_cancellationTokenSource = new CancellationTokenSource();
var token = _cancellationTokenSource.Token;
try
{
await Task.Delay(TimeSpan.FromSeconds(TimeSpan.FromSeconds(2), token).ContinueWith(r =>
{
if (!token.IsCancellationRequested)
{
addBarcodeProductToCart ();
}
}, token);
}
catch (TaskCanceledException e)
{
//noop
}
}).ConfigureAwait(false);
}
I have a function called getMessages that can be called by a Button click (using the RelayCommand trigger) or that is called in a timer every 15s.
The desired behavior is:
webservice > deserialize answer > system notification > updatelistview > insert localDB
But when the function is called by the timer the updatelistview is not done. Why does this happen if the function is the same and works perfectly in the button command?
CODE:
// Get messages for the logged in user
public async void getMessages()
{
try
{
List<FriendGetMessage> msg = new List<FriendGetMessage>();
var response = await CommunicationWebServices.GetCHAT("users/" + au.idUser + "/get", au.token);
if (response.StatusCode == HttpStatusCode.OK) // If there are messages for me.
{
var aux = await response.Content.ReadAsStringAsync();
IEnumerable<FriendGetMessage> result = JsonConvert.DeserializeObject<IEnumerable<FriendGetMessage>>(aux);
if (result != null)
{
foreach (var m in result)
{
msg.Add(m);
}
//MsgList=msg;
foreach (var f in Friends)
{
if (f.msg == null || f.msg.Count() == 0)
{
f.msg = new ObservableCollection<Messages>();
}
foreach (var mess in msg)
{
if (mess.idUser == f.idUser)
{
Messages mm = new Messages();
mm.received = mess.message;
mm.timestamp = "Received " + mess.serverTimestamp;
mm.align = "Right";
// Add to the friend list.
f.msg.Add(mm);
// Add to Local DB
InsertMessage(null, au.idUser.ToString(), f.idUser, mess.message, mess.serverTimestamp);
var notification = new System.Windows.Forms.NotifyIcon()
{
Visible = true,
Icon = System.Drawing.SystemIcons.Information,
BalloonTipIcon = System.Windows.Forms.ToolTipIcon.Info,
BalloonTipTitle = "New Message from " + f.name,
BalloonTipText = "Message: " + mess.message,
};
// Display for 5 seconds.
notification.ShowBalloonTip(5);
// The notification should be disposed when you don't need it anymore,
// but doing so will immediately close the balloon if it's visible.
notification.Dispose();
}
}
}
counterChat = 1; // resets the counter
}
}
else {
counterChat = counterChat * 2;
}
//var sql = "select * from chat";
//var respo = GetFromDatabase(sql);
OnPropertyChanged("Friends");
}
catch (Exception e)
{
MessageBox.Show("GetMessages: " + e);
Debug.WriteLine("{0} Exception caught.", e);
}
}
CODE TIMER:
public void chatUpdate()
{
_timerChat = new DispatcherTimer(DispatcherPriority.Render);
_timerChat.Interval = TimeSpan.FromSeconds(15);
_timerChat.Tick += new EventHandler(timerchat_Tick);
_timerChat.Start();
}
public void timerchat_Tick(object sender, EventArgs e)
{
if (counterChat != incChat)
{
incChat++;
}
else
{
getMessages();
OnPropertyChanged("Friends");
incChat = 0;
}
}
ADDED - I've also tried this and didn't worked (it seems that is some kind of concurrency problem to the ObservableCollection called Friends (is a friendslist) each friend has an ObservableCollection of messages (is a chat))
public void chatUpdate()
{
_timerChat = new DispatcherTimer(DispatcherPriority.Render);
_timerChat.Interval = TimeSpan.FromSeconds(15);
_timerChat.Tick += new EventHandler(timerchat_Tick);
_timerChat.Start();
}
public async void timerchat_Tick(object sender, EventArgs e)
{
if (counterChat != incChat)
{
incChat++;
}
else
{
Application.Current.Dispatcher.Invoke((Action)async delegate { await getMessages(); });
incChat = 0;
}
}
Best regards,
I think you need to make the timer handler be an async method as follows:
public async void timerchat_Tick(object sender, EventArgs e)
{
if (counterChat != incChat)
{
incChat++;
}
else
{
await getMessages();
OnPropertyChanged("Friends");
incChat = 0;
}
}
This way OnPropertyChanged("Friends") is guaranteed to fire after the work in getMessages is done.
The methods need to change to:
DispatcherTimer _timerChat = new DispatcherTimer(DispatcherPriority.Render);
_timerChat.Interval = TimeSpan.FromSeconds(15);
_timerChat.Tick += new EventHandler(timerchat_Tick);
_timerChat.Start();
public async void timerchat_Tick(object sender, EventArgs e)
{
//...
await getMessages();
//...
}
public async Task getMessages()
{
try
{
// ... your code here
string result = await response.Content.ReadAsStringAsync();
// .... rest of your code
}
catch (Exception e)
{
MessageBox.Show("GetMessages: " + e);
}
}
It is solved. The problem was in my ViewModels I was opening multiple threads and sometimes the right one would update the UI and sometimes no.
Thanks for all the answers.
I got a strange issue with my searchBox in Windows 8.1 App.
I got an unhandler exception (and a crush) if in my Suggestion i do not append the querySuggestion and append only the ResultSuggestion.
the problem occurs when i change the queryText.
This is my function
public async void OnSuggest(Windows.UI.Xaml.Controls.SearchBox e, SearchBoxSuggestionsRequestedEventArgs args)
{
var deferral = args.Request.GetDeferral();
var queryText = args.QueryText != null ? args.QueryText.Trim() : null;
if (string.IsNullOrEmpty(queryText)) return;
TransporterExt tr_search = new TransporterExt();
tr_search.name = queryText;
try
{
var suggestionCollection = args.Request.SearchSuggestionCollection;
ObservableCollection<TransporterExt> querySuggestions = await TransporterService.Search(tr_search);
if (querySuggestions != null && querySuggestions.Count > 0)
{
foreach (TransporterExt tr in querySuggestions)
{
//if (tr.name.ToUpperInvariant().Contains(e.QueryText.ToUpperInvariant()))
//{
// //suggestionCollection.AppendQuerySuggestion(tr.name);
// suggestionCollection.AppendResultSuggestion(tr.name,
// tr.trId.ToString(),
// tr.trId.ToString(),
// imgRef, "imgDesc");
//}
suggestionCollection.AppendQuerySuggestion(tr.name);
}
}
}
catch (Exception)
{
//Ignore any exceptions that occur trying to find search suggestions.
}
deferral.Complete();
}
I got the searchBox inside an UserControl
My controller code
public delegate void SuggestionsRequested(Windows.UI.Xaml.Controls.SearchBox sender, SearchBoxSuggestionsRequestedEventArgs args);
public event Windows.Foundation.TypedEventHandler<Windows.UI.Xaml.Controls.SearchBox, SearchBoxSuggestionsRequestedEventArgs> SearchBoxSuggestionsRequested;
private void SearchBoxSuggestions(Windows.UI.Xaml.Controls.SearchBox sender, SearchBoxSuggestionsRequestedEventArgs args)
{
if (SearchBoxSuggestionsRequested != null)
SearchBoxSuggestionsRequested(sender, args);
}
I got this exception
WinRT: A method was called at an unexpected time.
exception: System.InvalidOperationException - type (string)
Edited Solution - Working function
First of all i remove from the constructor of the page the registration of event
public TruckCrudPage()
{
this.InitializeComponent();
this.navigationHelper = new NavigationHelper(this);
this.navigationHelper.LoadState += navigationHelper_LoadState;
this.navigationHelper.SaveState += navigationHelper_SaveState;
//this.truckForm.SearchBoxSuggestionsRequested += OnSuggest;
}
public async void OnSuggest(Windows.UI.Xaml.Controls.SearchBox e, SearchBoxSuggestionsRequestedEventArgs args)
{
var deferral = args.Request.GetDeferral();
TransporterExt tr_search = new TransporterExt();
ObservableCollection<TransporterExt> querySuggestions = new ObservableCollection<TransporterExt>();
var queryText = args.QueryText != null ? args.QueryText.Trim() : null;
if (string.IsNullOrEmpty(queryText)) return;
suggested.Clear();
tr_search.name = queryText;
try
{
var suggestionCollection = args.Request.SearchSuggestionCollection;
querySuggestions = await TransporterService.Search(tr_search);
if (querySuggestions != null && querySuggestions.Count > 0 )
{
int i = 0;
foreach (TransporterExt tr in querySuggestions)
{
if (tr.name.StartsWith(e.QueryText, StringComparison.CurrentCultureIgnoreCase))
//if (tr.name.ToLower().Contains(e.QueryText))
{
string name = tr.name;
string detail = tr.trId.ToString();
string tag = i.ToString();
string imageAlternate = "imgDesc";
suggestionCollection.AppendResultSuggestion(name, detail, tag, imgRef, imageAlternate);
suggested.Add(tr);
//Debug.WriteLine("dentro" + suggested.Count);
i++;
}
}
}
}
catch (Exception exc)
{
//Ignore any exceptions that occur trying to find search suggestions.
Debug.WriteLine("Exception generata " + exc.Message);
Debug.WriteLine(exc.StackTrace);
}
deferral.Complete();
}
But it works only with condition StartsWith and i would like to use Contains
You can use SearchBox and SuggestionRequested event to fire the event when type on the SearchBox. I will show an Example
<SearchBox x:Name="SearchBoxSuggestions" SuggestionsRequested="SearchBoxEventsSuggestionsRequested"/>
and write the SearchBoxEventsSuggestionsRequested handler in the code behind
private void SearchBoxEventsSuggestionsRequested(object sender, SearchBoxSuggestionsRequestedEventArgs e)
{
string queryText = e.QueryText;
if (!string.IsNullOrEmpty(queryText))
{
Windows.ApplicationModel.Search.SearchSuggestionCollection suggestionCollection = e.Request.SearchSuggestionCollection;
foreach (string suggestion in SuggestionList)
{
if (suggestion.StartsWith(queryText, StringComparison.CurrentCultureIgnoreCase))
{
suggestionCollection.AppendQuerySuggestion(suggestion);
}
}
}
}
You can add the keyword to SuggestioList, and it will show in the dropdown when you type on the Searchbox.
Create the SuggestionList
public List<string> SuggestionList { get; set; }
initialize the list
SuggestionList = new List<string>();
and add keywords to the list
SuggestionList.Add("suggestion1");
SuggestionList.Add("suggestion2");
SuggestionList.Add("suggestion3");
SuggestionList.Add("suggestion4");
SuggestionList.Add("Fruits");
When you type s on the Searchbox it will show all the keyword starts with s.
Thanks.
I have a winform application that runs in background with a BackgroundWorker that has an infinite loop that execute something every hour. My UI Form class is something like this:
public partial class frmAutoScript : Form
{
private volatile bool _isDownloading = false;
private bool IsDownloading { get { return this._isDownloading; } set { this._isDownloading = value; } }
public frmAutoScript()
{
InitializeComponent();
this.RunAutoSynchronization();
}
private void RunAutoSynchronization()
{
bool isDownloading = this.IsDownloading;
BackgroundWorker bgwDownloader = new BackgroundWorker();
bgwDownloader.WorkerReportsProgress = true;
bgwDownloader.ProgressChanged += (sndr, evnt) =>
{
if (evnt.ProgressPercentage == 2)
isDownloading = this.IsDownloading;
else
{
this.IsDownloading = evnt.ProgressPercentage == 1;
isDownloading = this.IsDownloading;
}
};
bgwDownloader.DoWork += (sndr, evnt) =>
{
while (true)
{
if (DateTime.Now.Hour == 16 &&
DateTime.Now.Minute == 0)
{
try
{
bgwDownloader.ReportProgress(2);
if (!isDownloading)
{
bgwDownloader.ReportProgress(1);
new Downloader().Download();
}
bgwDownloader.ReportProgress(0);
}
catch { }
}
System.Threading.Thread.Sleep(60000);
}
};
bgwDownloader.RunWorkerAsync();
}
}
And in that frmAutoScript, I also have a button named btnDownload that when clicked, it will download and change the value of the volatile varialbe _isDownloading. The event of the button is something like this:
private void btnDownload_Click(object sender, EventArgs e)
{
if (IsDownloading)
MessageBox.Show("A download is currently ongoing. Please wait for the download to finish.",
"Force Download", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
else
{
this.IsDownloading = true;
BackgroundWorker bgwDownloader = new BackgroundWorker();
bgwDownloader.DoWork += (sndr, evnt) =>
{
try
{
new Downloader().Download();
}
catch(Exception ex)
{
MessageBox.Show("An error occur during download. Please contact your system administrator.\n Exception: " +
ex.GetType().ToString() + "\nError Message:\n" + ex.Message + " Stack Trace:\n" + ex.StackTrace, "Download Error!", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
};
bgwDownloader.RunWorkerCompleted += (sndr, evnt) =>
{
this.IsDownloading = false;
};
bgwDownloader.RunWorkerAsync();
}
}
But when I click the button btnDownload and the _isDownloading is set to true, and when the system time hit the 4:00 PM, the new Downloader().Download(); is executed again eventhough the _isDownloading is set to true. Why was it like this?
My code is in C#, framework 4, project is in winforms, build in Visual Studio 2010 Pro.
Your code is not testing against the volatile field - it is testing against isDownloading, which looks like a "local", but (because it is captured) is in fact a regular (non-volatile) field. So: either use some kind of memory barrier, or force that to be a volatile read. Or more simply: get rid of isDownloading completely, and check against the property.
Incidentally, the cache-defeating properties of volatile are not the intent of the keyword, but rather: a consequence. It'll work, but personally I'd suggest writing the code to work by intent rather than by consequence, perhaps using either a simple lock or something like Interlocked.