I have a button made from a data controls 'CreateInsert' operation.
I have set a boolean in my code (initialized to false) and when the createInsert button is clicked, I want to check this boolean before executing it's operation.
However, in this button's ActionListener, is nothing related to the CreateInsert operation I need to stop if my boolean check returns true..
Now my question is, where is the real Action handling for the CreateInsert button/how can I control it (stop it from executing) in my code?
Thanks in advance!
create a managed bean to the create insert button(I hope u can do that).
now open the managed bean java class , it automatically contains create insert method somewhat like this :::
BindingContainer bindings = getBindings();
OperationBinding operationBinding = bindings.getOperationBinding("CreateInsert1");
Object result = operationBinding.execute();
if (!operationBinding.getErrors().isEmpty()) {
return null;
}
return null;
Related
first I must apologize because english isn't my mother language, but I'll try to be clear in what I'm asking.
I have a set of rows in a tableview, every row has diferent comboboxs per columns. So, the interaction between combobox must be per row. If in the Combobox A1, I select Item 1, in the Combobox A2 the itemlist will be updated.
My problem is that every combobox A2, B2, C2, etc. Is being updated according the choice in A1... same thing with B1,C1 combobox.
I need to updated just the A2, according to A1. B2 according to B1, etc.
I set the comboboxes by cellfactory, because I have to save the data from behind in a serializable object.
Hope is clear.
Regards.
This is pretty much a pain...
From a TableCell, you can observe the TableRow via it's tableRowProperty().
From the TableRow, you can observe the item in the row, via the table row's itemProperty().
And of course, from the item in the row, you can observe any properties defined in your model class, and update a list of items in the combo box accordingly.
The painful part is that any of these value can, and will at some point change. So the things you need to observe keep changing, and you have to manage adding and removing listeners as this happens.
The Bindings.select method is supposed to help manage things like this, but as of JavaFX 8, it prints huge stack traces to the output as warnings whenever it encounters a null value, which it does frequently. So I recommend doing you own listener management until that is fixed. (For some reason, the JavaFX team doesn't seem to consider this a big deal, even though encountering null values in the path defined in a Bindings.select is explicitly supported in the API docs.)
Just to make it slightly more unpleasant, the getTableRow() method in TableCell<S,T> returns a TableRow, instead of the more obvious TableRow<S>. (There may be a reason for this I can't see, but, well...). So your code is additionally littered with casts.
I created an example that works: apologies for it being based on US geography, but I had much of the example already written. I really hope I'm missing something and that there are easier ways to do this: please feel free to suggest something if anyone has better ideas.
On last note: the EasyBind library may provide a simpler way to bind to the properties along an arbitrary path.
As #James_D's example no longer runs due to link rot, and I was dealing with this same issue, here's how I figured out to create this effect.
View the full test case here.
I extend the builtin ComboBoxTableCell<S, T> to expose necessary fields. The custom TableCell has a Supplier<S> tableValue = (S) this.getTableRow().getItem(); used to access the applicable Data object. Additionally, I reflectively retrieve and store a reference to the cell's ComboBox. Because it is lazily instantiated in the superclass, I also have to set it via reflection before I can get it. Finally, I have to initialize the ComboBox as well, as it would be in javafx.scene.control.cell.CellUtils.createComboBox, since I'm manually creating it. It is important to expose these, as:
In the column's CellFactory, we finish initializing the ComboBoxCell. We just need to create a new instance of our custom ComboBoxTableCell and then when the comboBox is shown for the first time (e.g. we can be sure that we have a Data object associated with the cell), we bind the ComboBox#itemsProperty to a Bindings.When returning the proper ObservableList for the case.
CellFactory:
column1.setCellFactory(c -> {
TransparentComboBoxTableCell<Data, Enum> tcbtc = new TransparentComboBoxTableCell<>();
tcbtc.comboBox.setOnShown(e -> {
if (!tcbtc.comboBox.itemsProperty().isBound()) tcbtc.comboBox.itemsProperty().bind(
Bindings.when(tcbtc.tableValue.get().base.isEqualTo(BASE.EVEN)).then(evens).otherwise(
Bindings.when(tcbtc.tableValue.get().base.isEqualTo(BASE.ODD)).then(odds).otherwise(
FXCollections.emptyObservableList()
))
);
});
return tcbtc;
});
custom ComboBoxTableCell:
public static class TransparentComboBoxTableCell<S, T> extends ComboBoxTableCell<S, T> {
public TransparentComboBoxTableCell() {
this(FXCollections.observableArrayList());
}
public TransparentComboBoxTableCell(ObservableList<T> startingItems) {
super(startingItems);
try {
Field f = ComboBoxTableCell.class.getDeclaredField("comboBox");
f.setAccessible(true);
f.set(this, new ComboBox<>());
comboBox = (ComboBox<T>) f.get(this);
// Setup out of javafx.scene.control.cell.CellUtils.createComboBox
// comboBox.converterProperty().bind(converter);
comboBox.setMaxWidth(Double.MAX_VALUE);
comboBox.getSelectionModel().selectedItemProperty().addListener((ov, oldValue, newValue) -> {
if (this.isEditing()) {
this.commitEdit((T) newValue);
}
});
} catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException ex) {
Logger.getLogger(FXMLDocumentController.class.getName()).log(Level.SEVERE, null, ex);
throw new Error("Error extracting 'comboBox' from ComboBoxTableCell", ex);
}
tableValue = () -> (S) this.getTableRow().getItem();
}
public final ComboBox<T> comboBox;
public final Supplier<S> tableValue;
}
Is it ever a good idea to work directly with the context? For example, say I have a database of customers and a user can search them by name, display a list, choose one, then edit that customer's properties.
It seems I should use the context to get a list of customers (mapped to POCOs or CustomerViewModels) and then immediately close the context. Then, when the user selects one of the CustomerViewModels in the list the customer properties section of the UI populates.
Next they can change the name, type, website address, company size, etc. Upon hitting a save button, I then open a new context, use the ID from the CustomerViewModel to retrieve that customer record, and update each of its properties. Finally, I call SaveChanges() and close the context. This is a LOT OF WORK.
My question is why not just work directly with the context leaving it open throughout? I have read using the same context with a long lifetime scope is very bad and will inevitably cause problems. My assumption is if the application will only be used by ONE person I can leave the context open and do everything. However, if there will be many users, I want to maintain a concise unit of work and thus open and close the context on a per request basis.
Any suggestions? Thanks.
#PGallagher - Thanks for the thorough answer.
#Brice - your input is helpful as well
However, #Manos D. the 'epitome of redundant code' comment concerns me a bit. Let me go through an example. Lets say I'm storing customers in a database and one of my customer properties is CommunicationMethod.
[Flags]
public enum CommunicationMethod
{
None = 0,
Print = 1,
Email = 2,
Fax = 4
}
The UI for my manage customers page in WPF will contain three check boxes under the customer communication method (Print, Email, Fax). I can't bind each checkbox to that enum, it doesn't make sense. Also, what if the user clicked that customer, gets up and goes to lunch... the context sits there for hours which is bad. Instead, this is my thought process.
End user chooses a customer from the list. I new up a context, find that customer and return a CustomerViewModel, then the context is closed (I've left repositories out for simplicity here).
using(MyContext ctx = new MyContext())
{
CurrentCustomerVM = new CustomerViewModel(ctx.Customers.Find(customerId));
}
Now the user can check/uncheck the Print, Email, Fax buttons as they are bound to three bool properties in the CustomerViewModel, which also has a Save() method. Here goes.
public class CustomerViewModel : ViewModelBase
{
Customer _customer;
public CustomerViewModel(Customer customer)
{
_customer = customer;
}
public bool CommunicateViaEmail
{
get { return _customer.CommunicationMethod.HasFlag(CommunicationMethod.Email); }
set
{
if (value == _customer.CommunicationMethod.HasFlag(CommunicationMethod.Email)) return;
if (value)
_customer.CommunicationMethod |= CommunicationMethod.Email;
else
_customer.CommunicationMethod &= ~CommunicationMethod.Email;
}
}
public bool CommunicateViaFax
{
get { return _customer.CommunicationMethod.HasFlag(CommunicationMethod.Fax); }
set
{
if (value == _customer.CommunicationMethod.HasFlag(CommunicationMethod.Fax)) return;
if (value)
_customer.CommunicationMethod |= CommunicationMethod.Fax;
else
_customer.CommunicationMethod &= ~CommunicationMethod.Fax;
}
}
public bool CommunicateViaPrint
{
get { return _customer.CommunicateViaPrint.HasFlag(CommunicationMethod.Print); }
set
{
if (value == _customer.CommunicateViaPrint.HasFlag(CommunicationMethod.Print)) return;
if (value)
_customer.CommunicateViaPrint |= CommunicationMethod.Print;
else
_customer.CommunicateViaPrint &= ~CommunicationMethod.Print;
}
}
public void Save()
{
using (MyContext ctx = new MyContext())
{
var toUpdate = ctx.Customers.Find(_customer.Id);
toUpdate.CommunicateViaEmail = _customer.CommunicateViaEmail;
toUpdate.CommunicateViaFax = _customer.CommunicateViaFax;
toUpdate.CommunicateViaPrint = _customer.CommunicateViaPrint;
ctx.SaveChanges();
}
}
}
Do you see anything wrong with this?
It is OK to use a long-running context; you just need to be aware of the implications.
A context represents a unit of work. Whenever you call SaveChanges, all the pending changes to the entities being tracked will be saved to the database. Because of this, you'll need to scope each context to what makes sense. For example, if you have a tab to manage customers and another to manage products, you might use one context for each so that when a users clicks save on the customer tab, all of the changes they made to products are not also saved.
Having a lot of entities tracked by a context could also slow down DetectChanges. One way to mitigate this is by using change tracking proxies.
Since the time between loading an entity and saving that entity could be quite long, the chance of hitting an optimistic concurrency exception is greater than with short-lived contexts. These exceptions occur when an entity is changed externally between loading and saving it. Handling these exceptions is pretty straightforward, but it's still something to be aware of.
One cool thing you can do with long-lived contexts in WPF is bind to the DbSet.Local property (e.g. context.Customers.Local). this is an ObservableCollection that contains all of the tracked entities that are not marked for deletion.
Hopefully this gives you a bit more information to help you decide which approach to help.
Microsoft Reference:
http://msdn.microsoft.com/en-gb/library/cc853327.aspx
They say;
Limit the scope of the ObjectContext
In most cases, you should create
an ObjectContext instance within a using statement (Using…End Using in
Visual Basic).
This can increase performance by ensuring that the
resources associated with the object context are disposed
automatically when the code exits the statement block.
However, when
controls are bound to objects managed by the object context, the
ObjectContext instance should be maintained as long as the binding is
needed and disposed of manually.
For more information, see Managing Resources in Object Services (Entity Framework). http://msdn.microsoft.com/en-gb/library/bb896325.aspx
Which says;
In a long-running object context, you must ensure that the context is
disposed when it is no longer required.
StackOverflow Reference:
This StackOverflow question also has some useful answers...
Entity Framework Best Practices In Business Logic?
Where a few have suggested that you promote your context to a higher level and reference it from here, thus keeping only one single Context.
My ten pence worth:
Wrapping the Context in a Using Statement, allows the Garbage Collector to clean up the resources, and prevents memory leaks.
Obviously in simple apps, this isn't much of a problem, however, if you have multiple screens, all using alot of data, you could end up in trouble, unless you are certain to Dispose your Context correctly.
Hence I have employed a similar method to the one you have mentioned, where I've added an AddOrUpdate Method to each of my Repositories, where I pass in my New or Modified Entity, and Update or Add it depending upon whether it exists.
Updating Entity Properties:
Regarding updating properties however, I've used a simple function which uses reflection to copy all the properties from one Entity to Another;
Public Shared Function CopyProperties(Of sourceType As {Class, New}, targetType As {Class, New})(ByVal source As sourceType, ByVal target As targetType) As targetType
Dim sourceProperties() As PropertyInfo = source.GetType().GetProperties()
Dim targetProperties() As PropertyInfo = GetType(targetType).GetProperties()
For Each sourceProp As PropertyInfo In sourceProperties
For Each targetProp As PropertyInfo In targetProperties
If sourceProp.Name <> targetProp.Name Then Continue For
' Only try to set property when able to read the source and write the target
'
' *** Note: We are checking for Entity Types by Checking for the PropertyType to Start with either a Collection or a Member of the Context Namespace!
'
If sourceProp.CanRead And _
targetProp.CanWrite Then
' We want to leave System types alone
If sourceProp.PropertyType.FullName.StartsWith("System.Collections") Or (sourceProp.PropertyType.IsClass And _
sourceProp.PropertyType.FullName.StartsWith("System.Collections")) Or sourceProp.PropertyType.FullName.StartsWith("MyContextNameSpace.") Then
'
' Do Not Store
'
Else
Try
targetProp.SetValue(target, sourceProp.GetValue(source, Nothing), Nothing)
Catch ex As Exception
End Try
End If
End If
Exit For
Next
Next
Return target
End Function
Where I do something like;
dbColour = Classes.clsHelpers.CopyProperties(Of Colour, Colour)(RecordToSave, dbColour)
This reduces the amount of code I need to write for each Repository of course!
The context is not permanently connected to the database. It is essentially an in-memory cache of records you have loaded from disk. It will only request records from the database when you request a record it has not previously loaded, if you force it to refresh or when you're saving your changes back to disk.
Opening a context, grabbing a record, closing the context and then copying modified properties to an object from a brand new context is the epitomy of redundant code. You are supposed to leave the original context alone and use that to do SaveChanges().
If you're looking to deal with concurrency issues you should do a google search about "handling concurrency" for your version of entity framework.
As an example I have found this.
Edit in response to comment:
So from what I understand you need a subset of the columns of a record to be overridden with new values while the rest is unaffected? If so, yes, you'll need to manually update these few columns on a "new" object.
I was under the impression that you were talking about a form that reflects all the fields of the customer object and is meant to provide edit access to the entire customer record. In this case there's no point to using a new context and painstakingly copying all properties one by one, because the end result (all data overridden with form values regardless of age) will be the same.
When I want to confirm a form exit, I use a DialogMsg call with an if to set Action parameter to caNone (No) or caHide (yes).
When I use that approach with database table row posting, I get a problem.
If I make a Save button with a confirmation dialog, I could call Post or Cancel, but when I have a Database Grid in the form, the problem comes when the user alter a row and later, selects another row, witch saves the previous row automatically.
The solution I found was to put the save confirmation dialog inside the OnBeforePost, but if the uses says No, how should I cancel the Post command to Continue? I've tryed Cancel and Abort commands, but it continues saving the row.
You need to create your own descendant TMyQuery of the TXxxQuery (or what else dataset kind you are using). And in your class override Post method and add a new event, allowing to decide is the Post needed. Then register new component and replace TXxxQuery in your application with TMyQuery. And create the event handler.
For example, the TMyQuery:
interface
type
TMyAllowPostEvent = procedure (ASender: TDataSet; var AAllow: Boolean) of object;
TMyQuery = class (TXxxQuery)
private
FOnAllowPost: TMyAllowPostEvent;
public
procedure Post; override;
published
property OnAllowPost: TMyAllowPostEvent read FOnAllowPost write FOnAllowPost;
end;
implementation
procedure TMyQuery.Post;
var
lAllow: Boolean;
begin
lAllow := True;
if Assigned(OnAllowPost) then
OnAllowPost(Self, lAllow);
if lAllow then
inherited Post;
end;
And the example of the event handler:
procedure TForm1.MyQuery1AllowPost(ASender: TDataSet; var AAllow: Boolean);
begin
AAllow := MessageDlg('Would you like to save changes ?', mtConfirmation, mbYesNo, -1) = mrYes;
end;
I have decorated a property of a class with a CustomValidationAttribute to validate if a GUID value was set but when I try to force it to be executed by using the helper method Validator.TryValidateObject() it seems that it doesn't invoke my validation logic.
The validation logic is being triggered when the value of the decorated property has changed, but I need to handle the scenario wherein the user clicks the save button without filling up required fields, hence the need to force validation attributes to run before a call to DomainContext.SubmitChanges() is called.
Interestingly, even classes that inherit from ValidationAtrribute isn't being run by Validator.TryValidateObject().
What is the correct way to force validation attributes to be executed?
Custom validators applied at the property level will have to be validated separately by using TryValidateProperty.
e.g.
Validator.TryValidateProperty(ViewModel.MyProperty,
new ValidationContext(ViewModel.MyProperty, null, null)
{ MemberName = "MyProperty" }, results);
A more simplistic way of doing this is to set the last parameter (validateAllProperties) on TryValidateObject() to true. See the msdn article for more information.
List<ValidationResult> vr = new List<ValidationResult>();
ValidationContext vc = new ValidationContext(viewModel, null, null);
Validator.TryValidateObject(viewModel, vc, vr, true);
I have a grid bound to a BindingSource which is bound to DataContext table, like this:
myBindingSource.DataSource = myDataContext.MyTable;
myGrid.DataSource = myBindingSource;
I couldn't refresh BindingSource after insert. This didn't work:
myDataContext.Refresh(RefreshMode.OverwriteCurrentValues, myBindingSource);
myBindingSource.ResetBinding(false);
Neither this:
myDataContext.Refresh(RefreshMode.OverwriteCurrentValues, myDataContext.MyTable);
myBindingSource.ResetBinding(false);
What should I do?
I have solved the problem but not in a way I wanted.
Turns out that DataContext and Linq To SQL is best for unit-of-work operations. Means you create a DataContext, get your job done, discard it. If you need another operation, create another one.
For this problem only thing I had to do was recreate my DataContext like this.dx = new MyDataContext();. If you don't do this you always get stale/cached data. From what I've read from various blog/forum posts that DataContext is lightweight and doing this A-OK. This was the only way I've found after searching for a day.
And finally one more working solution.
This solution works fine and do not require recreating DataContext.
You need to reset internal Table cache.
for this you need change private property cachedList of Table using reflection.
You can use following utility code:
public static class LinqDataTableExtension
{
public static void ResetTableCache(this ITable table)
{
table.InternalSetNonPublicFieldValue("cachedList", null);
}
public static void ResetTableCache(this IListSource source)
{
source.InternalSetNonPublicFieldValue("cachedList", null);
}
public static void InternalSetNonPublicFieldValue(this object entity, string propertyName, object value)
{
if (entity == null)
throw new ArgumentNullException("entity");
if(string.IsNullOrEmpty(propertyName))
throw new ArgumentNullException("propertyName");
var type = entity.GetType();
var prop = type.GetField(propertyName, BindingFlags.NonPublic | BindingFlags.Instance);
if (prop != null)
prop.SetValue(entity, value);
// add any exception code here if property was not found :)
}
}
using something like:
var dSource = Db.GetTable(...)
dSource.ResetTableCache();
You need to reset your BindingSource using something like:
_BindingSource.DataSource = new List();
_BindingSource.DataSource = dSource;
// hack - refresh binding list
Enjoy :)
Grid Data Source Referesh by new query instead just Contest.Table.
Simple Solution < But Working.
Whre is eg.
!!!!! Thanks - Problem Solved after no of days !!! but with so simple way ..
CrmDemoContext.CrmDemoDataContext Context = new CrmDemoContext.CrmDemoDataContext();
var query = from it in Context.Companies select it;
// initial connection
dataGridView1.DataSource = query;
after changes or add in data
Context.SubmitChanges();
//call here again
dataGridView1.DataSource = query;
I have the same problem. I was using a form to create rows in my table without saving the context each time. Luckily I had multiple forms doing this and one updated the grid properly and one didn't.
The only difference?
I bound one to the entity similarly (not using the bindingSource) to what you did:
myGrid.DataSource = myDataContext.MyTable;
The second I bound:
myGrid.DataSource = myDataContext.MyTable.ToList();
The second way worked.
I think you should also refresh/update datagrid. You need to force redraw of grid.
Not sure how you insert rows. I had same problem when used DataContext.InsertOnSubmit(row), but when I just inserted rows into BindingSource instead BindingSource.Insert(Bindingsource.Count, row)
and used DataContext only to DataContext.SubmitChanges() and DataContext.GetChangeSet(). BindingSource inserts rows into both grid and context.
the answer from Atomosk helped me to solve a similar problem -
thanks a lot Atomosk!
I updated my database by the following two lines of code, but the DataGridView did not show the changes (it did not add a new row):
this.dataContext.MyTable.InsertOnSubmit(newDataset);
this.dataContext.SubmitChanges();
Where this.dataContext.MyTable was set to the DataSource property of a BindingSource object, which was set to the DataSource property of a DataGridView object.
In code it does looks like this:
DataGridView dgv = new DataGridView();
BindingSource bs = new BindingSource();
bs.DataSource = this.dataContext.MyTable; // Table<T> object type
dgv.DataSource = bs;
Setting bs.DataSource equals null and after that back to this.dataContext.MyTable did not help to update the DataGridView either.
The only way to update the DataGridView with the new entry was a complete different approach by adding it to the BindingSource instead of the corresponding table of the DataContext, as Atomosk mentioned.
this.bs.Add(newDataset);
this.dataContext.SubmitChanges();
Without doing so bs.Count; returned a smaller number as this.dataContext.MyTable.Count();
This does not make sense and seems to be a bug in the binding model in my opinion.