I'm having an object in my viewmodel which consists of an Id and some other attributes.
my equality check contains the check on Id, so I can identify items in lists when refreshing.
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != GetType()) return false;
return Equals(obj as Class);
}
public bool Equals(Class other)
{
if (other == null)
{
return false;
}
return this.Id.Equals(other.Id);
}
Now when I'm on a detailPage which is only having one item, I want to manually refresh that item from the database.
When doing my refresh the Id obviously does not change, but the remaining attributes can.
Now the problem I have is that the Propertychanged is not triggered when item is identical(based on id).
Class refreshedItem = await Task.Run(() => backendConnection.GetSchedule(scheduleId, DTOType.Maxi, BackEndSettings.Default.SystemOfMeasurement));
Item = refreshedItem;
If I set the Item to a dummy item in between it is triggered every time.
Class refreshedItem = await Task.Run(() => backendConnection.GetSchedule(scheduleId, DTOType.Maxi, BackEndSettings.Default.SystemOfMeasurement));
Item = new Class(Guid.Empty) { Title = "test" };
Item = refreshedItem;
Looking at Github Fody Properties Overview, the (default) code that is injected in Item setter is equivalent to
if (value != item)
OnPropertyChanged();
It only fires when not equal.
The documentation for Fody Properties says to use Attributes to control its behavior. For what you want, use DoNotCheckEqualityAttribute.
Related
In app I'm bulding I used data model presented by James_D here:
Applying MVC With JavaFx
I just can find a way to bind labels text to property of object held in DataModel
Data is structured like this:
model class Student
//partial class
public class Student {
private final StringProperty displayName = new SimpleStringProperty();
public final StringProperty displayNameProperty(){
return this.displayName;
}
public Student(){
}
public final String getDisplayName() {
return this.displayNameProperty().get();
}
public final void setDisplayName(String displayName) {
this.displayNameProperty().set(displayName);
}
}
Student instaces are held by StudentDataModel class
public class StudentDataModel {
// complete student list
private final ObservableList<Student> studentList = FXCollections.observableArrayList();
private final ObjectProperty<Student> selectedStudent = new SimpleObjectProperty<>(new Student());
public final Student getSelectedStudent() {
return selectedStudent.get();
}
public final ObjectProperty<Student> selectedStudentProperty() {
return selectedStudent;
}
public final void setSelectedStudent(Student student) {
selectedStudent.set(student);
}
}
StudentList is displayed by Table View, there is change listener that sets selectedStudent like this:
public class TableViewController {
public void initModel(StudentDataModel studentDM) {
// ensure model is set once
if (this.studentDM != null) {
throw new IllegalStateException("StudentDataModel can only be initialized once");
}
this.studentDM = studentDM;
tableView.getSelectionModel().selectedItemProperty().addListener((obs, oldSelection, newSelection) -> {
if (newSelection != null) {
studentDM.setSelectedStudent(newSelection);
}
});
}}
There is another controller ActionsBarController that has label to display selected student (this seems redundant, but there is option for selecting multiple objects to perform bulk operations).
StudentDataModel is initialized properly (I can see it in debuger) but below doesn't do anything:
chosenStudentLabel.textProperty().bind(studentDM.getSelectedStudent().displayNameProperty());
//this shows class name with instance number changing correctly
chosenStudentLabel.textProperty().bind(studentDM.selectedStudentProperty().asString());
I could inject ActionsBarController to TableViewController and change label text from change Listener there, but this seems counter productive with data model.
What am I doing wrong?
Your code doesn't work, because you call (and evaluate) getSelectedStudent() at the time the binding is created (i.e. when you initialize the model). As a consequence, you only bind to the displayName property of the student that is selected at that time. (If nothing is selected, you'll get a NullPointerException.) The binding will only change if that initially-selected student's display name changes; it won't change if the selection changes.
You need a binding that unbinds from the old selected student's display name, and binds to the new selected student's display name, when the selected student changes. One way to do this is:
chosenStudentLabel.textProperty().bind(new StringBinding() {
{
studentDM.selectedStudentProperty().addListener((obs, oldStudent, newStudent) -> {
if (oldStudent != null) {
unbind(oldStudent.displayNameProperty());
}
if (newStudent != null) {
bind(newStudent.displayNameProperty());
}
invalidate();
});
}
#Override
protected String computeValue() {
if (studentDM.getSelectedStudent() == null) {
return "" ;
}
return studentDM.getSelectedStudent().getDisplayName();
}
});
Note that there is also a "built-in" way to do this, but it's a bit unsatisfactory (in my opinion) for a couple of reasons. Firstly, it relies on specifying the name of the "nested property" as a String, using reflection to access it. This is undesirable because it has no way to check the property exists at compile time, it requires opening the module for access, and it is less good performance-wise. Secondly, it gives spurious warnings if one of the properties in the "chain" is null (e.g. in this case if the selected student is null, which is will be initially), even though this is a supported case according to the documentation. However, it is significantly less code:
chosenStudentLabel.textProperty().bind(
Bindings.selectString(studentDM.selectedStudentProperty(), "displayName")
);
Since MenuItem is not a Node, I'm not able to look it up. How do I test, if some MenuItem is disabled?
I've tried to look it up as it was a node and it returned me something, which looks like this..
(toString representation of returned object):
(ContextMenuContent$MenuItemContainer[id=mnEditHrom, styleClass=menu-item])
But i can't cast MenuItem on that, it says "Node cannot be converted to MenuItem" and when I call isDisabled() function on what was returned, i get incorrect information.
Lets say I have MenuItem with "mnEdit" id, which is disabled. When i call
find("#mnEdit").isDisabled();
it returns false. Find method looks like this:
public <T extends Node> T find(String query)
{
return (T) lookup(query).queryAll().iterator().next();
}
So again, how do I test whether some MenuItem is disabled or not in testFx?
You almost done in the original post. When you get the MenuItemContainer get the MenuItem firstly and finally call isDisable():
ContextMenuContent.MenuItemContainer actualMenuItemContainer = find("#mnEdit");
boolean actualResult = actualMenuItemContainer.getItem().isDisable();
I solved it by looking up MenuBar, identifying item I want to test by its Id and since I have now MenuItem obejct in hands, I can call isDisable() on it.
MenuTest.class
CommonTests common = new CommmonTests();
#Test
public void disabledMenuItemTest()
{
common.disabledMenuItemTest("#mainMenu", "mnEditHrom", true);
}
CommonTests.class
TestUtils utils = new TestUtils();
public void disabledMenuItemTest(String menuBarSelector, String menuItemId, boolean expected)
{
Boolean actual = utils.isMenuItemDisabled(menuBarSelector, menuItemId);
if (actual != null)
assertEquals("MenuItem "+menuItemId+" je enabled/disabled (expected = "+expected+").", expected, actual.booleanValue());
else
fail("MenuBar/MenuItem not found.");
}
TestUtils.class
public Boolean isMenuItemDisabled(String menuBarSelector, String menuItemId)
{
ArrayList<MenuItem> list = getAllMenuItems(menuBarSelector);
Boolean disabled = null;
if(list != null)
{
for(MenuItem item : list)
{
if(item.getId() != null && item.getId().equals(menuItemId))
return item.isDisable();
}
}
return disabled;
}
private ArrayList<MenuItem> getAllMenuItems(String menuBarSelector)
{
ArrayList<MenuItem> itemsList = new ArrayList<MenuItem>();
MenuBar menuBar = (MenuBar) find(menuBarSelector);
if(menuBar != null)
{
menuBar.getMenus().forEach(menu -> {
menu.getItems().forEach(menuItem -> {
itemsList.add(menuItem);
});
});
return itemsList;
}
return null;
}
I am trying to implmenet a file uploader that can take various amounts of files. The files input elemnts are all named the same so produce a list of files that MVC3 happily binds to.
So in my controller I have have
public virtual ViewResult UploadReceive(IEnumerable<HttpPostedFileBase> Files ){
This gets all the files it should. However all empty form file input elements are adding a null. This is stopping my basic non empty List validation in the controller from working as I want.
The validation is below:
public class EnsureMinimumElementsAttribute : ValidationAttribute
{
private readonly int _minElements;
public EnsureMinimumElementsAttribute(int minElements)
{
_minElements = minElements;
}
public override bool IsValid(object value)
{
var list = value as IList;
if (list != null)
{
return list.Count >= _minElements;
}
return false;
}
}
Any idea how I change the validation to generically count only non null elements?
If you only want to count non-null objects you can use LINQ with an IList by using:
list.Cast<object>().Count(o => o != null)
Alternatively you can just loop and count each non-null object.
int count = 0;
foreach (var item in list)
{
if (item != null)
count++;
}
I am data binding to many FormView controls using EF entity instances, but I have to resort to this ridiculous kludge in order to achieve what I want without using EntityDataSource controls:
propertyHeaderSection.DataSource = new List<PropertyDetailsModel> { _propertyDetails };
I suspect I will have to derive my own control from FormView and enable it to accept an almost POCO as a data source. Where do I start?
This is my implementation, sort of the same idea as patmortech, but i also found out that the ValidateDataSource method on the BaseDataBoundControl is what throws the exception at run-time if your datasource isn't enumerable.
public class CustomFormView : System.Web.UI.WebControls.FormView
{
public override object DataSource
{
get
{
if (!(base.DataSource is IEnumerable))
return new[] {base.DataSource};
return base.DataSource;
}
set
{
base.DataSource = value;
}
}
// This method complains at run time, if the datasource is not
// IListSource, IDataSource or IEnumerbale
protected override void ValidateDataSource(object dataSource)
{
//base.ValidateDataSource(dataSource);
}
}
EDIT:
Considering the suggestion, i've made some changes to the way i check if the assigned DataSource is enumerable or not. I have also managed to create a sample app (VS 2010 Solution) to demo the changes. The app can be downloaded from http://raghurana.com/blog/wp-content/attachments/FormViewDataProblem.zip
In short this is what i am checking to ensure that the existing datasource can be enumerated already or not:
public static bool CanEnumerate( this object obj )
{
if (obj == null) return false;
Type t = obj.GetType();
return t.IsArray ||
t.Implements(typeof (IEnumerable).FullName) ||
t.Implements(typeof (IListSource).FullName) ||
t.Implements(typeof (IDataSource).FullName);
}
Please feel free to suggest more changes, if this isnt quite the desired functionality. Cheers.
Not sure it's the best idea in the world, but this is how you could derive from FormView to allow single object data source values. It basically does the same check that the ValidateDataSource does internally, and then creates a list wrapper for the item if it's not already a valid type.
public class SingleObjectFormView : System.Web.UI.WebControls.FormView
{
public override object DataSource
{
get
{
return base.DataSource;
}
set
{
//will check if it's an expected list type, and if not,
//will put it into a list
if (! (value == null || value is System.Collections.IEnumerable || value is System.ComponentModel.IListSource || value is System.Web.UI.IDataSource) )
{
value = new List<object> { value };
}
base.DataSource = value;
}
}
}
I would like to create a collection of key, value pairs in C# where the key is a property of an ASP.net control (e.g. ID) and the value is the value of that property. I would like to do this so I may later iterate through the collection and see if a given control has the properties in my collection (and the values of the properties in the control match the values defined in my collection). Any suggestions as to the best way to do this? Thanks for any help.
Pseudo-code example:
Properties[] = new Properties[] {new Property(){name="ID",value="TestControl1"}, new Property(){name = "Text",value="Type text here"}}
private bool controlContainsProperties(Control control){
foreach(Property Property in Properties[])
{
if((control does not contain property) || (control property value != Property.Value))
return false;
}
return true;
}
didn't test this, but here's my go:
public bool HasProperty( object target, IDictionary<string, object> values )
{
var targetType = target.GetType();
return values.All( kvp =>
{
var property = targetType.GetProperty( kvp.Key );
if ( property != null )
{
var value = property.GetValue( target, null );
if ( value != null )
return value.Equals( kvp.Value );
}
return false;
} );
}
My first idea was in using 'tag' property, but then I realized that there are no tags in APS.NET controls. However, there is an answered question about tags.
In the same thread there is a solution with 'Attributes' property map - looks promising.