Context Action Menu Item not working in iOS PCL Project - c#

I'm making an MenuItem dynamic in a PCL project, constructing this when the list view are appearing.
This is my xaml:
<ListView x:Name="ListParceiros" RowHeight="60" ItemTapped="Parceiros_Tapped" Style="{StaticResource listViewGlobalStyle}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell Appearing="OnItemAppearing">
<StackLayout Orientation="Horizontal" HorizontalOptions="Fill" BackgroundColor="#fff">
<StackLayout Orientation="Vertical">
<Label Text = "{Binding Nome}" FontSize="24" AbsoluteLayout.LayoutBounds="0.25, 0.25, 400, 40"/>
<Label Text = "{Binding CpfCnpj}" AbsoluteLayout.LayoutBounds="50, 35, 200, 25"/>
</StackLayout>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
And my cs file:
private void OnItemAppearing(object sender, EventArgs e)
{
ViewCell theViewCell = (ViewCell)sender;
var item = theViewCell.BindingContext as Pessoa;
theViewCell.ContextActions.Clear();
if (item != null)
{
var pessoaVinculo = _pessoaVinculoRepository.Get(w => w.PessoaId == item.PessoaId && w.NegocioId == App.CurrentUser.NegocioId);
if (pessoaVinculo.NegocioAtivo)
{
var desativarAction = new MenuItem { Text = "Desativar", IsDestructive = true };
desativarAction.SetBinding(MenuItem.CommandParameterProperty, new Binding("."));
desativarAction.Clicked += DesativarParceiro;
var servicoAction = new MenuItem { Text = "Serviços" };
servicoAction.SetBinding(MenuItem.CommandParameterProperty, new Binding("."));
servicoAction.Clicked += CallServicos;
theViewCell.ContextActions.Add(desativarAction);
theViewCell.ContextActions.Add(servicoAction);
}
else
{
var aceitarVinculoAction = new MenuItem { Text = "Aceitar Vinculo" };
aceitarVinculoAction.SetBinding(MenuItem.CommandParameterProperty, new Binding("."));
aceitarVinculoAction.Clicked += AceitarConvite;
theViewCell.ContextActions.Add(aceitarVinculoAction);
}
}
}
When I try to access the MenuItem in Android it's work fine, but in iOS the MenuItem are not working.
How could i make this work?

This can be solved using two DataTemplates, one for each case, each one with the needed ContextActions, then use DataTemplateSelector to show the right DataTemplate.
Create your DataTemplateSelector and override the OnSelectTemplate method returning the right DataTemplate depending on your condition (pessoaVinculo.NegocioAtivo in your case).
Know more about DataTemplateSelector in
https://developer.xamarin.com/guides/xamarin-forms/templates/data-templates/selector

Related

Binding properties to a ListView in Xamarin, does not update the View

I am having trouble, with binding properties to a ListView in Xamarin Forms. What I am trying to do is:
{
InitializeComponent();
//Task.Run(async () => await GetTaskDetails());
GetTasks();
}
ObservableCollection<XMCTasks> _userTasks;
private async void GetTasks()
{
using (var client = new HttpClient())
{
string userId = "";
if(Application.Current.Properties["userId"] != null)
{
userId = Application.Current.Properties["userId"].ToString();
}
var uri = "http://diplomaxmcws-dev.us-east-2.elasticbeanstalk.com/api/Tasks/GetUserTasks?userId=" + userId;
var result = await client.GetStringAsync(uri);
var TaskList = JsonConvert.DeserializeObject<List<XMCTasks>>(result);
UserTasks = new ObservableCollection<XMCTasks>(TaskList);
}
}
public ObservableCollection<XMCTasks> UserTasks
{
get
{
return _userTasks;
}
set
{
_userTasks = value;
OnPropertyChanged();
}
}
Getting a list of objects from a Rest API call, and after that binding those objects to a ListView:
<ListView ItemsSource="{Binding UserTasks}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<ViewCell.View>
<StackLayout>
<!-- <Label Text="{Binding XMCTask_Id, StringFormat='XMCTask_Id: {0:F0)}'}"></Label> -->
<Label Text="{Binding Task_Name, StringFormat='Task_Name: {0:F0)}'}" TextColor="Black" FontSize="Medium"></Label>
<!-- <Label Text="{Binding Task_Description, StringFormat='Task_Description: {0:F0)}'}"></Label>
<Label Text="{Binding Creator_Id, StringFormat='Creator_Id: {0:F0)}'}"></Label>
<Label Text="{Binding Referencer_Id, StringFormat='Referencer_Id: {0:F0)}'}"></Label>
<Label Text="{Binding XMCPune_Id, StringFormat='XMCPune_Id: {0:F0)}'}"></Label>
<Label Text="{Binding XMCProjekt_Id, StringFormat='XMCProjekt_Id: {0:F0)}'}"></Label>
<Button Text="{Binding XMCTipologjia_Id, StringFormat='XMCTipologjia_Id: {0:F0)}'}"></Button>-->
</StackLayout>
</ViewCell.View>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
I don't know if it has to do with the lifecycle of a Xamarin Forms Page. Just to let you know, this page gets loaded after a successful login. Since the process of getting the results from the web service is async it may be possible something to get messed up. Any approach is much appreciated.
The BindingContext property of the target object must be set to the source object.
If you want to use ItemsSource="{Binding UserTasks} in the xaml,you should add BindingContext = this;in your page.cs constructor as Jason said above.
or you could define x:Name for your ListView in xaml,then set ItemSource in your page.cs:
<ListView x:Name="listview">
...
</ListView>
private async void GetTasks()
{
using (var client = new HttpClient())
{
string userId = "";
if(Application.Current.Properties["userId"] != null)
{
userId = Application.Current.Properties["userId"].ToString();
}
var uri = "http://diplomaxmcws-dev.us-east-2.elasticbeanstalk.com/api/Tasks/GetUserTasks?userId=" + userId;
var result = await client.GetStringAsync(uri);
var TaskList = JsonConvert.DeserializeObject<List<XMCTasks>>(result);
UserTasks = new ObservableCollection<XMCTasks>(TaskList);
listview.ItemsSource = UserTasks;
}
}

Xamarin CustomRenderer in ListView

I have a ListView that have a custom view inside it ViewCell.
This custom view is a Label that render an HTML content.
All works, except when a ViewCell exit from the screen the label lost th HTML format and show the HTML tags.
This is the custom renderer in IOS (same problem on Android):
[assembly: ExportRenderer(typeof(LabelHtmlView), typeof(LabelHtmlCustomRenderer))]
namespace SgatMobileV2.iOS {
public class LabelHtmlCustomRenderer : LabelRenderer {
protected override void OnElementChanged(ElementChangedEventArgs<Label> e) {
base.OnElementChanged(e);
var View = (LabelHtmlView)Element;
if (View == null) return;
var Attribute = new NSAttributedStringDocumentAttributes();
var NsError = new NSError();
Attribute.DocumentType = NSDocumentType.HTML;
Control.AttributedText = new NSAttributedString(View.Text, Attribute, ref NsError);
}
}
}
This is the ListView code:
<ListView x:Name="ListaRigheWo" CachingStrategy="RecycleElement"
HasUnevenRows="True" SeparatorVisibility="Default"
ItemsSource="{Binding ListaWORighe}">
[...]
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid>
[...]
<view:LabelHtmlView
Text="{Binding DescrizioneIntervento}" Grid.Row="1" Grid.Column="2"
Grid.ColumnSpan="4" Style="{StaticResource LblValore}" />
How can I solve this?
Thank you!

c# uwp gridview items zindex

In UWP I have GridView. That GridView has ItemTemplate like this:
<Page.Resources>
<DataTemplate x:Key="Template" x:DataType="local:ModelClass">
<local:CustomUserControl
Model="{x:Bind Mode=OneWay}"/>
</DataTemplate>
</Page.Resources>
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<GridView x:Name="gvMain" ItemTemplate="{StaticResource Template}" SelectionChanged="gvMain_SelectionChanged">
<GridView.ItemsPanel>
<ItemsPanelTemplate>
<ItemsWrapGrid Orientation="Vertical"
Margin="0,0,0,-10"
MaximumRowsOrColumns="1"
ItemWidth="50"
ItemHeight="50"/>
</ItemsPanelTemplate>
</GridView.ItemsPanel>
</GridView>
</Grid>
The usercontrol is like this:
<Grid x:Name="gridMain" Width="50" Height="50">
<Grid VerticalAlignment="Top" HorizontalAlignment="Right" Margin="0, 0, -10, 0" Width="20" Height="20" Background="Pink"/>
</Grid>
And in codebehind:
public ModelClass Model
{
get { return (ModelClass)GetValue(ModelProperty); }
set { SetValue(ModelProperty, value); SetBackground(); }
}
public static readonly DependencyProperty ModelProperty =
DependencyProperty.Register("Model", typeof(ModelClass), typeof(CustomUserControl), new PropertyMetadata(new ModelClass()));
private void SetBackground()
{
if (Model == null)
{
return;
}
gridMain.Background = Model.BackgroundColor;
}
public CustomUserControl()
{
this.InitializeComponent();
}
I am populating the GridView like this:
List<ModelClass> list = new List<ModelClass>();
ModelClass mc = new ModelClass();
mc.BackgroundColor = new SolidColorBrush(Colors.Red);
ModelClass mc1 = new ModelClass();
mc1.BackgroundColor = new SolidColorBrush(Colors.Blue);
ModelClass mc2 = new ModelClass();
mc2.BackgroundColor = new SolidColorBrush(Colors.Yellow);
ModelClass mc3 = new ModelClass();
mc3.BackgroundColor = new SolidColorBrush(Colors.Green);
list.Add(mc);
list.Add(mc1);
list.Add(mc2);
list.Add(mc3);
gvMain.ItemsSource = list;
And what it looks like is this:
On each item there is a small square in upper right corner, colored in pink.
When I click on some item, I want that item to overlap every other items, so my pink square will be visible.
How to change Z-index of GridView items in this case?
How to change Z-index of GridView items in this case?
If you want to change the GridViewItem's Z-Index, you might think about using canvas relevant panel as the GridView's ItemsPanel.
Then, in your SelectionChanged event handler method, you could use the Canvas.SetZIndex(UIElement, index) method to set current selected item's Canvas.ZIndex. It would get your effect that you want.
But, if you used the general Canvas control as the GridView's ItemsPanel. You would find that the items would not be shown as the general items list.
As a result, in your case, you also would need to define your custom panel. You could need to rearrange the items in it.
I've made a simple for your reference:
<GridView x:Name="gvMain" SelectionChanged="gvMain_SelectionChanged">
<GridView.ItemsPanel>
<ItemsPanelTemplate>
<local:CustomPanel></local:CustomPanel>
</ItemsPanelTemplate>
</GridView.ItemsPanel>
<GridViewItem >
<Rectangle Fill="Red" Width="50" Height="50"></Rectangle>
</GridViewItem>
<GridViewItem >
<Rectangle Fill="Blue" Width="50" Height="50" ></Rectangle>
</GridViewItem>
<GridViewItem>
<Rectangle Fill="Yellow" Width="50" Height="50"></Rectangle>
</GridViewItem>
</GridView>
public class CustomPanel:Canvas
{
protected override Size MeasureOverride(Size availableSize)
{
Size s = base.MeasureOverride(availableSize);
foreach (UIElement element in this.Children)
{
element.Measure(availableSize);
}
return s;
}
protected override Size ArrangeOverride(Size finalSize)
{
this.Clip = new RectangleGeometry { Rect = new Rect(0, 0, finalSize.Width, finalSize.Height) };
Double position = 0d;
foreach (UIElement item in this.Children)
{
if (item == null)
continue;
Size desiredSize = item.DesiredSize;
if (double.IsNaN(desiredSize.Width) || double.IsNaN(desiredSize.Height)) continue;
var rect = new Rect(0, position, desiredSize.Width, desiredSize.Height);
item.Arrange(rect);
TranslateTransform compositeTransform = new TranslateTransform();
compositeTransform.X = position / 2;
item.RenderTransform = compositeTransform;
position += desiredSize.Width;
}
return finalSize;
}
}
private void gvMain_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
GridViewItem item = (sender as GridView).SelectedItem as GridViewItem;
if (item != null)
{
Canvas.SetZIndex(item,index);
}
}
This just is a simple code sample, you could do more custom behavior in your custom panel.
The following are the effect screenshots:

Xaml - Unable to get item Name in class file (inside listView)

I'm making an XAML app and i'm having some issues binding my xaml file with its class .
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage
x:Class="App.TestXaml"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml">
<ContentPage.Content>
<ListView x:Name="ListTest">
<Label FontSize="12" x:Name="test1"/>
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Spacing="5" Orientation="Horizontal">
<Label FontSize="14" x:Name="test2"/>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ContentPage.Content>
</ContentPage>
in my cs file testXaml.cs thats linked to this xaml :
test1.FontSize = 20 ;
// Works - it detects the test1 variable for that label.
In my listview however , when i try to access the label named test2 , it does not detect it in my cs file
test2.FontSize = 24 ;
// The class does not detect test2 (The name test2 does not exist in the current context)
Any idea how to fix this or set up a value for the list items from my cs file ?
You can't access the controls that are inside the itemtemplate by their name.
You have 2 options
Use a property in the binded item for the font size and bind it to the fontsize of the control. I think this is more clean solution.
Use triggers as described by #ed
But i would definetely go with Mvvm
If you need more programmatic decision here is another option.
Derive MyViewCell from ViewCell and your xml will look the same except MyViewCell and I added binding to show something. You will need to add local code reference to use MyViewCell in xaml
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:ButtonRendererDemo;assembly=ButtonRendererDemo"
x:Class="ButtonRendererDemo.ListCellAccessPage">
<ContentPage.Content>
<ListView x:Name="ListTest" HasUnevenRows="true">
<Label FontSize="12" x:Name="test1"/>
<ListView.ItemTemplate>
<DataTemplate>
<local:MyViewCell>
<StackLayout Spacing="5" Orientation="Horizontal">
<Label FontSize="14" x:Name="test2" Text="{Binding Name}"/>
</StackLayout>
</local:MyViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ContentPage.Content>
</ContentPage>
Now here is the code behind
namespace ButtonRendererDemo
{
public partial class ListCellAccessPage : ContentPage
{
MyListItem[] listItems = new MyListItem[]
{
new MyListItem { Name= "1" },
new MyListItem{Name= "2" },
new MyListItem{Name= "3" },
new MyListItem{Name= "4" }
};
public ListCellAccessPage()
{
InitializeComponent();
test1.Text = "List";
ListTest.ItemsSource = listItems;
}
}
class MyListItem
{
public string Name { get; set; }
}
class MyViewCell : ViewCell
{
protected override void OnChildAdded(Element child)
{
base.OnChildAdded(child);
var label = child.FindByName<Label>("test2");
if (label != null)
{
label.PropertyChanged -= Label_PropertyChanged1;//unsubscribe in case of cell reuse
label.PropertyChanged += Label_PropertyChanged1;
}
private void Label_PropertyChanged1(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
var label = sender as Label;
if ((label != null) && (e.PropertyName == "Text"))
{
if (label.Text == "3")
label.FontSize = 48;
else
label.FontSize = 14;//in case of cell reuse
}
}
}
}
So, it examines the content of your cell and if it is confirms certain condition (in this case name is 3) it sets the font. Here is the screenshot

Reach a TextBlock from a specific ListViewItem from the ListView in Windows Phone 8.1 XAML programmatically

I am a new developer on Windows Phone 8.1, I am try to reach a specific ListView item from the ListView collection and be able to color it or color the TextBock inside of it, But I can't reach the item or reach any of items inside of ListView, Please take a look for my below code :
protected async override void OnNavigatedTo(NavigationEventArgs e)
{
SQLiteRT db1 = new SQLiteRT();
var db_connection = await db1.Connection("MyDB.sqlite");
List<MyTBL> t_list = db1.GetTable("SELECT * FROM MyTBL LIMIT 4 ORDER BY RANDOM() ;");
db_connection.Close();
LV_Options.ItemsSource = t_list;
}
// my List View called LV_Options
private void LV_Options_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
ListView lv1 = sender as ListView;
if (lv1 == null)
return;
MyTBL wrd = lv1.SelectedItem as MyTBL;
if (wrd == null)
return;
TextBlock tb = lv1.FindName("TB_AMean1") as TextBlock;
tb.FontSize = 17; // here I got debug error (it not worked !!!!!!!)
var item = LV_Options.Items.ElementAt(3); // this seems not work also !!!!
item.BackColor = Color.LightSteelBlue;
}
As you can see above, I tried to reach a specific item by LV_Options.Items.ElementAt(3) but it doesn't work! I also tried to reach the TextBlock from the selected List view item, but also not worked !
(Updated)
XAML code :
<!-- Title Panel -->
<StackPanel Grid.Row="0" Margin="19,0,0,0">
<TextBlock Name="TB_Rslt" Text="Here result of your answer" Style="{ThemeResource TitleTextBlockStyle}" Margin="0,12,0,0"/>
<TextBlock Text="page title" Margin="0,-6.5,0,26.5" Style="{ThemeResource HeaderTextBlockStyle}" CharacterSpacing="{ThemeResource PivotHeaderItemCharacterSpacing}"/>
</StackPanel>
<!--TODO: Content should be placed within the following grid-->
<Grid Grid.Row="1" x:Name="ContentRoot" Margin="19,10,19,15">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<TextBlock Name="TB_Question" Text="Choose Answer " Margin="0,0,25,0" HorizontalAlignment="Right" FontWeight="Bold" FontSize="22" FontFamily="Verdana" RenderTransformOrigin="0.5,0.5" />
<TextBlock Name="TB_EnWord" Text="" Margin="90,0,15,0" HorizontalAlignment="Left" FontWeight="Bold" FontSize="22" FontFamily="Verdana" RenderTransformOrigin="0.5,0.5" TextAlignment="Right" />
<StackPanel Grid.Row="1" Margin="5,22,0,0">
<ListView Name="LV_Options" SelectionChanged="LV_Options_SelectionChanged">
<ListView.ItemTemplate>
<DataTemplate>
<Grid Margin="6">
<StackPanel VerticalAlignment="Top" Margin="10,0,0,0">
<TextBlock Name="TB_AMean1" Text="{Binding AMean1}" TextWrapping="Wrap"/>
</StackPanel>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackPanel>
<Button Name="Btn_Answer" Content="Ansewr" HorizontalAlignment="Left" Grid.Row="1" VerticalAlignment="Bottom" Click="Btn_Answer_Click"/>
My application is a quiz application that offer 4 choices/options as answers for each question, and when user select a true answer, I want to highlight the true answer(true choice) by make its background to green, and if the user selected wrong answer/option I want to make the background of that answer (a specific List View item) with red.
Any help please ?
You're not going to be able to access an element inside a data template like that. Instead, leverage the binding to a view model to set the color and other view-related properties. First, create a wrapper view model for your data class:
public class MyTBLViewModel : INotifyPropertyChanged
{
public MyTBL Entity
{
get { return _entity; }
}
private readonly MyTBL _entity;
public Brush Highlight
{
get { return _brush; }
set
{
_brush = value;
RaisePropertyChanged("Highlight");
}
}
private Brush _highlight;
public double ItemFontSize
{
get { return _itemFontSize; }
set
{
_itemFontSize = value;
RaisePropertyChanged("ItemFontSize");
}
}
private Brush _itemFontSize;
public MyTBLViewModel(MyTBL entity)
{
_entity = entity;
_highlight = new SolidColorBrush(Colors.Transparent);
_itemFontSize = 12;
}
public event PropertyChangedEventArgs PropertyChanged;
protected void RaisePropertyChanged(string propName)
{
var handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propName));
}
}
Use this as your ItemsSource:
List<MyTBLViewModel> t_list = db1.GetTable("SELECT * FROM MyTBL LIMIT 4 ORDER BY RANDOM() ;")
.AsEnumerable().Select(entity => new MyTBLViewModel(entity)).ToList();
Now in your view, bind the view elements to "Highlight" and "ItemFontSize", and to any other properties you like:
<ListView.ItemTemplate>
<DataTemplate>
<Grid Margin="6" Background="{Binding Highlight}">
<StackPanel VerticalAlignment="Top" Margin="10,0,0,0">
<TextBlock Name="TB_AMean1" Text="{Binding Entity.AMean1}" TextWrapping="Wrap"
FontSize="{Binding ItemFontSize}"/>
</StackPanel>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
Finally, you can get the data item from the SelectionChangedEventArgs -- use it to update your view-related properties:
private void LV_Options_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
foreach (var item in e.AddedItems.OfType<MyTBLViewModel>())
{
item.Highlight = new SolidColorBrush(Color.LightSteelBlue);
item.ItemFontSize = 17;
}
foreach (var item in e.RemovedItems.OfType<MyTBLViewModel>())
{
item.Highlight = new SolidColorBrush(Colors.Transparent);
item.ItemFontSize = 12;
}
}
var item = LV_Options.Items.ElementAt(3);
This line is incorrect. It will not return you a TextBlock. I don't know what a .BackColor is, and it should not compile. The Items property in a ListView will return you a list of ListViewItems. If you want to access the inside element from a ListViewItem, you'll need to access the ContentTemplateRoot property.
Do not use var ever. It lets you assume that you know the type, whereas if you explicitly typed the declaration you would realize you're doing it wrong.
MyTBL wrd = lv1.SelectedItem as MyTBL;
if (wrd == null)
return;
TextBlock tb = lv1.FindName("TB_AMean1") as TextBlock;
What is a MyTBL type? FindName is only available to framework DependencyObjects so I'm assuming it's a user control? You have to provide a lot more code to show us what you're doing and what you're setting the ListView's ItemsSource and ItemTemplate with and what these errors are and how you have 2 breaking debug errors at once and what the error messages are.
Comprehending runtime error messages is a huge part of being a good developer.

Categories