I have a WPF Application with two ComboBox
When I select the first one the items related to the first combobox will be populated on the second one
Here is my select Property
public string SelectedApplication
{
set
{
if (_selectedApplication == value) return;
this._selectedApplication = value;
InitializeTransactionTypes();
}
get
{
return this._selectedApplication;
}
}
here i am checking a matching id between the two comboboxes to populate the second combobox items.
ObservableCollection<TransactionTypeViewModel> _transTypeObsList = new ObservableCollection<TransactionTypeViewModel>();
private void InitializeTransactionTypes()
{
if (_selectedApplication != null)
{
var getAppCode =
ApplicationVModel.GetAllApplications()
.FirstOrDefault(apps => apps.Name == _selectedApplication);
var transTypeList = TransactionTypeVModel.GetAllViewModelTransTypes()
.Where(t => getAppCode != null && t.Id == getAppCode.Id);
transactionTypes = new ObservableCollection<TransactionTypeViewModel>(transTypeList);
NotifyPropertyChanged("TransactionTypes");
}
}
More information about methods:
List of VM mapped from List of Model
public List<TransactionTypeViewModel> GetAllViewModelTransTypes()
{
TransactionTypeViewModels = TransactionTypeModel.GetAllTransactionTypes().Select(transType => new TransactionTypeViewModel
{
Id = transType.Id,
Name = transType.Name,
})
.ToList();
return TransactionTypeViewModels;
}
Lets say I select first combobox has {A,B,C,D} ...and the second combobox has {A'1,A'2,A'3}, when I select item from first Combobox the second combobo keeps populating
items. I wanted to show only {A'1 for A} {B'1 for B} ...etc but now what it does is {A'1 A'1 A'1 ..... for A} {B'1 B'1 B'1 ....for B} for every select.
I want the previous selection to be cleared and display a new list per select. Thanks
To sum up comments. Instead of creating new ObservableCollection every time something changes reuse one that you already have and it will notify UI about changes. Your InitializeTransactionTypes should look something like this:
private void InitializeTransactionTypes()
{
if (_selectedApplication != null)
{
var getAppCode =
ApplicationVModel.GetAllApplications()
.FirstOrDefault(apps => apps.Name == _selectedApplication);
transactionTypes.Clear();
foreach(var transactionItem in TransactionTypeVModel.GetAllViewModelTransTypes().Where(t => getAppCode != null && t.Id == getAppCode.Id))
transactionTypes.Add(transactionItem);
}
}
and like this you should not have to notify about TransactionTypes changes any more
Related
I am using vaadin 7.7.7
In a grid i have a combobox as an edited item in one of the columns
as
grid.addColumn("columnProperty").setEditorField(combobox);
I need to update a property/cell in same row based on the combobox selection change
My issue is , the selection change event triggers twice, once when the combobox in clicked and second when the selection value is changed. But the updated value in next cell gets reflected on UI only first time.
Below is the code written . Any solutions?
Combobox.addValueChangeListener(new ValueChangeListener()
#Override
public void valueChange(ValueChangeEvent event) {
// below line works only first time when the combobox is clicked,but i want
//it when the item in the combobox is changed
gridContainer.getContainerProperty(editedRow,"editedColumProperty").setValue("ValueTobeUpdated");}
});
Need to update the unit column on combobox change in edited mode(before saving)
Refer below link for image
example image
You will get value change events even when the field gets value that it should show to the user. In order to get event that indicates that the user has accepted the input you should use field group (setEditorFieldGroup).
From Book of Vaadin example for grid editing:
grid.getColumn("name").setEditorField(nameEditor);
FieldGroup fieldGroup = new FieldGroup();
grid.setEditorFieldGroup(fieldGroup);
fieldGroup.addCommitHandler(new CommitHandler() {
private static final long serialVersionUID = -8378742499490422335L;
#Override
public void preCommit(CommitEvent commitEvent)
throws CommitException {
}
#Override
public void postCommit(CommitEvent commitEvent)
throws CommitException {
Notification.show("Saved successfully");
}
});
Edit
I assume that you want to connect Parameter and Unit comboboxes. I would do that with this kind of value change lister
BeanItemContainer container = new BeanItemContainer<>(
Measurement.class,
measurements);
Grid grid = new Grid(container);
grid.setEditorEnabled(true);
ComboBox parameterComboBox = new ComboBox();
ComboBox unitComboBox = new ComboBox();
parameterComboBox.addItems(Parameter.Pressure, Parameter.Temperature, Parameter.Time);
parameterComboBox.addValueChangeListener(v -> setUnits(parameterComboBox, unitComboBox));
grid.getColumn("parameter").setEditorField(parameterComboBox);
grid.getColumn("unit").setEditorField(unitComboBox);
Units could be updated like this. I think you need to preserve current value and set it back if you replace available items in the combobox.
private void setUnits(ComboBox parameterComboBox, ComboBox unitComboBox) {
Object currentValue = unitComboBox.getValue();
List<String> units = unitsForParameter(parameterComboBox.getValue());
unitComboBox.removeAllItems();
unitComboBox.addItems(units);
if (units.contains(currentValue)) {
unitComboBox.setValue(currentValue);
} else {
unitComboBox.setValue(null);
}
}
private List<String> unitsForParameter(Object value) {
if (value == null) {
return Collections.emptyList();
} else if (value == Parameter.Pressure) {
return asList("Pascal", "Bar");
} else if (value == Parameter.Temperature) {
return asList("Celcius", "Kelvin");
} else if (value == Parameter.Time) {
return asList("Second", "Minute");
} else {
throw new IllegalArgumentException("Unhandled value: " + value);
}
}
I cannot get updated item in ListView after modifying existing database item. Though, once I reload the application one can see updated item in ListView.
I have binded to an ObservableCollection for the ListView
This is my interface
public interface IService
{
IEnumerable<Employee> GetDetails();
IEnumerable<Employee> GetDetailsById(int MatchID);
}
I have implemented IService IEmployeeServiceData class.
public class IEmployeeServiceData:IService
{
private EmployeeContext Context
{
get;
set;
}
public IEmployeeServiceData()
{
Context = new EmployeeContext();
}
public IEnumerable<Model.Employee> GetDetails()
{
return Context.Employees;
}
public IEnumerable<Model.Employee> GetDetailsById(int MatchID)
{
var q = from f in Context.Employees
where f.EMPLOYEE_ID == MatchID
select f;
return q.AsEnumerable();
}
}
This is my VM
public void RefereshData()
{
var e = EmployeeService.GetDetails();
if (SelectedIndexValue == 1)
{
var Data = from e1 in e
where e1.LOCATION == "Pune"
select e1;
EmployeeMasterData = new ObservableCollection<Model.Employee>(Data);
}
else if(SelectedIndexValue==2)
{
var Data = from e1 in e
where e1.LOCATION == "Bangalore"
select e1;
EmployeeMasterData = new ObservableCollection<Model.Employee>(Data);
}
else
{
EmployeeMasterData = new ObservableCollection<Model.Employee>(e);
}
}
Updating Exiting Item:
public void UpdateEmployee()
{
try
{
Context = new EmployeeContext();
Employee Emp = Context.Employees.First(i => i.EMPLOYEE_ID == FindId1);
Emp.FIRST_NAME = this.FIRSTNAME;
Emp.FAMILY_NAME = this.FAMILY_NAME;
Emp.EXTERNAL_ID = this.EXTERNALID;
Emp.DB_SPONSOR = this.DBSPONSOR;
Emp.LEGAL_ENTITY = this.LEGAL_ENTITY;
Emp.COST_CENTER = this.COST_CENTER1;
Emp.STATUS = this.StatusCategory;
Emp.ENTRY_DATE = this.ENTRYDATE;
Emp.LOCATION = this.LocationCategory1;
Context.SaveChanges();
Clear();
AlertMessage1 = "Employee Record is Updated Sucessfulyy !!!";
IsVisible1 = true;
timer.Start();
}
catch(Exception ex)
{
Console.WriteLine(ex.InnerException);
}
}
Existing Item
Updated Item
Changes done to an entity in Entity Framework will not be reflected on screen because the two instances are not related in your example. Yes the have the same values, but they are two different distinct reference locations in memory. **For the ObservableCollection is a copy of the list and not the actual list being manipulated in your example.
Hence they are not related.
To show a change you have these options:
Change the actual object's property(ies) held by the observable collection to mirror the change done in to the other EF entity. Also the EF entity must adhere to INotifyPropertyChange or also the data property change won't be seen on the screen.
Or delete the screen entity and add the changed entity into the list.
Or delete the whole observable list and re-add it with the latest version from EF. (You mention that you do this and that is an option as well).
Can some one please tell me Why is this not possible? I am new to WPF and Linq
I am trying to select a value from my first combobox and display the related values in my second combobox.
private void initializeTransactionTypes()
{
var getAppCode = applicationVModel.GetAllApplications().FirstOrDefault(apps => apps.AppCode == selectedApplication);
var transTypeList = (from transName in transTypeVModel.GetAllTransactionTypes()
where transName.Id == getAppCode.Id
select transName.Name).ToList();
//cast list of string to observ.
ObservableCollection<TransactionTypeViewModel> transTypeObsList =
new ObservableCollection<TransactionTypeViewModel>(transTypeList);
TransactionTypes = transTypeObsList;
NotifyPropertyChanged("TransactionTypes");
// }
//}
}
// Bind trans type combobox to this
public ObservableCollection<TransactionTypeViewModel> TransactionTypes
{
set
{
initializeTransactionTypes();
NotifyPropertyChanged("TransactionTypes");
}
get
{
return _transactionType;
}
}
It looks like transTypeList is a List<string> (assuming transName.Name is a string) and you are trying to use it to initialise an ObservableCollection<TransactionTypeViewModel>.
The constructor for ObservableCollection<T> requires a List<T> so you need to provide a List<TransactionTypeViewModel> instead.
It looks like you just need to change your linq query to:
var transTypeList = (from transName in transTypeVModel.GetAllTransactionTypes()
where transName.Id == getAppCode.Id
select transName).ToList();
or alternatively:
var transTypeList = transTypeVModel.GetAllTransactionTypes()
.Where(t => t.Id == getAppCode.Id)
.ToList();
Using the standard listbox I would like to bind it to a set of objects and update a bound items collection to include those selected.
So I have something like:
_pContext = new BindingSource();
_pContext.DataSource = _gpContext;
_pContext.DataMember = "ParentEntities";
_AllChildrenListBox.DataSource = _container.ChildEntities;
_AllChildrenListBox.DataBindings.Add("MySelectedItems", _pContext, "ChildEntities", false);
_allChildrenListBox is the listbox. I created a new listbox type inheriting from ListBox so I could create an alternative SelectedItems property which would then encapsulate the logic to set/unset the items.
So the question in a nutshell is: In the above, ChildEntities is a collection of "ChildEntity" objects. My list box contains all possible ChildEntity objects and I want the elements in ChildEntities to be selected, and updated when selection changed.
I have found a way around this. It's a little ugly at the moment, but works. I can refine it later.
So first bit was the binding itself.
_AllChildrenListBox.DataBindings.Add("SelectedItems2", _pContext, "ChildEntities2", true);
The key here seemed to be setting the formatting parameter to true.
Next I needed something in SelectedItems2 that would do my dirty work. This is a mess, but works. Here's the full class:
public class MyListBox : ListBox
{
private IEnumerable<object> _original;
public IEnumerable<object> SelectedItems2
{
get
{
return UpdateSet();
}
set
{
SelectItems(value);
}
}
private IEnumerable<object> UpdateSet()
{
var listSource = _original as IListSource;
IList list = null;
if (listSource != null)
{
list = listSource.GetList();
}
var iList = _original as IList;
if (list == null && iList != null)
{
list = iList;
}
if (list == null)
{
return _original;
}
foreach (var item in SelectedItems)
{
if (!list.Contains(item))
{
list.Add(item);
}
}
foreach (var item in _original.ToList())
{
if (!SelectedItems.Contains(item))
{
list.Remove(item);
}
}
return _original;
}
private void SelectItems(IEnumerable<object> items)
{
_original = items;
var hashset = new HashSet<object>();
foreach (var item in items)
{
hashset.Add(item);
}
for(var i=0;i<Items.Count;i++)
{
SetSelected(i, hashset.Contains(Items[i]));
}
}
}
Essentially I'm breaking all the rules and assuming IEnumerable hides a more tasty list based interface, if it does it uses that to changes the underlying set.
Finally, I'm using EF (Entity Framework) and you can't call the setter of a collection property, so my entity currently looks like this: Notice how I'm duplicating all the list change operations which is totally unnecessary, but I did say this was just the first working go.
public partial class ParentEntity
{
public IEnumerable<object> ChildEntities2
{
get
{
return new List<object>(ChildEntities);
}
set
{
if (value == null)
{
return;
}
foreach (var item in ChildEntities.ToList().Where(item => !value.Contains(item)))
{
ChildEntities.Remove(item);
}
foreach (var item in value)
{
var cItem = item as ChildEntity;
if (cItem != null)
{
if (!ChildEntities.Contains(item as ChildEntity))
{
ChildEntities.Add(item as ChildEntity);
}
}
}
}
}
}
I have an ItemsContol bound to a Country model - which look like this.
Country
--int Id
--string Name
--List Counties
In the DataTemplate of the ItemsControl there's a Listbox - which is bound to the Counties property.
So what I want is only one item in any of the listboxes be selected at any one time.
For example:
I have an item selected in the first listbox and I click an item in the second listbox, then the first listbox shouldn't have any selected items.
Any ideas ??
Add a SelectedCounty property to your Country object. Then you can bind the SelectedItem on your ListBox to that property. Then in code manually set all others to null. Something like so
Country.OnPropertyChanged += (s,e) =>
{
if(e.PropertyName == "SelectedCounty")
{
foreach(Country country in MyCountries)
if(country != sender)
country.SelectedCounty = null;
}
}
Just for reference here's the solution I'm using - it resides in the CountryViewModel
private CountyModel _selectedcounty;
public CountyModel SelectedCounty
{
get { return _selectedcounty; }
set
{
_selectedcounty = value;
RaisePropertyChanged("SelectedCounty");
if (value != null)
{
if (CountySelectedEvent != null)
CountySelectedEvent(value, EventArgs.Empty);
Messenger.Default.Send<CountyModel>(value, "SelectedCounty");
}
}
}
public CountryViewModel()
{
Counties = new ObservableCollection<CountyModel>();
Messenger.Default.Register<CountyModel>(this, "SelectedCounty",
msg =>
{
if(msg != this.SelectedCounty && msg != null)
this.SelectedCounty = null;
});
}
Hope it helps someone :)