Below is the code of binding data into dropdown list of the property grid.
[Category(Constants.ColumnScrambler), PropertyOrder(2)]
[DisplayName(Constants.Condition)]
[Description(Constants.Condition)]
[ItemsSource(typeof(CustomColumnConditionProperty))]
public ConditionType Condition
{
get
{
return this.condition;
}
set
{
this.condition = value;
if (condition == ConditionType.Expression)
{
var descriptor = TypeDescriptor.GetProperties(this.GetType())["ConditionExpressionType"];
var attrib = (BrowsableAttribute)descriptor.Attributes[typeof(BrowsableAttribute)];
FieldInfo isBrow = attrib.GetType().GetField("browsable", BindingFlags.NonPublic | BindingFlags.Instance);
if (isBrow != null) isBrow.SetValue(attrib, true);
descriptor.SetValue(this, attrib);
}
this.OnPropertyChanged("Condition");
this.objExpressionBuilder.NotifyPropertyCheckSelected(this);
}
}
I want to show below Textbox when i select Expression from the dropdown list of property grid.
[Category(Constants.ColumnScrambler)]
[DisplayName("Expression")]
[Description("Expression")]
[Browsable(false)]
public string ConditionExpressionType
{
get { return "TestData"; }
}
But the problem is that to do so ,i have to rebind the property grid again and all the values vanished. can anyone please suggest a way without rebind on selection of dropdown list in property grid i can show the text box.
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 have a problem regarding the comportment my ComboBox.
First I use a combobox to display all elements in a IEnumarale.
Then, with a button wich open a popup, the user can add an alement to that list.
The problem is that when the user validate his choice and close the popup, the element is not automatly added to the ComboBox without doing a refresh of the page.
The combobox is coded as follows :
<telerik:RadComboBox x:Name="MyElements"
SelectionChanged="MyElements_OnSelectionChanged"
ItemTemplate="{StaticResource ComboBoxElementsTemplate}"
ItemsSource="{Binding ListElements}"/>
The constructor of the list is :
public IEnumerable<Element> ListElements
{
get { return _listElements; }
set
{
_listElements= value;
RaisePropertyChange("ListElements");
}
}
And the code behind of the button to validate the user choice in the popup :
private ObservableCollection<HistoriqueElement> elementList = null;
private void SelectClick(object sender, RoutedEventArgs e)
{
var element= _GridList.SelectedItem as HistoriquePasserelle;
if (_GridList.SelectedItem != null)
{
var installation = this.DataContext as Installation;
if (installation != null && element!= null)
{
element.DateFin = DateTime.Now;
HistoriqueElement newElement= new HistoriqueElement()
{
Installation = installation,
ContactAction = GlobalActeurs.Current.CurrentContact,
Date = DateTime.Now,
Element = element.Element,
StatutElement = element.StatutElement ,
Owner= element.Owner,
};
elementList.Remove(element);
}
MainPage.ClosePopup();
}
}
When the user choose a new element in the list display in the popup and validate his choice, he returns to the main page, but his choice is not automatically added to the combobox.
I can post you any parts of the code.
Thank you in advance.
The method OnDataContextChanged :
public override void OnDataContextChanged(DependencyPropertyChangedEventArgs e)
{
if (e.NewValue is Installation)
{
if (MainPage.CurrentInstallation.LastElements != null)
{
ListElements = MainPage.CurrentInstallation.LastElements;
MyElements.SelectedIndex = 0;
}
else
{
LoadOperation<Element> operation =
_context.Load(_context.GetCurrentElementsByInstallationId(MainPage.CurrentInstallation.Id));
this._busy.IsBusy = true;
operation.Completed += delegate
{
this._busy.IsBusy = false;
if (operation.ManageError())
{
ListElements = operation.Entities;
}
};
}
this.DataContext = this;
}
else
{
RaisePageTitleChanged();
if (MainPage.CurrentInstallation == null)
return;
}
if (MyElements.SelectedItem == null && MyElements.Items.Any())
{
MyElements.SelectedIndex = 0;
}
}
If the collection the ItemsSource is bound to implement INotifyCollection changed, that is, it's an ObservableCollection<>, then the combobox will be notified of any changes to the collection and you will not need to rebind or refresh, it will all be automatic.
Once you add the item to the list, bind the itemsource to the combobox, then you dont have to refersh.
MyElements.ItemsSource = ListElements
I have one textBox and one combobox in wpf usercontrol. ComboxBox is binded to ICollectionView (CurencyList) which populates Currency Pairs like GBP/EUR,CLP/EUR,USD/EUR,EUR/USD etc. Whenever the user writes in textbox e.g. EUR the combobox should get filtered and display the dropdownlist with EUR as the second currency.
For this I have used like:
public string Currency
{
get {
return _criteriaType.currency; }
set
{
if (_criteriaType.currency != value)
{
_criteriaType.currency = value.EmptyOrWhiteSpaceAsNull();
base.OnPropertyChanged("Currency");
CurrencyList.Filter = new Predicate<object>(Contains);
}
}
}
public bool Contains(object de)
{
CurrencyPair o = de as CurrencyPair;
if (Currency != null || Currency == string.Empty)
{
return (o.name.Substring(3, 4).ToLower().Contains(Currency.ToLower()));
}
else
{
IsOpen = false;
OnPropertyChanged("IsOpen");
return false;
}
}
CurrencyList is coming from a webservice:
private ICollectionView GetCurrencyPair()
{
strCurrencyPair.arg0 = (Currency != string.Empty && Currency != null) ? Convert.ToString(Currency).ToUpper() : string.Empty;
string[][] cPair = ServiceLocator.Resolve<IWebServiceRepository>().BusinessWebService.getCurrenyPairs(strCurrencyPair);
foreach (string[] item in cPair)
{
IList.Add(new CurrencyPair() { name = (Convert.ToString(item[0]).ToUpper() + "/" + Convert.ToString(item[1]).ToUpper()) });
}
return CurrencyList =CollectionViewSource.GetDefaultView(IList);
}
Filtering is working fine. But when the user deletes the currency from textbox with backward arrow key from keyboard, the combobox filtered to nothing i.e. dropdownlist is empty.
How to overcome this problem. kindly suggest?
you need to update your collection view through the text change event
private void OnTextChanged(object sender, Eventargs e) {
var vm = yourViewModelOrWhatEver;
((ICollectionView)vm.CurrencyList).Refresh();
}
or set the filter predicate once and fire only the refresh on currency change
public void ctor() {
CurrencyList.Filter = new Predicate<object>(Contains);
}
public string Currency {
get { return _criteriaType.currency; }
set {
if (_criteriaType.currency == value) {
return;
}
_criteriaType.currency = value.EmptyOrWhiteSpaceAsNull();
base.OnPropertyChanged("Currency");
CurrencyList.Refresh(); // refresh/filter the collection view
}
}
hope that helps
EDIT
you say
Filtering is working fine. But when the user deletes the currency from
textbox with backward arrow key from keyboard, the combobox filtered
to nothing i.e. dropdownlist is empty. How to overcome this problem.
kindly suggest?
then you must change your predicate function to this one
public bool Contains(object de)
{
CurrencyPair o = de as CurrencyPair;
if (Currency != null || Currency == string.Empty) {
// Currency == string.Empty should also true
return (Currency == string.Empty) || (o.name.Substring(3, 4).ToLower().Contains(Currency.ToLower()));
} else {
IsOpen = false;
OnPropertyChanged("IsOpen");
return false;
}
}
I would assume the issue lies with this statement: string[][] cPair =
ServiceLocator.Resolve().BusinessWebService.getCurrenyPairs(strCurrencyPair);
what is the return value from that service if you pass string.empty for strCurrencyPair as you will currently be doing once the textbox is empty from backspacing?
I'm using a MVVM approach with WPF to let the user select one item in a combobox. The model contains a set of possible options, the combobox is bound to this set, the current selection is again bound to a property of my model. This part works fine.
Now I'd like to allow the user to enter an arbitrary text into the combobox. If the text doesn't correspond to an existing item the program should ask him if he wants to add a new item. He should also be allowed to cancel the action and select another item.
How would I do that within the MVVM pattern?
You would check the "already existing" status of the text from your ViewModel's bound property setter. At that point, you need a mechanism to raise an event and decide what to do based on what happens.
An example:
enum Outcome { Add, Cancel }
class BlahEventArgs : EventArgs
{
Outcome Outcome { get; set; }
}
class ViewModel
{
private string name;
public EventHandler<BlahEventArgs> NotExistingNameSet;
public Name
{
get { return this.name; }
set
{
if (/* value is existing */) {
this.name = value;
return;
}
var handler = this.NotExistingNameSet;
if (handler == null) {
// you can't just return here, because the UI
// will desync from the data model.
throw new ArgumentOutOfRangeException("value");
}
var e = new BlahEventArgs { Outcome = Outcome.Add };
handler(this, e);
switch (e.Outcome) {
case Outcome.Add:
// Add the new data
this.name = value;
break;
case Outcome.Cancel:
throw new Exception("Cancelled property set");
}
}
}
}
Your View would add an event handler to NotExistingNameSet to present appropriate UI and set the value of e.Outcome accordingly.
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 :)