Xamarin Forms Custom Datagrid - xamarin

I have a model as you can see in the attachment. I can get output in datagrid itemsource as shown (syncfusion sfDataGrid). but I want to get output like below. how can I do it?
img

if you want to achieve this you can :
1- the best way is to replace your sfDataGrid with syncfusion PivodGrid.
2- Or if you want to achieve it with a datagrid, you have to transform your data collection according to, each element in the collection is a row so you have to make group by yourself.

I have prepared a sample to achieve your requirement. Please refer to the following code snippets to achieve the requirement,
XAML: Define Columns and rows using GridUnboundColumn and UnboundRows respectively.
<sfgrid:SfDataGrid x:Name="sfGrid"
ColumnSizer="Star"
AutoGenerateColumns="False"
ItemsSource="{Binding OrdersInfo}">
<sfgrid:SfDataGrid.Behaviors>
<local:DataGridBehavior/>
</sfgrid:SfDataGrid.Behaviors>
<sfgrid:SfDataGrid.Columns>
<sfgrid:GridTextColumn HeaderText="Color" MappingName="Color" />
<sfgrid:GridUnboundColumn MappingName="S" HeaderText="S"/>
<sfgrid:GridUnboundColumn MappingName="M" HeaderText="M"/>
<sfgrid:GridUnboundColumn MappingName="L" HeaderText="L"/>
<sfgrid:GridUnboundColumn MappingName="XL" HeaderText="XL"/>
<sfgrid:GridUnboundColumn MappingName="2XL" HeaderText="2XL"/>
</sfgrid:SfDataGrid.Columns>
<sfgrid:SfDataGrid.UnboundRows>
<sfgrid:GridUnboundRow />
<sfgrid:GridUnboundRow />
</sfgrid:SfDataGrid.UnboundRows>
</sfgrid:SfDataGrid>
Behavior: In the SfDataGrid.QueryUnboundRow event, set the value based on the model object. Also, hide the actual data rows using the QueryRowHeight event.
public class DataGridBehavior : Behavior<SfDataGrid>
{
SfDataGrid DataGrid;
protected override void OnAttachedTo(SfDataGrid bindable)
{
DataGrid = bindable;
DataGrid.QueryUnboundRow += sfGrid_QueryUnboundRow;
DataGrid.QueryRowHeight += sfGrid_QueryRowHeight;
base.OnAttachedTo(bindable);
}
private void sfGrid_QueryUnboundRow(object sender, GridUnboundRowEventArgs e)
{
var viewModel = (sender as SfDataGrid).BindingContext as ViewModel;
if (e.UnboundAction == UnboundActions.QueryData)
{
List<Orders> rowOrders = null;
if (e.RowColumnIndex.RowIndex == 1)
{
rowOrders = viewModel.OrdersInfo.Where(x => x.Color == "WHITE").ToList();
}
else if (e.RowColumnIndex.RowIndex == 2)
{
rowOrders = viewModel.OrdersInfo.Where(x => x.Color == "BLACK").ToList();
}
if (e.RowColumnIndex.ColumnIndex == 0)
{
e.Value = rowOrders[0].Color;
e.Handled = true;
}
else
{
var item = rowOrders.FirstOrDefault(x => x.Size == e.Column.HeaderText.ToString());
e.Value = item != null ? item.Stock.ToString() : "-";
e.Handled = true;
}
}
}
private void sfGrid_QueryRowHeight(object sender, QueryRowHeightEventArgs e)
{
if (e.RowIndex == 0)
{
e.Height = 50;
}
//To hide the actual data rows from the view.
else if (!DataGrid.IsUnboundRow(e.RowIndex))
{
e.Height = 0;
e.Handled = true;
}
}
}
Please find the workable sample in the following link.
Sample: https://www.syncfusion.com/downloads/support/directtrac/general/ze/GettingStarted-549596453
You can refer to our user guidance document regarding UnboundRows and UnboundColumns from the following link,
UG links:
https://help.syncfusion.com/xamarin/datagrid/unbound-column
https://help.syncfusion.com/xamarin/datagrid/unbound-row#populating-data-for-unbound-rows
https://help.syncfusion.com/xamarin/datagrid/row-height-customization#customize-rowheight-for-all-rows

Related

How can I implement the SearchBar method to search keywords for more than one element from the Class in Xamarin Forms?

Here I have the SearchBar method, which, at the moment, searching keywords from my TITLE element of the Post Class. But I want to search by TITLE and LOCATION, which is the second element in my Post Class. How to add the LOCATION element from my Post class to the searchBar method?
private void searchBarmainPage_TextChanged(object sender, TextChangedEventArgs e)
{
try
{
using (SQLiteConnection conn = new SQLiteConnection(App.DatabaseLocation))
{
var keyword = e.NewTextValue;
conn.CreateTable<PostClass>();
var posts = conn.Table<PostClass>().ToList();
if(keyword.Length >= 1)
{
var results = posts.Where(x => x.Title.ToLower().Contains(keyword.ToLower()));
listViewMainPage.ItemsSource = results;
listViewMainPage.IsVisible = true;
}
else
{
listViewMainPage.IsVisible = false;
}
}
} catch (NullReferenceException r)
{
}catch (Exception m)
{
}
}
You can use the || operator to check if the keyword is contained inside the Title or inside the Location.
If you want the keyword to be in both places at the same type, you should use &&
using (SQLiteConnection conn = new SQLiteConnection(App.DatabaseLocation))
{
var keyword = e.NewTextValue;
conn.CreateTable<PostClass>();
var posts = conn.Table<PostClass>().ToList();
if(keyword.Length >= 1)
{
var results = posts.Where(x => x.Title.ToLower().Contains(keyword.ToLower()) || x.Location.ToLower().Contains(keyword.ToLower()) );
listViewMainPage.ItemsSource = results;
listViewMainPage.IsVisible = true;
}
else
{
listViewMainPage.IsVisible = false;
}
}

Windows Form Multi-Select for Tree View

Is there a way to multi-select in a Windows Tree View? Similar to the image below
I know that .NET currently doesn't have a multiselect treeview. It is treated as a wrapper around the win32 native treeview control. I would like to avoid the Treeview's Checkbox property if possible. Any suggestions is greatly appreciated!
Im gonna assume you're trying to avoid check boxes. Here is an example:
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
treeView1.DrawMode = OwnerDrawText;
treeView1.DrawNode += treeView1_DrawNode;
treeView1.NodeMouseClick += treeView1_NodeMouseClick;
}
private void treeView1_DrawNode(object sender, DrawTreeNodeEventArgs e) {
// Show checked nodes with an underline
using (SolidBrush br = new SolidBrush(e.Node.TreeView.BackColor))
e.Graphics.FillRectangle(br, e.Node.Bounds);
Font nodeFont = e.Node.NodeFont;
if (nodeFont == null) nodeFont = e.Node.TreeView.Font;
if (e.Node.Checked) nodeFont = new Font(nodeFont, FontStyle.Underline);
using (SolidBrush br = new SolidBrush(e.Node.TreeView.ForeColor))
e.Graphics.DrawString(e.Node.Text, nodeFont, br, e.Bounds);
if (e.Node.Checked) nodeFont.Dispose();
}
private void treeView1_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e) {
if (Control.ModifierKeys == Keys.Shift && e.Node.Parent != null) {
// Extend selection
bool check = false;
foreach (TreeNode node in e.Node.Parent.Nodes) {
if (node.Checked) check = true;
node.Checked = check;
if (node == e.Node) break;
}
}
else {
unselectNodes(treeView1.Nodes);
e.Node.Checked = true;
}
}
This question has been answered here but I'll briefly answer your question. While it is true that Native Treeview control does not allow multiple selection, you can derive a subclass from it and override its behaviors.
Example code:
checkNodes method:
private void checkNodes(TreeNode node, bool check)
{
foreach (TreeNode child in node.Nodes)
{
if (child.Checked == true)
{
MessageBox.Show(child.Text);
}
//MessageBox.Show(child.Text);
checkNodes(child, check);
}
}
Treeview method after check:
private void treeView1_AfterCheck(object sender, TreeViewEventArgs e)
{
if (e.Action != TreeViewAction.Unknown)
{
if (busy) return;
busy = true;
try
{
TreeNode _node = e.Node;
checkNodes(e.Node, e.Node.Checked);
if (e.Node.Checked)
{
MessageBox.Show(e.Node.Text);
}
}
finally
{
busy = false;
}
}
}
It is not trivial to do so, however it can be done.

How to implement TabLayout.IOnTabSelectedListener.OnTabUnselected with TabbedPage.ToolbarPlacement="Bottom" - Xamarin Forms?

I just recently used android:TabbedPage.ToolbarPlacement="Bottom". I used to have the following code:
void TabLayout.IOnTabSelectedListener.OnTabUnselected(TabLayout.Tab tab)
{
var playPage = Element.CurrentPage as NavigationPage;
if (!(playPage.RootPage is PhrasesFrame))
return;
var tabLayout = (TabLayout)ViewGroup.GetChildAt(1);
var playTab = tabLayout.GetTabAt(4);
tab.SetText("Play");
tab.SetIcon(Resource.Drawable.ionicons_2_0_1_play_outline_25);
App.pauseCard = true;
}
Anyone knows how can I implement this with ToolbarPlacement="Bottom" ? I have implemented both BottomNavigationView.IOnNavigationItemSelectedListener, BottomNavigationView.IOnNavigationItemReselectedListener but can't find any reference for UnselectedTab if there is any.
Edit:
Previous custom renderer using the default tab position and implementing TabLayout:
namespace Japanese.Droid
{
public class MyTabbedPageRenderer: TabbedPageRenderer, TabLayout.IOnTabSelectedListener
{
ViewPager viewPager;
TabLayout tabLayout;
bool setup;
public MyTabbedPageRenderer(Context context): base(context){ }
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
// More codes here
}
void TabLayout.IOnTabSelectedListener.OnTabReselected(TabLayout.Tab tab)
{
UpdateTab(tab);
}
void TabLayout.IOnTabSelectedListener.OnTabSelected(TabLayout.Tab tab)
{
UpdateTab(tab);
}
void TabLayout.IOnTabSelectedListener.OnTabUnselected(TabLayout.Tab tab)
{
var playPage = Element.CurrentPage as NavigationPage;
if (!(playPage.RootPage is PhrasesFrame))
return;
var tabLayout = (TabLayout)ViewGroup.GetChildAt(1);
var playTab = tabLayout.GetTabAt(4);
tab.SetText("Play");
tab.SetIcon(Resource.Drawable.ionicons_2_0_1_play_outline_25);
App.pauseCard = true;
}
void UpdateTab(TabLayout.Tab tab)
{
// To have the logic only on he tab on position 1
if (tab == null || tab.Position != 4)
{
return;
}
if (tab.Text == "Play")
{
tab.SetText("Pause");
tab.SetIcon(Resource.Drawable.ionicons_2_0_1_pause_outline_22);
App.pauseCard = false;
}
else
{
tab.SetText("Play");
tab.SetIcon(Resource.Drawable.ionicons_2_0_1_play_outline_25);
App.pauseCard = true;
}
}
}
}
Current custom renderer using the ToolbarPlacement="Bottom":
namespace Japanese.Droid
{
public class BottomTabPageRenderer : TabbedPageRenderer, BottomNavigationView.IOnNavigationItemSelectedListener, BottomNavigationView.IOnNavigationItemReselectedListener
{
public BottomTabPageRenderer(Context context) : base(context) { }
protected override void OnElementChanged(ElementChangedEventArgs<TabbedPage> e)
{
base.OnElementChanged(e);
// More codes here
}
bool BottomNavigationView.IOnNavigationItemSelectedListener.OnNavigationItemSelected(IMenuItem item)
{
base.OnNavigationItemSelected(item);
UpdateTab(item)
}
void BottomNavigationView.IOnNavigationItemReselectedListener.OnNavigationItemReselected(IMenuItem item)
{
UpdateTab(item);
}
void UpdateTab(IMenuItem item)
{
var playTabId = 4;
var title = item.TitleFormatted.ToString();
if (item == null || item.ItemId != playTabId)
{
return;
}
if (item.ItemId == playTabId)
{
if (title == "Play")
{
item.SetTitle("Pause");
item.SetIcon(Resource.Drawable.ionicons_2_0_1_pause_outline_22);
App.pauseCard = false;
}
else
{
item.SetTitle("Play");
item.SetIcon(Resource.Drawable.ionicons_2_0_1_play_outline_25);
App.pauseCard = true;
}
}
}
}
}
So now my problem is I don't have any idea how will I implement the TabLayout.IOnTabSelectedListener.OnTabUnselected in the new custom renderer.
There is no official stuff for OnTabReselected event for TabbedPage's bottom navigation or
BottomNavigationView because It doesn't use TabLayout.Tab for a start. Many overridden methods of TabbedPageRenderer not being called like SetTabIcon. If you are using IOnTabSelectedListener interface(As your first part of code) you have three methods to use.
void OnTabReselected(Tab tab);
void OnTabSelected(Tab tab);
void OnTabUnselected(Tab tab);
But when it comes to BottomNavigationView interface you have only two methods
void OnNavigationItemReselected
bool OnNavigationItemSelected
So we don't have built in OnTabUnselected method. Here you need to write custom code to make unseleted event.
I have tried this code without using custom renderer using 4 tabs pages & the xaml of tabbed written in MailPage.xaml file. First declare List<string> in App.xaml.cs file to store Title of all tabs
public static List<string> Titles {get;set;}
Add tabs pages title in above list from MainPage.xaml.cs file's OnAppearing method
protected override void OnAppearing()
{
for (int i = 0; i < this.Children.Count; i++)
{
App.Titles.Add(this.Children[i].Title);
}
}
Now go to your MyTabbedPage class in which is available in shared project.
public class MyTabbedPage : Xamarin.Forms.TabbedPage
{
string selectedTab = string.Empty;
string unSelectedTab = string.Empty;
bool isValid;
public MyTabbedPage()
{
On<Xamarin.Forms.PlatformConfiguration.Android>().SetToolbarPlacement(ToolbarPlacement.Bottom);
this.CurrentPageChanged += delegate
{
unSelectedTab = selectedTab;
selectedTab = CurrentPage.Title;
if (App.Titles != null)
isValid = true;
else
App.Titles = new List<string>();
if (isValid)
{
MoveTitles(selectedTab);
//Pass 0 index for tab selected & 1 for tab unselected
var unSelecteTabTitle = App.Titles[1];
//TabEvents(1); here you know which tab unseleted call any method
}
};
}
//This method is for to moving selected title on top of App.Titles list & unseleted tab title automatic shifts at index 1
void MoveTitles(string selected)
{
var holdTitles = App.Titles;
if (holdTitles.Count > 0)
{
int indexSel = holdTitles.FindIndex(x => x.StartsWith(selected));
holdTitles.RemoveAt(indexSel);
holdTitles.Insert(0, selected);
}
App.Titles = holdTitles;
}
}
Or you can make swith case like this
void TabEvents(int index)
{
switch (index)
{
case 0:
//Tab selected
break;
case 1:
//Tab unselected
break;
}
}
Few things I should mention that MainPage.xaml.cs file inheriting MyTabbedPage
public partial class MainPage : MyTabbedPage
Structure of MainPage.xaml file
<?xml version="1.0" encoding="utf-8" ?>
<local:MyTabbedPage
<TabbedPage.Children>
<NavigationPage Title="Browse">
</NavigationPage>
</TabbedPage.Children>
</local:MyTabbedPage>
Answer seems long but hope it help you.
As per G.Hakim's suggestion, I was able to do what I wanted to do by capturing the tab item I wanted to work on and do the necessary actions in BottomNavigationView.IOnNavigationItemSelectedListener.OnNavigationItemSelected.
namespace Japanese.Droid
{
public class BottomTabPageRenderer : TabbedPageRenderer, BottomNavigationView.IOnNavigationItemSelectedListener, BottomNavigationView.IOnNavigationItemReselectedListener
{
// same as above
bool BottomNavigationView.IOnNavigationItemSelectedListener.OnNavigationItemSelected(IMenuItem item)
{
base.OnNavigationItemSelected(item);
if(item.ItemId == 4 && item.TitleFormatted.ToString() == "Play")
{
item.SetTitle("Pause");
item.SetIcon(Resource.Drawable.ionicons_2_0_1_pause_outline_22);
App.pauseCard = false;
playTab = item;
}
if(item.ItemId !=4 && playTab.TitleFormatted.ToString() == "Pause")
{
playTab.SetTitle("Play");
playTab.SetIcon(Resource.Drawable.ionicons_2_0_1_play_outline_25);
App.pauseCard = true;
}
return true;
}
// same as above
}
}

Trying to retrieve result using linq

Hi I have a table which has a column AllowStockEdit which is a bit
I am trying to check is a user has edit access and then show edit and delete buttons on a radgridview
this is the code I am using
protected void AccessLevels(object sender, EventArgs e)
{
LINQDataContext dc = new LINQDataContext();
UserPermission up = dc.UserPermissions.Where(a => a.ID == (int)Session["Permission"]).SingleOrDefault();
up.AllowStockEdit = true;
}
/*show hide buttons */
protected void SelectedStockGridView_RowDataBound(Object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
// show the edit button when user has correct access level
if
{
Button btnEdit = (Button)e.Row.FindControl("ShowEditButton");
Button btndelete = (Button)e.Row.FindControl("ShowDeleteButton");
btnEdit.Visible = true;
btndelete.Visible = true;
}
}
}
I am trying to check to see if the user has edit access if they do show the buttons
any help appreciated
Something like that:
protected bool AccessLevels()
{
LINQDataContext dc = new LINQDataContext();
return dc.UserPermissions.Where(a => a.ID == (int)Session["Permission"]).SingleOrDefault().AllowStockEdit;
}
protected void SelectedStockGridView_RowDataBound(Object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
// show the edit button when user has correct access level
if(AccessLevels() == true)
{
Button btnEdit = (Button)e.Row.FindControl("ShowEditButton");
Button btndelete = (Button)e.Row.FindControl("ShowDeleteButton");
btnEdit.Visible = true;
btndelete.Visible = true;
}
}
}

Metro App OnNavigatedTo setting textbox value in a different method

I am following around on a kindle book I bought for developing metro apps. For some reason I cannot set the text value of a text box in a method outside the OnNavigatedTo method. This is the code that the book provides:
protected override void OnNavigatedTo(NavigationEventArgs e)
{
//passed in the view model
viewModel = e.Parameter as ViewModel;
this.DataContext = viewModel;
viewModel.PropertyChanged += (sender, eventArgs) =>
{
if (eventArgs.PropertyName == "SelectedItemIndex")
{
if (viewModel.SelectedIndex == -1)
{
SetItemDetail(null);
}
else
{
SetItemDetail(viewModel.GroceryList[viewModel.SelectedIndex]);
}
}
SetItemDetail(viewModel.GroceryList[viewModel.SelectedIndex]);
};
}
private void SetItemDetail(GroceryItem item)
{
ItemDetailName.Text = "test"; //(item == null) ? "" : item.Name;
ItemDetailQuantity.Text = "test"; //(item == null) ? "" : item.Quantity.ToString();
//if (item != null)
//{
// ItemDetailStore.SelectedItem = item.Store;
//}
//else
//{
// ItemDetailStore.SelectedIndex = -1;
//}
}
I have commented parts out in the set item detail method, but I still cannot set the value of a textbox when I click it (this is supposed to be the behavior). I have used break points and the property of the textbox is getting set, however, it is not displayed on screen.
Thanks.

Resources