Blazor(ise) DataGrid iterate through DataGridColumns in code (behind) - datagrid

Sorry if this is a Blazorise and not just a general Blazor WebAseembly question, being a noob in both I'm just not sure so posting with both tags, but I'd like to display a list of items in a DataGrid that has certain columns sortable (multiple simultaneously and not by just one at a time), and once that sortable columns desc/asc/none direction setting occurs I'd like to be able to read their set direction properties state on a button click to pass it along to another component...only I can't do it with a #ref like this:
<DataGrid TItem="Item"
Data="#ItemList"
#ref="dataGrid"
#bind-SelectedRow="#selectedItem"
Responsive ShowPager="true" PageSize="10">
<DataGridCommandColumn TItem="Item" />
<DataGridColumn TItem="Item" Field="#nameof(Item.Id)" Caption="#" Sortable="false" />
<DataGridColumn TItem="Item" Field="#nameof(Item.SKU)" Caption="SKU" Sortable="false"/>
<DataGridColumn TItem="Item" Field="#nameof(Item.ModelId)" Caption="Model" Sortable="false" />
<DataGridColumn TItem="Item" Field="#nameof(Item.Year)" Caption="Year" Editable="true" Direction="SortDirection.Ascending" />
<DataGridColumn TItem="Item" Field="#nameof(Item.Weight)" Caption="Weight" Editable="true" Direction="SortDirection.Ascending" />
</DataGrid>
#code {
private Blazorise.DataGrid.DataGrid<Ad> dataGrid;
protected void OnClick(MouseEventArgs mouseEventArgs)
{
int i = 0;
string sortdirections="";
dataGrid.DataGridColumns.
foreach(Blazorise.DataGrid.DataGridColumn<Ad> col in dataGrid.DataGridColumns)
{
if (col.Sortable)
{
i++;
switch(col.SortDirection){
case SortDirection.Ascending: smartsort += ("a" + i.ToString()); break;
case SortDirection.Descending: smartsort += ("d" + i.ToString()); break;
case SortDirection.None: break;
}
}
}
. . .
}
Because I get a build error
CS1579 foreach statement cannot operate on variables of type
'RenderFragment' because 'RenderFragment' does not contain a public
instance or extension definition for 'GetEnumerator'
given that the dataGrid.DataGridColumns seemingly doesn't reference the actual rendered instance of the dataGrid component I'm using (but a RenderFragment instead), because one should probably databind variables to those Direction properties I guess...but the trouble with me databinding Direction properties to some or particular variable(s) is that I'd like to make the DataGrid a bit more dynamic in the future, in which case I wouldn't even know in advance during design-time what and which columns would be sortable and the user could be setting some sortable columns to sort direction none...thus I need some (pardon the pun) direction please on how to do it this way (basically like using old ASP.NET server-side components to access its run-time state in a blazor webassembly app) or how to do it with preferably just a single databound variable dynamically but so that just a few columns out of the ones displayed are going to actually be sortable through a click on a datagrid column name with which the user could change the sort order direction (so that the databound variable then after the user finishes clicking the sort orders of colums holds the state of that datagrid indicating which of the sortable columns have been set to ascend and which of the to descend, if any of them, since they can also choose direction none)?
TIA

The latest version of Blazorise has a sort mode:
<DataGrid ... Sortable="true" SortMode="DataGridSortMode.Multiple" ...
https://blazorise.com/docs/helpers/enums/datagrid
If that's not exactly what you are looking for, ask Mladen on gitter or check out the source code here.

Related

Flex: Programmatically determine value selected from MultiSelectComboBox

I am new to Flex and want to programmatically determine the value selected from a MultiSelectComboBox. The code is as follows:
<columns: ExtendedDataGridColumn
width="50" dataField="department"
filterComboBoxBuildFromGrid="false"
filterComboBoxDataField="label"
filterComboBoxDataProvider="{deptCollection}"
filterControl="MultiSelectComboBox"
filterOperation="Equals"
sortable="true" />
Whenever you need to check the selected value (or values), use the selectedItems property:
private function querySelections() {
foreach (var item:* in multiComboBox) {
trace(item.id);
}
}
Of course, you'll need to make sure that you can get a reference to the MultiSelectComboBox to the code that wants to read it. If it's defined inside an ItemRenderer, you'll need to make sure to expose it to the calling code.

Button to Show a Window from Listbox Row

I want to create a button that can show a window to show details of elements in listbox when it's clicked. the listbox itsetf was created from a list of JSONObject like this:
<listbox id="userListbox">
<listhead>
<listheader laber="Action"></listheader>
<listheader label="Id"></listheader>
<listheader label="Name"></listheader>
<listheader label="Address"></listheader>
<listheader label="Phone"></listheader>
</listhead>
<listitem forEach="${userController.list}">
<listcell>
<button label="Detail" id="detailButton"></button>
</listcell>
<listcell label="${each.id}" ></listcell>
<listcell label="${each.name}" ></listcell>
<listcell label="${each.address}" ></listcell>
<listcell label="${each.phone}" ></listcell>
</listitem>
</listbox>
for every row (listcell) there is always a button to show the details. but when I load the page, it failed to show the list with error message:
Not unique in ID space < Window cP8Q0#userWindow>: detailButton.
any idea to show a window when the button clicked? here is the code when button is clicked:
#Listen("onClick = #detailButton")
public void showModal(Event event) {
Component comp = Executions.createComponents("/widgets/window/modal_dialog/employee_dialog.zul", null, null);
if(comp instanceof Window) {
((Window)comp).doModal();
}
}
thank you for your help.
The problem is that if you click on different buttons you are running the createComponents again and again. Your employee_dialog.zul is only safe to include into the page once as it has IDs in it; if you do the operation twice you are creating a second set of components with the same ID and the IDs should be unique within a given idSpace (see the ZK developer guide for the theory).
There are other issues here: why create the components twice? Why not keep one and only one set around, showing and hiding them based on button clicks. That is more efficient.
Look at Button to Show a Window from Listbox Row which shows that you can:
<zk>
<!-- hidden -->
<window id="wnd" title="My Modal" visible="false" width="300px">
<button label="close" onClick="wnd.visible = false"/>
</window>
<!-- click button to pop the hidden window! -->
<button label="do it" onClick="wnd.doModal()"/>
</zk>
So you can use a
<include src="/widgets/window/modal_dialog/employee_dialog.zul">
to pull the model dialog into the bottom of the main page once and only once. Then in the code you can set the data into it and do
win1.doModal();
where win1 is the modal window defined in the fragment. You have to tell the model window what to display before you pop it but that is not hard. Use desktopScope.put( "myName", this) to have the controller/view-model of the dialog box register itself in a location where the controller/view-model in the main window can find it and talk to it to pass it the data to render.
Two other tips.
Hide your fragments as /WEB-INF/zul/employee_dialog.zul as anything under WEB-INF cannot be directly accessed by a browser for better security.
Try not to put any zul into your java. That is mixing behaviour with presentation. Sometimes it is unavoidable but always try first to keep the zul in the zul then interact with it via java IDs only (much like my suggestion). It is not always possible but separation of logic from layout is a core design pattern.
Simon
<button label="Detail" />
#Listen("onClick = listbox listitem listcell button")

Need help to prepare Main Home Page for WPF application having vertical menu

Hii,
I am creating a WPF aplication. My home page will look like the one I have shown in the image.
In which i will have following componenents:
1. Topbar
2. Left bar - slide down menu like accordion which will slide down on selection if it has any submenu items otherwise on selection it will show related form.
3. Main panel - in which i will open my child forms
4. Bottom bar.
I would prefer if i get already implemented application that i can reuse in my application, as I think this form is gonna take hell lot of time. And Also as I am new to WPF, I would love to have some guidance about following points
How to make a slide down accordion like menu in WPF, which are also supposed to have submenu in it. ex. Report menu - will have list of all reports in it, which will be displayed when you click on the reports menu. How can I accomplish this in WPF>
How to open child form in right side panel? What controls/components should I use in my form to host child forms?
Any sample applications, web references, or already implemented code will be of great help as I have very strict deadline and dont afford to spend much time in exploring.
Abandon full accordion functionality
If you can live without a full accordion, you could easily accomplish something similar to what you want by using a TabControl, with alternate layout (TabStripPlacement="Left").
See this question (the same as in my comments): Create Tabbed Sidebar with sections WPF
Existing Library
There are existing WPF control libraries with accordions:
WPF Toolkit
Telerik Rad controls - http://www.telerik.com/products/wpf.aspx (or silverlight/asp.net MVC, etc)
Many others, most of them for money...
DIY
You can try using a TreeView to implement your accordion, too. You just need a few tricks up your sleeve to accomplish this:
First, you need to hide the tree-view buttons. They will mess up what we're trying to accomplish. See this question - Treeview hide [+] [-] buttons
Second, you want to ensure that the IsExpanded property is set to true if a TreeViewItem or one of its children is selected, and set to false otherwise. You can do this with a IMultiValueConverter combined with a Style for TreeViewItem.
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication1">
<!-- ... -->
<TreeView>
<TreeView.Resources>
<local:SelectedItemToIsChildConverter x:Key="isChildConverter" />
<Style TargetType="{x:Type TreeViewItem}">
<Style.Setters>
<Setter Property="IsExpanded">
<Setter.Value>
<MultiBinding Converter="{StaticResource isChildConverter}">
<Binding Path="SelectedItem"
RelativeSource="{RelativeSource AncestorType={x:Type TreeView}}" />
<Binding RelativeSource="{RelativeSource Self}" />
</MultiBinding>
</Setter.Value>
</Setter>
</Style.Setters>
</Style>
</TreeView.Resources>
<!-- Children here, or set ItemsSource property via databinding -->
</TreeView>
Here's the code for the converter, in separate CS file:
public class SelectedItemToIsChildConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
TreeViewItem selectedItem = values.Length > 0 ? values[0] as TreeViewItem : null;
TreeViewItem targetItem = values.Length > 1 ? values[1] as TreeViewItem : null;
if (targetItem == null)
return false;
TreeViewItem currentItem = selectedItem;
while (currentItem != null)
{
if (currentItem == targetItem)
return true;
currentItem = currentItem.Parent as TreeViewItem;
}
return false;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
After this, you would have to style it to make it look nice, and support animation.
Once this is all done, use a grid to split up your UI. Use data binding to show content on your main UI area, based off the selected tree view item.
Edit:
Actually, a tree view is a poor base for an accordion. I searched a bit for details on accordion controls, and it turns out that they tend to only have one level of hierarchy.
With this description in mind, it may be easier to use a DataGrid, and take advantage of the RowDetails to expand your accordion view.
Here's a brief tutorial: http://www.wpftutorial.net/DataGrid.html#rowDetails
Just make sure most of the data grid features are disabled.

How to validate a <mx:List component>?

How can I validate if atleast one item has been selected from a list, such that the selectedIndices is set to NULL at the init() of application?
Following code can be of help to someone who want to validate a list like I wanted:
<mx:NumberValidator
id ="myListValidator"
trigger ="{myButton}"
triggerEvent ="click"
minValue ="0"
lowerThanMinError="Should I write an application to you for selecting atleast one of the option X-("
source ="{myList}"
property ="selectedIndex"
/>

Flex ComboBox, default value and dataproviders

I have a Flex ComboBox that gets populated by a dataprovider all is well...
I would now like to add a default " -- select a item --" option at the 0 index, how can I do this and still use a dataprovider? I have not seen any examples of such, but I can't imagine this being hard...
If you don't need the default item to be selectable you can use the prompt property of ComboBox and set the selectedIndex to -1. That will show the string you set propmt to as the selected value until the user chooses another. It will not appear in the list of options, however.
I came across this problem today and wanted to share my solution.
I have a ComboBox that has an ArrayCollection containing Objects as it's dataprovider. When the application runs, it uses a RemoteObject to go out and get the ArrayCollection/Objects. In my event handler for that call I just have it append another object to the beginning of the ArrayCollection and select it:
var defaultOption:Object = {MyLabelField: "Select One"};
myDataProvider.addItemAt(defaultOption, 0);
myComboBox.selectedIndex = 0;
This is what my ComboBox looks like for reference:
<mx:ComboBox id="myComboBox" dataProvider="{myDataProvider}" labelField="MyLabelField" />
The way I've dealt with this in the past is to create a new collection to serve as the data provider for the combobox, and then I listen for changes to the original source (using an mx.BindingUtils.ChangeWatcher). When I get such a notification, I recreate my custom data provider.
I wish I knew a better way to approach this; I'll monitor this question just in case.
This can be used following code for selected default value of combobox
var index:String = "foo";
for(var objIndex:int = 0; objIndex < comboBox.dataProvider.length; objIndex++) {
if(comboBox.dataProvider[objIndex].label == index)
{
comboBox.selectedIndex = objIndex;
break;
}
}
<mx:ComboBox id="comboBox" dataProvider="{_pageIndexArray}" />

Resources