I am having trouble in vaadin combobox after setting a value. here is my code
public class ComponentService implements FieldGroupFieldFactory {
/**
* Create Distributor ComboBox
*/
public ComboBox createComboBoxDistributor(String caption, boolean required) {
ComboBox c = new ComboBox(caption);
BeanItemContainer<Distributor> beans = new BeanItemContainer<Distributor>(Distributor.class);
beans.addAll(distributorService.find(null));
c.setContainerDataSource(beans);
c.setFilteringMode(FilteringMode.CONTAINS);
c.setRequired(required);
return c;
}
}
ComboBox comboDistributor = componentService.createComboBoxDistributor("Disributor", false);
comboDistributor.setValue(this.entity.getCustomer().getDistributor());
You could check if distributorService.find(null).contains(this.entity.getCustomer().getDistributor()) as Vaadin uses the equals function of the Bean (Distributor in this case).
Alternatively you can check if beans.getItemIds().contains(this.entity.getCustomer().getDistributor()); returns true.
If any of the above statements return true, the selection should work.
Maybe the client does not update its content? try getUI().access( () -> getUI().push());
Related
I have a comboBox in XPages which is showing an hierarcal list of categories and values populates as a vector in SSJS.
I now want to apply a styleheet (bold) to the categories (i.e on only the categories of the generated option tags)
please note that I do not need a lesson in how stylesheets work. I need to know how to add a class or style to the categories in the outputted options tags
how can I do that?
thanks
Thomas
UPDATED MY QUESTION WITH A WORKING CLASS
Mimics a categorized view with 3 columns in a comboBox, category, label and value
public class Utils {
public static List<SelectItem> getGroupedComboboxOptions() {
try {
Database db = ExtLibUtil.getCurrentDatabase();
View vv = db.getView("ProdukterByCat");
Vector v = vv.getColumnValues(0);
List<SelectItem> groupedOptions = new ArrayList<SelectItem>();
SelectItemGroup group;
for (int i = 0; i < v.size(); i++) {
List<SelectItem> options = new ArrayList<SelectItem>();
group = new SelectItemGroup(v.get(i).toString());
ViewEntryCollection nvec = vv.getAllEntriesByKey(v.get(i), true);
ViewEntry entry = nvec.getFirstEntry();
while (entry != null) {
SelectItem option = new SelectItem(entry.getColumnValues().get(2).toString(),entry.getColumnValues().get(1).toString());
options.add(option);
entry = nvec.getNextEntry(entry);
}
group.setSelectItems(options.toArray(new SelectItem[options.size()]));
groupedOptions.add(group);
}
return groupedOptions;
} catch (NotesException e) {
e.printStackTrace();
}
return null;
}
}
A combobox in XPages is rendered using a HTML select tag. If you organise the options in optgroup's (see also Populating selectItems of the combobox (label, value) using a managed bean) you get some default styling out of the box. Example here.
You can even apply additional styling on them with standard CSS by targeting the optgroup. But support for that is limited: it doesn't work on an iPad for example.
If you want more control on how your dropdowns look, I'd suggest to use a plugin like Select2.
Using Windows forms and linq to Sql, I bound a datagridview to Products Table, I added to the form 1 Textbox to input the searched text.
I wonder how to position the datagridview according to the text entered to find a given ProductName.
Here I do not want to filter rows, I only want to reposition datagrid after each character entered, the used code:
private void textBox1_TextChanged(object sender, EventArgs e)
{
var searchValue = textBox1.Text.Trim().ToUpper();
var qry = (from p in dc.Products
where p.ProductName.ToUpper().StartsWith(searchValue)
select p).ToList();
int itemFound = productBindingSource.Find("ProductName", searchValue);
productBindingSource.Position = itemFound;
}
The execution of code give the next error: System.NotSupportedException was unhandled at the ligne:
int itemFound = productBindingSource.Find("ProductName", searchValue);
Any idea please ?
The MSDN documentation for BindingSource has the answer:
The Find method can only be used when the underlying list is an
IBindingList with searching implemented. This method simply refers the
request to the underlying list's IBindingList.Find method. For
example, if the underlying data source is a DataSet, DataTable, or
DataView, this method converts propertyName to a PropertyDescriptor
and calls the IBindingList.Find method. The behavior of Find, such as
the value returned if no matching item is found, depends on the
implementation of the method in the underlying list.
When you call this method on a BindingSource whose underlying data source does not implement IBindingList then you see the exception (thrown by the default implementation of IBindingList.FindCore:
System.NotSupportedException: The specified method is not supported.
You don't show what you bind the binding source to but clearly it doesn't implement this method.
Annoyingly, BindingList<T> the recommended list type to use for your data source does not provide a FindCore implementation.
If you are using BindingList you will need to create your own custom type. Here is the code for an absolutely bare bones implementation of a BindingList that supports find:
public class FindableBindingList<T> : BindingList<T>
{
public FindableBindingList()
: base()
{
}
public FindableBindingList(List<T> list)
: base(list)
{
}
protected override int FindCore(PropertyDescriptor property, object key)
{
for (int i = 0; i < Count; i++)
{
T item = this[i];
if (property.GetValue(item).Equals(key))
{
return i;
}
}
return -1; // Not found
}
}
You can do lots with your own implementations of BindingList such as supporting sorting. I've left my answer as just the minimum to support the find method. Search for SortableBindingList if you want to know more.
To use this class do something like this:
var qry = (from p in dc.Products
where p.ProductName.ToUpper().StartsWith(searchValue)
select p).ToList();
FindableBindingList<YourType> list = new FindableBindingList<YourType>(qry);
dataGridView1.DataSource = list;
Ok, a bit of a strange one - and it's probably something simple as I'm pretty new to Silverlight!
I have an object with the following property:-
private int targetID = NULL_TARGET_VALUE;
[Display(Name="Target", Order=1)]
[Required]
public int TargetID
{
get
{
return targetID;
}
set
{
if (this.targetID != value)
{
this.ValidateProperty("TargetID", value);
this.targetID = value;
this.RaisePropertyChanged("TargetID");
}
}
}
This object is created using the DataForm from the toolkit. I use the AutoGeneratingField event to change the item to a combo box drop down with the code below:
if (e.PropertyName == "TargetID")
{
ComboBox target = new ComboBox() { DisplayMemberPath = "Title", SelectedValuePath = "ItemID" };
target.ItemsSource = TaskManager.Manager.GanttItemSource;
var selectedItem = TaskManager.Manager.GanttItemSource.FirstOrDefault(p => p.ItemID == ParentTargetID);
target.SelectedItem = selectedItem;
e.Field.ReplaceTextBox(target, ComboBox.SelectedValueProperty, binding => binding.Converter = new TargetNullValueConverter());
break;
}
This does result in a drop down as I would expect. On my save button event I have this code:
if (registerForm.ValidateItem())
{
this.task.Save();
}
If the debugger is attached to the silverlight project this works great. If it's not then ValidateItem returns false as it thinks I have added an invalid target ("Input is not in a correct format" is the exact validation error I get).
Any ideas really appreciated! (BTW Just to confirm this happens in both release and debug build modes, simply attaching or removing a debugger causes this to occur)
Dammit, the issues was down to this line in the autogeneratingfield event:-
e.Field.ReplaceTextBox(target, ComboBox.SelectedValueProperty, binding => binding.Converter = new TargetNullValueConverter());
This allows it to work
e.Field.ReplaceTextBox(target, ComboBox.SelectedValueProperty);
Which makes sense because I'm dealing with ints not objects. Still don't know why it works with the debugger attached however!
I have a WPF DataGrid control with a SelectionUnit of "FullRow" and SelectionMode of "Extended" that I'm programmatically selecting an item in (the first item, usually). The selection works, but for some reason any form of programmatic selection seems to break the shift-select multiselect ability.
If I single click another item in the DataGrid (so the item I just clicked is the only item selected), then shift-select will work. It only seems to break if I've programmatically selected the item. Additionally, control-click works to select multiple items in either case -- it seems to only be shift-select that is broken.
I've tried various forms of programmatically selecting the single item, from as simple as myGrid.SelectedIndex = 0, to using the DataGrid's ItemContainerGenerator to get an instance of the DataGridRow object and setting IsSelected = true on it, but to no avail.
To re-iterate -- programmatic selection of an item works, but it breaks shift-click selection.
Has anyone run into this before? I've tried setting focus on the DataGridRow instance that is programmatically selected, but it doesn't seem to help?
I succeeded to work around this problem using reflection:
var method = typeof(DataGrid).GetMethod("HandleSelectionForCellInput", BindingFlags.Instance | BindingFlags.NonPublic);
method.Invoke(MyDataGrid, new object[] { cellToSelect, false, false, false });
I struggled with this problem for multiple days and tried a lot of things that I found on the internet. In the end, I found the solution that works for me by studying the source code of the DataGrid.
In the DataGrid I noticed a member variable called _selectionAnchor and guessed that this must be the starting point for when a user expands the selection in the grid. My solution is to set this member to the first cell of the row that is selected. If a row is selected in code, than this fix makes sure that when expanding the selection it starts at the selected row.
Please note that I used the code from this issue to enable multiselect. Then, in file MainWindow.xaml.cs, I added this code:
private void ExampleDataGrid_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (ExampleDataGrid.SelectedItems.Count > 0)
{
ExampleDataGrid.ScrollIntoView(ExampleDataGrid.SelectedItems[0]);
// Make sure that when the user starts to make an extended selection, it starts at this one
foreach (var cellInfo in ExampleDataGrid.SelectedCells)
{
if (cellInfo.Column.DisplayIndex == 0)
{
var cell = GetDataGridCell(cellInfo);
cell?.Focus();
var field = typeof(DataGrid).GetField("_selectionAnchor", BindingFlags.NonPublic | BindingFlags.Instance);
field?.SetValue(ExampleDataGrid, cellInfo);
break;
}
}
}
}
public DataGridCell GetDataGridCell(DataGridCellInfo cellInfo)
{
var cellContent = cellInfo.Column.GetCellContent(cellInfo.Item);
if (cellContent != null)
{
return (DataGridCell)cellContent.Parent;
}
return null;
}
In the xaml file:
<vm:CustomDataGrid x:Name="ExampleDataGrid" ItemsSource="{Binding ImportItems}"
SelectedItemsList="{Binding SelectedImportItems, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
AutoGenerateColumns="False" SelectionMode="Extended" IsReadOnly="True" CanUserAddRows="False"
SelectionChanged="ExampleDataGrid_SelectionChanged">
Remember there is a difference between focus and keyboard focus. When you select the item in code, check to see what control has Keyboard focus / regular focus. I'm guessing that the data grid loses this focus until you click on it with the mouse and then it regains the focus needed to use the ctrl function.
I ran into this issue in a WPF user control we were hosting inside a C++ application.
I just resolved exactly the same problem with the help of #ezolotko's snippet.
Because the grid is dynamically generating rows I needed to subscribe to ItemContainerGenerator.StatusChanged event and find the first cell in a row representing this element.
To find the cell I used DataGridHelper class and wrapped it all in an attached behaviour:
using System.Reflection;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using Speedwell.WPF.Helpers;
namespace Speedwell.WPF.Behaviors
{
public static class DataGridSingleRowSelected
{
public static readonly DependencyProperty IsSelectionFixEnabledProperty = DependencyProperty.RegisterAttached
(
"IsSelectionFixEnabled",
typeof(bool?),
typeof(DataGridSingleRowSelected),
new PropertyMetadata(null, IsSelectionFixEnabledChanged)
);
public static bool GetIsSelectionFixEnabled(DataGrid element)
{
return (bool)element.GetValue(IsSelectionFixEnabledProperty);
}
public static void SetIsSelectionFixEnabled(DataGrid element, bool value)
{
element.SetValue(IsSelectionFixEnabledProperty, value);
}
private static void IsSelectionFixEnabledChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
{
var dataGrid = sender as DataGrid;
if(dataGrid != null)
{
if(args.OldValue == null)
{
dataGrid.ItemContainerGenerator.StatusChanged += (s, e) => ContainerStatusChanged(dataGrid, ((ItemContainerGenerator)s));
}
}
}
private static void ContainerStatusChanged(DataGrid dataGrid, ItemContainerGenerator generator)
{
if(generator != null && generator.Status == GeneratorStatus.ContainersGenerated && dataGrid.SelectedItems.Count == 1)
{
var row = (DataGridRow)dataGrid.ItemContainerGenerator.ContainerFromItem(dataGrid.SelectedItems[0]);
if(row != null)
{
var cell = dataGrid.GetCell(row, 0);
if(cell != null)
{
SelectCellMethod.Invoke(dataGrid, new object[] { cell, false, false, false });
}
}
}
}
private static readonly MethodInfo SelectCellMethod = typeof(DataGrid).GetMethod("HandleSelectionForCellInput", BindingFlags.Instance | BindingFlags.NonPublic);
}
}
As you can see the proper selection is only applied when there is a single (1) row selected and this is exactly what I need and it seems it also what #Jordan0Day requested.
I'm developing a Windows Forms application in VS2008. I want to display a unknown, but small number of DataGridViews on a form, using code like this:
foreach (QueryFilter f in Query.Filter)
{
DataGridView grid = CreateGridView(String.Format("GridView{0}", filters.Count));
grid.Location = new System.Drawing.Point(3, 9 + (filters.Count * grid.Height + 9));
BindingList<QueryFilterNode> nodes = new BindingList<QueryFilterNode>();
foreach (QueryFilterNode node in f)
nodes.Add(node);
grid.DataSource = nodes;
panel1.Controls.Add(grid);
filters.Add(nodes);
}
The grid(s) are added to the panel, but the data inside is not displayed. My guess is setting the DataSource property doesn't actualy bind the grid, because (for example) the dataGridView_ColumnAdded event is not fired.
QueryFilter and QueryFilterNode are just POCO's and contain data of course.
For completeness sake the construction of the DataGridView:
private DataGridView CreateGridView(string name)
{
DataGridView grid = new DataGridView();
grid.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
grid.Name = name;
grid.Size = new System.Drawing.Size(484, 120);
grid.ColumnAdded += new System.Windows.Forms.DataGridViewColumnEventHandler(this.dataGridView_ColumnAdded);
return grid;
}
Hmm, it seems it was my own mistake.
QueryFilterNode, used as datasource ( BindingList<QueryFilterNode> ) wasn't a POCO but a datacontract. Snippet:
[DataContract(Name = "QueryFilterNode")]
public class QueryFilterNode
{
[DataMember(IsRequired = true)]
public string FieldCode;
For some reason these cannot be databound. I used a simple class like this in my BindingList and it just worked.
class QueryFilterNodeSimple
{
public string FieldCode
{ get; set; }