|
Hello everyone, back to coding after a long absence so excuse my rustiness
When doing database apps ibe allways done the wrong thing & validated user input on the form, via simple checks against the controls .text property. Now i want to do it the right way, and concentrate all validation closer to the data side of things, in this case the data tables.
So i decided to do it via the RowChanging event:
On my table...
public override void EndInit()
{
base.EndInit();
customersRowChanging += customersRowChangeEvent;
}
public void customersRowChangeEvent(object sender, customersRowChangeEvent e)
{
if (e.Row.Name.Length == 0)
{
e.Row.SetColumnError("name", "Customer name cannot be empty");
}
else
{
e.Row.SetColumnError("name", "");
}
}
On my app, in a form the textboxes & other input are bound to a BindingSource, wich in turn is bound to the datatable in the dataset (100% as per visual studio designer).
To add a record,
I call the BindingSource.AddNew(), and allow the user to enter the data and then on my handler for the "Save" button...
try
{
Validate();
customersBindingSource.EndEdit();
customersTableAdapter.Update(samDataSet.customers);
}
catch(Exception ex)
{
}
Even without handling the rowChange event, This works when a datatable or database constraint is violated, e.g. if the name is NULL or not unique (as specified in the data table constraints), an exception occurs, and the record is not saved.
However, Even with the RowChangeEvent implemented as above, if a record with an empty (not null, empty string) name is in the record, no exception is thrown, the datatable gladly accepts the new record, and the table adapter saves it (the MySQL database does not enforce empty string values).
Ibe checked, and the handler does get called, and the call to SetColumnError is made, but it doesnt prevent the table from accepting the new row.
I read to use this method from here: Validate data in datasets[^]
And i was under the impression that when i call SetColumnError() with a non empty string for error, the table would not accept the new row. Evidently i got it wrong.
Ibe also tried throwing an exception myself if the data fails the validation requirements, like this:
public void customersRowChangeEvent(object sender, customersRowChangeEvent e)
{
if (e.Row.Name.Length == 0)
{
e.Row.SetColumnError("name", "Customer name cannot be empty");
throw new System.Exception("Customer Name cannot be empty");
}
else
{
e.Row.SetColumnError("name", "");
}
}
But the Binding source does not catch & (re) throw the exception to my own code when it tries to commit the new record, because i end up with an unhandled exception.
Of course there are 101 ways i could enforce data validation on the form, or creating specific bool ValidateThis(DataRow theData) methods, but i would depend on calling such methods every time, and i would prefeer the tables to enforce their own rules automatically.
Can anyone see why its not working?
If calling the SetColumnError doesnt prevent the table from accepting the row, then whats the point of calling it to set errors?
Maybe im doing it the wrong way?
Any input much appreciated!
modified 9-Nov-17 0:27am.
|
|
|
|
|
I've never had input-validation on a DataTable ; usually there is a (generated) validation in the UI, and another one in the database itself. Yes, they partially overlap.
If your DataTable HasErrors , you could try to RejectChanges[^].
Bastard Programmer from Hell
If you can't read my code, try converting it here[^]
|
|
|
|
|
Thanks for the reply Eddy.
I just found out whats wrong...
This:
public void customersRowChangeEvent(object sender, customersRowChangeEvent e)
{
if (e.Row.Name.Length == 0)
{
e.Row.SetColumnError("name", "Customer name cannot be empty");
throw new System.Exception("Customer Name cannot be empty");
}
else
{
e.Row.SetColumnError("name", "");
}
}
Does work as intended. The unhandled exception i was getting was a First chance exception. If i hit continue and let the code continue to run, it does get handled properly on my own try / catch statements on the Save button handler i posted above.
Now i feel embarassed. i guess im rustier than i tought i was. I completely forgot about first chance exceptions and how the debuger handles them.
|
|
|
|
|
Hehe, I recognize those days
Bastard Programmer from Hell
If you can't read my code, try converting it here[^]
|
|
|
|
|
I would like to use the circle progress bar in my form application
but it is nothing on my tool box.
could you help me where I can get this add on?
|
|
|
|
|
In less time than you spent typing the question in here, you could have performed the following Google search[^]. Being able to do your own research is one of the most valuable abilities you can develop as a programmer. I suggest that you take the time to learn it.
This space for rent
|
|
|
|
|
The bigger question is: What posseses you to use VS2008 when you could be using any one of 4 or 5 more recent versions?
Maybe you should just use a stick and some string.
"(I) am amazed to see myself here rather than there ... now rather than then".
― Blaise Pascal
|
|
|
|
|
Done
I create some class in user control
Thanks for your concern Brother.
|
|
|
|
|
Hi everybody,
I'm trying to figure out how to call windows camera UI from a windows form.
I did this and it does compile:
Public Function ShootPicture() As StorageFile
Dim captureUI As New CameraCaptureUI
captureUI.PhotoSettings.Format = CameraCaptureUIPhotoFormat.Jpeg
captureUI.PhotoSettings.AllowCropping = False
Dim GetPhotoTask As Task(Of StorageFile) = captureUI.CaptureFileAsync(CameraCaptureUIMode.Photo)
GetPhotoTask.Wait()
Dim result As StorageFile = GetPhotoTask.Result
Return result
End Function
But there is a 'System.InvalidCastException' execution error on .capturefileAsync() : type 'System._ComObject' cannot be casted as 'System.threading.tasks.task'
The idea of wait instead of await was to make the function Synchronous because I would rather to call it from a Protected Overrides Function. However I tried with the classic Async declaration and I don't have a better result (does not compile).
Dim GetPhotoTask As Task(Of StorageFile) = captureUI.CaptureFileAsync(CameraCaptureUIMode.Photo)
Dim Photo As StorageFile = Await GetPhotoTask
Would anyone have any idea on how to fix this? Thanks
If it can help here is the c# code translation:
public StorageFile ShootPicture()
{
CameraCaptureUI captureUI = new CameraCaptureUI();
captureUI.PhotoSettings.Format = CameraCaptureUIPhotoFormat.Jpeg;
captureUI.PhotoSettings.AllowCropping = false;
Task<StorageFile> GetPhotoTask = captureUI.CaptureFileAsync(CameraCaptureUIMode.Photo);
GetPhotoTask.Wait();
StorageFile result = GetPhotoTask.Result;
return result;
}
|
|
|
|
|
The message is perfectly clear, you cannot cast the returned type to something completely different.
|
|
|
|
|
|
Thanks Richard it seems to be the right solution.
I managed to add WindowsRuntimeSystemExtensions to the project following these instructions: [^]
And I imported it to the module with:
Imports System.WindowsRuntimeSystemExtensions
But IAsyncOperation still don't have
.AsTask()
Any idea?
|
|
|
|
|
Hi,
I've finally manage to compile and execute the code as suggested:
Private Async Sub MassPointImageBox_Click(sender As Object, e As EventArgs) Handles MassPointImageBox.Click
MsgBox("Take a Picture")
Dim capture = New CameraCaptureUI()
capture.PhotoSettings.Format = CameraCaptureUIPhotoFormat.Jpeg
capture.PhotoSettings.MaxResolution = CameraCaptureUIMaxPhotoResolution.HighestAvailable
Dim GetPhotoTask As Task(Of StorageFile) = capture.CaptureFileAsync(CameraCaptureUIMode.Photo).AsTask
Dim Photo As StorageFile = Await GetPhotoTask
If Photo Is Nothing Then
MsgBox("No picture taken")
Else
MsgBox(Photo.Path)
End If
End Sub
However, the camera app does not open, and photo is always nothing. AnyOne ever had this kind of issue with .CaptureFileAsync ?
Thanks
|
|
|
|
|
I am trying to let a user type in a textbox and process input as the typing occurs - but also want to make sure that the last characters typed (when the user finished typing) are processed - I want to have only 1 processing task running at any time - so I would probably need something like the below with an async semaphore, right?
Does someone have a hint towards the correct code snippet?
MainWindow XAML:
<Window x:Class="InputTaskQueue.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:behav="clr-namespace:InputTaskQueue.Behaviors"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<StackPanel Orientation="Vertical">
<TextBox Name="tbInput"
behav:TextChangedCommand.ChangedCommand="{Binding SearchCommand}"
HorizontalAlignment="Left" VerticalAlignment="Bottom"
Width="100" Height="20"/>
<TextBlock Text="{Binding SearchStringResult,UpdateSourceTrigger=PropertyChanged,Mode=OneWay}" Width="100" Height="100" />
</StackPanel>
</Window>
Text KeyUp Behavior Triggera command via binding:
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
public static class TextChangedCommand
{
private static readonly DependencyProperty ChangedCommandProperty = DependencyProperty.RegisterAttached(
"ChangedCommand",
typeof(ICommand),
typeof(TextChangedCommand),
new PropertyMetadata(null, OnTextChangedCommandChange));
public static void SetChangedCommand(DependencyObject source, ICommand value)
{
source.SetValue(ChangedCommandProperty, value);
}
public static ICommand GetChangedCommand(DependencyObject source)
{
return (ICommand)source.GetValue(ChangedCommandProperty);
}
private static void OnTextChangedCommandChange(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
TextBox uiElement = d as TextBox;
if (uiElement != null)
{
uiElement.TextChanged -= OnText_Changed;
var command = e.NewValue as ICommand;
if (command != null)
{
uiElement.TextChanged += OnText_Changed;
}
}
}
private static void OnText_Changed(object sender, TextChangedEventArgs e)
{
TextBox uiElement = sender as TextBox;
if (uiElement == null)
return;
if (uiElement.IsEnabled == false)
return;
ICommand changedCommand = TextChangedCommand.GetChangedCommand(uiElement);
if (changedCommand == null)
return;
var item = uiElement.Text;
if (changedCommand is RoutedCommand)
{
(changedCommand as RoutedCommand).Execute(item, uiElement);
}
else
{
changedCommand.Execute(item);
}
}
}
ViewModel bond to MainWindow:
private string _SearchStrinResult;
public string SearchStringResult
{
get { return _SearchStrinResult; }
private set
{
if (_SearchStrinResult != value)
{
_SearchStrinResult = value;
NotifyPropertyChanged(() => SearchStringResult);
}
}
}
#endregion properties
#region methods
public ICommand SearchCommand
{
get
{
if (_SearchCommand == null)
{
_SearchCommand = new RelayCommand<object>((p) =>
{
string findThis = p as string;
if (string.IsNullOrEmpty(findThis) == true)
return;
SearchCommand_ExecutedAsync(findThis);
},
(p =>
{
return true;
})
);
}
return _SearchCommand;
}
}
private List<string> _Queue = new List<string>();
private static SemaphoreSlim SlowStuffSemaphore = new SemaphoreSlim(1, 1);
private async void SearchCommand_ExecutedAsync(string input)
{
_Queue.Add(input);
await SlowStuffSemaphore.WaitAsync();
try
{
if (_Queue.Count > 1)
{
_Queue.Remove(input);
return;
}
else
{
Console.WriteLine("Queue Count: {0}", _Queue.Count);
}
await createTask(input);
_Queue.Remove(input);
this.SearchStringResult = input;
}
catch (Exception exp)
{
Console.WriteLine(exp.Message);
}
finally
{
SlowStuffSemaphore.Release();
}
}
private Task createTask(string input)
{
return Task.Run(() =>
{
Console.WriteLine("searching:" + input);
System.Threading.Thread.Sleep(5000);
})
.ContinueWith((p) =>
{
});
}
modified 13-Oct-17 16:45pm.
|
|
|
|
|
The easier way is for the user to finish typing, and not run a new thread until he/she finished editing. I don't see any data being presented to the user during processing, so in effect it would be the same as simply waiting for the focus-change and start processing then.
Bastard Programmer from Hell
If you can't read my code, try converting it here[^]
|
|
|
|
|
The statement System.Threading.Thread.Sleep(5000); is a mockup for the background processing - it might in reality be 1 second or half a econd long but should definetly be done while typing not after - I know it would be easier otherwise - but anyone can do easy
|
|
|
|
|
Then no, a semophore is not enough; you're focussing on just having one thread - you should be focussing on returning (partially processed) variables. Cancelling a running thread (see backgroundworker for ideas) is not hard.
Bastard Programmer from Hell
If you can't read my code, try converting it here[^]
|
|
|
|
|
I am not sure what you mean - did you see the Task.Run(() statement?
Could you be more ,specific about what would be enough. Is there an open source example where something like this is implemented somewhere?
|
|
|
|
|
Dirk Bahle wrote: I am not sure what you mean - did you see the Task.Run(() statement? Yup. It is running a task, but I don't see it returning any values to present to the user. That's what you're trying to achieve; run a task, show the results to the user, and rerun with new data if the user changes the input.
Dirk Bahle wrote: Could you be more ,specific about what would be enough. You already have a single task that is run on the correct moment, as you say. So all that would be lacking is the actual presentation of the results "so far", and a mechanism to cancel the previous workload.
Bastard Programmer from Hell
If you can't read my code, try converting it here[^]
|
|
|
|
|
I push keyboard characters onto a "Stack" (which is what you are using your "queue" for).
If my "stack worker" isn't running, it gets started; and does incremental searching over the internet; returning results to a listbox.
If the stack is empty, the worker stops. It simply gets started again when another character is pushed and it is not running. No semaphor or waiting.
(And I only use a few lines of "code-behind" for what amounts to "plumbing"; not a lot of "indirection").
"(I) am amazed to see myself here rather than there ... now rather than then".
― Blaise Pascal
|
|
|
|
|
OK, you use a pull pattern from the worker thread - thats another good concept - but if you use no synchronization (via semaphores) between your threads then an unlucky timimg (even if unlikely) could still produce hard to debug results - I think this is part of the reason why Rx got introduced (see other comment in this discussion)
- I'll have a look at the Rx sample projects and maybe you should too - but thanks for the suggestion - I realy appreciate a discussion like this because it opens up your mind to the host of possibilities
|
|
|
|
|
This type of thing is generally accomplished, in the world of XAML apps, using RX. Search for RX autocomplete samples to get an understanding of how to structure it.
This space for rent
|
|
|
|
|
|
Hi,
I am getting the error :
An unhandled exception of type 'System.AccessViolationException' occurred in System.Data.dll
Additional information: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
when I am trying to read excel file in my Console Application, I am also researching and googling but not finding the appropriate answer that can fix. The error is happening at conn.Open() call, is it related to opening file, then is there any way I can just open the file in read mode and read the values from it because all I need is to read the file and output/write those values into PipeDelimited CSV file.
Here is the code that I have:
public static string ConvertXlsAndXlstToPipeDelimitedFile(string strSourceFilePath, bool isFirstRowColumnHeader, string sheetName)
{
string strConn = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" +
strSourceFilePath + ";Extended Properties=\"Excel 8.0;HDR=Yes;IMEX=1\"";
OleDbConnection conn = null;
StreamWriter wrtr = null;
OleDbCommand cmd = null;
OleDbDataAdapter da = null;
string destinationFilePath = string.Empty;
conn = new OleDbConnection(strConn);
try
{
if (conn.State != ConnectionState.Open)
{
conn.Open();
}
cmd = new OleDbCommand("SELECT * FROM [" + sheetName + "$]", conn); //"Sheet1"
cmd.CommandType = CommandType.Text;
da = new OleDbDataAdapter(cmd);
DataTable dt = new DataTable();
da.Fill(dt);
string strDirectory = (System.IO.Path.GetDirectoryName(strSourceFilePath));
if (!System.IO.Directory.Exists(strDirectory))
{
System.IO.Directory.CreateDirectory(strDirectory);
}
Path.GetFileNameWithoutExtension(strSourceFilePath);
destinationFilePath = (strDirectory + (@"\" + (Path.GetFileNameWithoutExtension(strSourceFilePath) + ".csv")));
wrtr = new StreamWriter(destinationFilePath);
int ColCount = 0; string rowString = "";
for (int y = 0; y < dt.Columns.Count; y++)
{
rowString += dt.Columns[y].ColumnName + "|";
}
wrtr.WriteLine(rowString);
for (int x = 0; x < dt.Rows.Count; x++)
{
rowString = "";
for (int y = 0; y < dt.Columns.Count; y++)
{
rowString += "\"" + dt.Rows[x][y].ToString() + "\"|";
}
wrtr.WriteLine(rowString);
}
if (File.Exists(destinationFilePath))
return destinationFilePath;
}
catch (Exception ex)
{
throw ex;
}
finally
{
if (conn != null)
{
if (conn.State != ConnectionState.Closed)
{
conn.Close();
}
conn.Dispose();
}
if (cmd != null)
{
cmd.Dispose();
}
if (da != null)
{
da.Dispose();
}
if (wrtr != null)
{
wrtr.Close();
wrtr.Dispose();
}
}
//MessageBox.Show("Done");
return string.Empty;
}
Can anybody please help me why am I getting that error and is there any fix for it? - Thanks in advance.
Thanks,
Abdul Aleem
"There is already enough hatred in the world lets spread love, compassion and affection."
|
|
|
|
|
This is just like a NullPointerException, but it gets caught by a system library. You need to use your debugger to find the point in your code that leads to the error and see which parameter or variable contains an invalid address.
|
|
|
|