How am I supposed to work with Collections for 1 column? I have tried:
private ObservableList<EmailU> emails= FXCollections.observableList(new ArrayList<EmailU>());
public ObservableList<EmailU> emailsProperty() {
return emails;
}
and then
col_email.setCellValueFactory(
new PropertyValueFactory<Client, ObservableList<EmailU>>("emails"));
col_email.setCellFactory(new MultilineTextFieldCellFactory());
but get the following error:
SEVERE: javafx.scene.control.Control loadSkinClass Failed to load skin 'StringProperty [bean: TableRow[id=null, styleClass=cell indexed-cell table-row-cell], name: skinClassName, value: com.sun.javafx.scene.control.skin.TableRowSkin]' for control TableRow[id=null, styleClass=cell indexed-cell table-row-cell]
java.lang.RuntimeException: java.lang.ClassCastException: com.sun.javafx.collections.ObservableListWrapper cannot be cast to javafx.beans.property.ReadOnlyProperty*
Any ideas?
FooProperty method should return property in terms of javafx.beans.property.Property. These properties are capable of notifying other entities about their changes which is vital for binding and TableView work. In your case it would be ListProperty:
private ListProperty<EmailU> emails = new SimpleListProperty<>(
FXCollections.observableList(new ArrayList<EmailU>()));
public ListProperty<EmailU> emailsProperty() {
return emails;
}
public ObservableList<EmailU> getEmails() {
return emailsProperty().get();
}
public void setEmails(ObservableList<EmailU> emails) {
emailsProperty().set(emails);
}
Note you need to provide getter and setter for correct work of TableView.
Related
I have a Trade class which contains a property currentPrice, which downloads price data from a website using getPricedata() method. The Trade object will show up as a table row in TableView. Now, my task: is to
use the getPricedata() method to grab data from internet, populate the currentPrice cell, whenever the object is created.
relaunch the getPricedata() method to every 1 minute after the object has been created and update table cell.
Below is the basic structure of my code. But I have no idea how to implement this ?
Which package do I need ? Task ? Service ? ScheduledService ?
public class Trade{
private DoubleProperty currentPrice;
// need thread here
public double getPricedata(){
.......
}
}
Use a ScheduledService<Number>, whose Task<Number>'s call() method retrieves and returns the value. Then you can either register an onSucceeded handler with the service, or just bind the Trade's currentPrice to service.lastValue(). Call setPeriod(..) on the service (once) to configure it to run every minute.
Since the currentPrice is being set from the service, you should only expose a ReadOnlyDoubleProperty from your Trade class (otherwise you might try to call currentPriceProperty().set(...) or setCurrentPrice(...), which would fail as it's bound).
I would do something like
public class Trade {
private final ReadOnlyDoubleWrapper currentPrice ;
private final ScheduledService<Number> priceService = new ScheduledService<Number>() {
#Override
public Task<Number> createTask() {
return new Task<Number>() {
#Override
public Number call() {
return getPriceData();
}
};
}
};
public Trade() {
priceService.setPeriod(Duration.minutes(1));
// in case of errors running service:
priceService.setOnFailed(e -> priceService.getException().printStackTrace());
currentPrice = new ReadOnlyDoubleWrapper(0);
currentPrice.bind(priceService.lastValueProperty());
startMonitoring();
}
public final void startMonitoring() {
priceService.restart();
}
public final void stopMonitoring() {
priceService.cancel();
}
public ReadOnlyDoubleProperty currentPriceProperty() {
return currentPrice.getReadOnlyProperty();
}
public final double getCurrentPrice() {
return currentPriceProperty().get();
}
private double getPriceData() {
// do actual retrieval work here...
}
}
(Code just typed in here without testing, but it should give you the idea.)
I am trying to create a Waveform Control Panel to change the properties of its components. I attempted to apply the example in the Redhawk documentation for a Component Control Panel, but for some reason I get a java.lang.NullPointerException when running the plugin. The error occurs when I attempt to bind the text field to a component property, the exact line where the error occurred is in the comments of the code (at the very bottom).
public class TestControlPanel extends AbstractScaContentEditor<ScaWaveform> {
private ScaWaveform waveform;
private ScaComponent myComponent;
private Text propertyValueField;
private EMFDataBindingContext context;
/**
* {#inheritDoc}
*/
#Override
public void createPartControl(final Composite main) {
main.setLayout(new GridLayout(2, false));
Group controlGroup = new Group(main, SWT.SHADOW_ETCHED_OUT);
controlGroup.setLayoutData(GridDataFactory.fillDefaults().grab(true, true).create());
controlGroup.setText("Controls");
createControlGroup(controlGroup);
}
private void createControlGroup(Composite parent) {
parent.setLayout(new GridLayout(2, false));
EObject input = getInput();
if (input instanceof ScaWaveform) {
// make local copy of waveform
waveform = (ScaWaveform) input;
try {
waveform.refresh(null, RefreshDepth.FULL);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
label = new Label(parent,SWT.None);
label.setText("Property Value:");
propertyValueField = new Text(parent, SWT.BORDER | SWT.FILL);
myComponent = waveform.getScaComponent("myComponent_1");
if(myComponent != null)
{
IObservableValue observable = SCAObservables.observeSimpleProperty(myComponent, "propertyId");
IObservableValue targetObservable = WidgetProperties.text(SWT.Modify).observeDelayed(5000,propertyValueField);
if(observable != null && targetObservable != null)
{
// ***** THE BELOW LINE CAUSES A java.lang.NullPointerException ERROR *****
context.bindValue(targetObservable, observable);
// ***** THE ABOVE LINE CAUSES A java.lang.NullPointerException ERROR *****
}
}
}
}
My original guess for the reason for this error was that one of the IObservableValue variables (e.g. targetObservable or observable) was null, which is why I check to make sure the values are not null before binding them. However, this didn't fix the problem and I still got the same error.
From what code I can see it seems as though your field varible "context" was never initialized.
Simply call the no argument constructor:
context = new EMFDataBindingContext();
It appears that the context variable is null. I see that you define "context" at the top of the class, but I didn't see where it has been set.
Below is a sample implementation that uses metro API and data binding (using MVVM) to populate list of folders in a drop down list.
The View model‘s constructor uses SetFolders method (private async), which calls an awaitable method fileService.GetFoldersAsync() to get list of folders. The folders list is then gets assigned to the property called “FoldersList”. XAML uses this property to populate a drop down list using the data binding.
I wonder is there a better way to set the FoldersList property without having to set it in the constructor as below. I would prefer to call the GetFilesAsync method and set the FilesList property value, when the actual data binding occurs (not during the class init). Since the properties do not support async/await modifiers (as far as I know) I’m struggling to implement a proper solution. Any ideas greatly appreciated.
The code is below.
ViewModel
public class FileViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private readonly IFileService fileService;
public FileDataViewModel(IFileService fileService)
{
this.fileService = fileService;
SetFolders();
}
private async void SetFolders ()
{
FoldersList = await fileService.GetFoldersAsync();
}
private IEnumerable< IStorageFolder > foldersList;
public IEnumerable<StorageFolder> FoldersList
{
get { return foldersList; }
private set
{
foldersList = value;
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs("FoldersList"));
}
}
}
}
IFileService and implementation
public interface IFileService {
Task<IEnumerable<IStorageFolder>> GetFilesAsync();
}
public class FileService : IFileService
{
public async Task<IEnumerable<IStorageFolder>> GetFoldersAsync()
{
var folder = KnownFolders.DocumentsLibrary;
return await folder.GetFoldersAsync();
}
}
I would implement it as a lazy property and use ObservableCollection<T> rather than IEnumerable<T>. We are doing it in several projects and it works well. This way you can guarantee that you are loading data only when needed. Furthermore, if you need to prefetch it, you can always call the load method in the constructor or elsewhere.
As a side note, I personnaly wouldn't expose IStorageFolder directly from my ViewModels.
private async Task LoadData()
{
if(!IsLoading)
{
IsLoading = true;
Folders = new ObservableCollection<Folder>(await fileService.GetFolderAsync());
}
IsLoading = false;
}
private ObservableCollection<Folder> _folders;
public ObservableCollection<Folder> Folders
{
get
{
if(_folders == null)
{
LoadData();//Don't await...
}
return _folders;
}
private set
{
SetProperty(ref _folders,value);
}
}
private bool _isLoading;
public bool IsLoading
{
get
{
return _isLoading;
}
private set
{
SetProperty(ref _isLoading,value);
}
}
Note that you can use the IsLoading property to display a progress ring for instance. after that the observable collection is loaded, you will be able to refresh it without recreating it. (_folders.Add, _folders.Remove, _folders.Clear...)
I am using the Unit of Work and Generic Repository pattern. Here is the statement that checks for a duplicate entry:
int id = int.Parse(beer.id); //id comes from the item we're hoping to insert
if (_unitOfWork.BeerRepository.GetByID(id) == null)
\\create a new model br
_unitOfWork.BeerRepository.Insert(br);
_unitOfWork.save();
Apparently this is failing to check to see if the beer is already in the database because I get this inner exception:
Violation of PRIMARY KEY constraint 'PK_Beers_3214EC2703317E3D'.
Cannot insert duplicate key in object 'dbo.Beers'.\r\nThe statement
has been terminated.
I also get this message:
An error occurred while saving entities that do not expose foreign
key properties for their relationships. The EntityEntries property
will return null because a single entity cannot be identified as the
source of the exception. Handling of exceptions while saving can be
made easier by exposing foreign key properties in your entity types.
See the InnerException for details.
The UnitOfWork class has my BeerRecommenderContext which implements DbContext and the UnitOfWork has a generic repository for each entity:
namespace BeerRecommender.Models
{
public class GenericRepository<TEntity> where TEntity : class
{
internal BeerRecommenderContext context;
internal DbSet<TEntity> dbSet;
public GenericRepository(BeerRecommenderContext context)
{
this.context = context;
this.dbSet = context.Set<TEntity>();
}
public virtual IEnumerable<TEntity> Get(
Expression<Func<TEntity, bool>> filter = null,
Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null,
string includeProperties = "")
{
IQueryable<TEntity> query = dbSet;
if (filter != null)
{
query = query.Where(filter);
}
foreach (var includeProperty in includeProperties.Split
(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
{
query = query.Include(includeProperty);
}
if (orderBy != null)
{
return orderBy(query).ToList();
}
else
{
return query.ToList();
}
}
public virtual TEntity GetByID(object id)
{
return dbSet.Find(id);
}
public virtual void Insert(TEntity entity)
{
dbSet.Add(entity);
}
public virtual void Delete(object id)
{
TEntity entityToDelete = dbSet.Find(id);
Delete(entityToDelete);
}
public virtual void Delete(TEntity entityToDelete)
{
if (context.Entry(entityToDelete).State == EntityState.Detached)
{
dbSet.Attach(entityToDelete);
}
dbSet.Remove(entityToDelete);
}
public virtual void Update(TEntity entityToUpdate)
{
dbSet.Attach(entityToUpdate);
context.Entry(entityToUpdate).State = EntityState.Modified;
}
}
}
I have a similar usage of repository using code-first. Occasionally, I would see conflicts like the one you described. My issue was with change tracking across multiple processes. Are you inserting items into the database inside one process (using a single entity context)?
If you are, you should look at the Merge Options available with Entity Framework. If you are using the default merge option (AppendOnly), then you could be querying the in memory context instead of going to the database. This could cause the behaviour you are describing.
Unfortunately, as far as I understand, all the merge options are not yet exposed to Code-First. You can choose the default (AppendOnly) or NoTracking, which will go to the database every time.
Hope this helps,
Davin
I have a service that needs to invoke a runnable class.
Here are the lines of code that are being used in my service.
#Autowired
private LinkBrc2MemberProfile brcTask;
// Background Task.
SimpleAsyncTaskExecutor sate = new SimpleAsyncTaskExecutor();
sate.createThread(new LinkBrc2MemberProfile(user));
Here is my Runnable class
#Service
public class LinkBrc2MemberProfile implements Runnable {
private final Logger log = LoggerFactory.getLogger(LinkBrc2MemberProfile.class);
#Autowired
private LoyaltyDao dao;
private Member member;
public LinkBrc2MemberProfile() {
super();
}
public LinkBrc2MemberProfile(Member member) {
this.member = member;
}
public void run() {
log.debug("*** Member User Name: " + member.getString("USER_NAME"));
String emailAddress = member.getString("USER_NAME");
Map<String, Object> map = dao.findBrcByEmailAddress( emailAddress );
log.debug("==========================================================");
if( ! map.isEmpty() ) {
try {
//a.CUSTOMER_ID, a.EMAIL_ADDRESS, b.card_no
String customerId = (String) map.get("CUSTOMER_ID");
String brcCardNumber = (String) map.get("CARD_NO");
log.debug("\ncustomerId: " + customerId + " brcCardNumber: " + brcCardNumber);
if(!brcCardNumber.equals("")) {
// Add the Be Rewarded Card.
HashMap<String, String> userAttributes = new HashMap<String, String>();
String brcNumber = member.getString("BREWARDED_CARD_NO");
if (brcNumber.equals("")) {
userAttributes.put("BREWARDED_CARD_NO", brcCardNumber);
try {
member.putAll(userAttributes);
} catch (Exception e) {
String errorMessage = "Unable to save user's BRC information due to: " + e.getMessage();
log.error("{}", errorMessage);
}
}
}
} catch (Exception e) {
log.error(e.getMessage());
e.printStackTrace();
}
}
}
I'm not seeing any errors in the log but at the same time it does not appear to be invoking the Runnable class. Am I missing an annotation somewhere? Are there any good examples that you can point me to, the only ones I have found use XML files to configure the runnable class I would like to use annotations. Thanks in Advance.
I've updated my service to do the following.
Please help, my DAO is NULL so it looks like my #Autowired in my Runnable class is not wiring it in.
I've added the following bean to my bean-config.xml file.
<bean id="brcType" class="com.ws.ocp.service.LinkBrc2MemberProfile" scope="prototype"/>
I removed my #Autowired annotation and added the following to my service class.
ClassPathResource rsrc = new ClassPathResource("bean-config.xml");
XmlBeanFactory factory = new XmlBeanFactory(rsrc);
LinkBrc2MemberProfile brcTask = (LinkBrc2MemberProfile) factory.getBean("brcType");
SimpleAsyncTaskExecutor sate = new SimpleAsyncTaskExecutor();
// Set Member attribute
brcTask.setMember(user);
// Executer
sate.execute(brcTask);
Why is my dao still null?
The runnable will throw a NullPointerException, since you create it yourself (using the new operator), instead of letting Spring create it. This obviously means that the autowired DAO attribute won't be autowired, which will lead to a NPE when calling dao.findBrcByEmailAddress(...).
You should get your Runnable instance from the bean factory (as a prototype), set its member attribute, and then submit it to the executor.
To answer your question of how to properly use a Prototype-Bean, this is my favorite way:
#Component
abstract class MyBean {
/* Factory method that will be installed by Spring */
#Lookup
protected abstract YourPrototypeBean createBean();
void someCode() {
YourPrototypeBean bean = createBean();
}
}
Since it's a factory method, you can create as many instances as you like.