Why is MenuFlyout.Items always null in Closing event? - xaml

I can successfully add a MenuFlyoutItem to a MenuFlyout dynamically in the ContextMenuFlyout_Opening event, but when I try to remove it in ContextMenuFlyout_Closing the MenuFlyout.Items is always null and the MFI isnt found and removed.
Any ideas why this is so?
<Page.Resources>
<MenuFlyout
x:Key="ListViewContextMenu"
Closing="{x:Bind ViewModel.ContextMenuFlyout_Closing}"
Opening="{x:Bind ViewModel.ContextMenuFlyout_Opening}">
<MenuFlyoutItem
Click="{x:Bind ViewModel.EditParty}"
Icon="Edit"
Text="Edit" />
<MenuFlyoutItem Text="Open in new window">
<MenuFlyoutItem.Icon>
<FontIcon
FontFamily="Segoe MDL2 Assets"
FontSize="40"
Glyph="" />
</MenuFlyoutItem.Icon>
</MenuFlyoutItem>
<MenuFlyoutSeparator />
<MenuFlyoutItem
Click="MenuFlyoutItem_Click"
Icon="Delete"
Text="Delete" />
</MenuFlyout>
</Page.Resources>
ViewModel event handlers
public void ContextMenuFlyout_Opening(object sender, object e)
{
MenuFlyout flyout = sender as MenuFlyout;
if (flyout != null)
{
// If party.IsConflict = true then add the MFI
if (SelectedTalent.IsConflict)
{
flyout.Items.Add(new MenuFlyoutItem()
{
Icon = new FontIcon() { Glyph = "\uEC4F" },
Text = "Resolve Conflict"
});
}
}
}
public void ContextMenuFlyout_Closing(object sender, object e)
{
// Remove 'Resolve Conflict' MFI if its found
MenuFlyout flyout = sender as MenuFlyout;
if (flyout != null)
{
var rc = flyout.Items.FirstOrDefault(o => o.Name == "Resolve Conflict");
if (rc != null)
{
flyout.Items.Remove(rc);
}
}
}
ListView that uses the MenuFlyout
<ListView
ContextFlyout="{StaticResource ListViewContextMenu}"

Based on your code, it seems that you are trying to get the MenuFlyoutItem object by name. But you forget to give the MenuFlyoutItem object a Name when you add it to the MenuFlyout, you just added a Text property.
flyout.Items.Add(new MenuFlyoutItem()
{
Icon = new FontIcon() { Glyph = "\uEC4F" },
Text = "Resolve Conflict",
Name = "Resolve Conflict",
});

Related

Refresh xaml page every x seconds and keep the current expander state

I have a xamarin project. There is a scrollview with a list of expanders.
I like to refresh the page every x seconds, but keep the state of my expanders (isExpanded boolean).
How do I check the state of my expanders (or label, button, whatever) and keep these values during a refresh every x seconds?
I feel like I have to add a parameter to my behindcode function, similar to the 'object sender' during a tap or click event.
In the behindcode I am trying to refresh the page every x seconds with
Device.StartTimer(TimeSpan.FromSeconds(x),Updatefunction);
Currently they all have their default isExpanded (false) state when the page refreshes.
You can add a bool property in the viewModel, then binding this property to IsExpanded="{Binding Expand1Opened}" in <Expander> tab. When user click the Expander, IsExpanded will depend on the value of Expand1Opened property. no matter the refresh the page every x seconds, it will keep the current expander state. And I add Command for Expander, if Expander is clicked, value of Expand1Opened property will be changed in the ViewModel.
<RefreshView IsRefreshing="{Binding IsRefreshing}"
RefreshColor="Teal"
Command="{Binding RefreshCommand}">
<ScrollView>
<StackLayout>
<Expander IsExpanded="{Binding Expand1Opened}" Command="{Binding Expand1OpenedCommand}">
<Expander.Header>
<Label Text="List1"
FontAttributes="Bold"
FontSize="Medium" />
</Expander.Header>
<Grid Padding="10">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<FlexLayout Direction="Row"
Wrap="Wrap"
AlignItems="Center"
AlignContent="Center"
BindableLayout.ItemsSource="{Binding Items}"
BindableLayout.ItemTemplate="{StaticResource ColorItemTemplate}" />
</Grid>
</Expander>
<Expander IsExpanded="{Binding Expand2Opened}" Command="{Binding Expand2OpenedCommand}">
<Expander.Header>
<Label Text="List2"
FontAttributes="Bold"
FontSize="Medium" />
</Expander.Header>
<Grid Padding="10">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<FlexLayout Direction="Row"
Wrap="Wrap"
AlignItems="Center"
AlignContent="Center"
BindableLayout.ItemsSource="{Binding Items}"
BindableLayout.ItemTemplate="{StaticResource ColorItemTemplate}" />
</Grid>
</Expander>
</StackLayout>
</ScrollView>
</RefreshView>
Here is viewModel. I have two <Expander>, So I add two properties Expand1Opened and Expand2Opened, and add two Commands called Expand1OpenedCommand and Expand2OpenedCommand, if the <Expander> were clicked, Expand1OpenedCommand will be invoked, then value of Expand1Opened will be changed, If the refreshview was refreshed, value of Expand1Opened will not be changed, so expander's state wil be kept.
public class MainPageViewModel : INotifyPropertyChanged
{
const int RefreshDuration = 2;
int itemNumber = 1;
readonly Random random;
bool isRefreshing;
public bool IsRefreshing
{
get { return isRefreshing; }
set
{
isRefreshing = value;
OnPropertyChanged();
}
}
bool expand1Opened = false;
public bool Expand1Opened
{
get { return expand1Opened; }
set
{
expand1Opened = value;
OnPropertyChanged();
}
}
bool expand2Opened=false;
public bool Expand2Opened
{
get { return expand2Opened; }
set
{
expand2Opened = value;
OnPropertyChanged();
}
}
public ObservableCollection<Item> Items { get; private set; }
public ICommand RefreshCommand => new Command(async () => await RefreshItemsAsync());
public ICommand Expand1OpenedCommand { get; set; }
public ICommand Expand2OpenedCommand { get; set; }
public MainPageViewModel()
{
random = new Random();
Items = new ObservableCollection<Item>();
Expand1OpenedCommand = new Command((() =>
{
expand1Opened = !expand1Opened;
}));
Expand2OpenedCommand = new Command((() =>
{
expand2Opened = !expand2Opened;
}));
AddItems();
}
void AddItems()
{
for (int i = 0; i < 1; i++)
{
Items.Add(new Item
{
Color = Color.FromRgb(random.Next(0, 255), random.Next(0, 255), random.Next(0, 255)),
Name = $"Item {itemNumber++}",
Isfavourite = false
});
}
}
async Task RefreshItemsAsync()
{
IsRefreshing = true;
await Task.Delay(TimeSpan.FromSeconds(RefreshDuration));
AddItems();
IsRefreshing = false;
}
#region INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
}
}
Here is running GIF.

Keep highlighting the cell when user deselect

I'm using Xamarin Forms ListView as a SideBar. How can I prevent users from deselecting cell? Or at least keep highlighting the cell when users deselect it.
This is how I'm binding
<ListView x:Name="listView" SelectionMode="Single">
<ListView.ItemsSource>
<x:Array Type="{x:Type x:String}">
<x:String>Management</x:String>
<x:String>Information</x:String>
<x:String>Language</x:String>
<x:String>Settings</x:String>
</x:Array>
</ListView.ItemsSource>
<ListView.ItemTemplate>
<DataTemplate>
<TextCell Text="{Binding}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
According to your description, when you select item from ListView, this item highlighting, you want to this item still highlighting when this item is not selected state. It seems that you want to select multiple item from ListView.
I've made a sample, you can take a look:
<ContentPage.Content>
<StackLayout>
<ListView
ItemTapped="ListView_ItemTapped"
ItemsSource="{Binding Items}"
SelectionMode="Single">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout BackgroundColor="{Binding background}" Orientation="Horizontal">
<Label
HorizontalOptions="StartAndExpand"
Text="{Binding DisplayName}"
TextColor="Fuchsia" />
<BoxView
HorizontalOptions="End"
IsVisible="{Binding Selected}"
Color="Fuchsia" />
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ContentPage.Content>
public partial class Page10 : ContentPage
{
public Page10 ()
{
InitializeComponent ();
this.BindingContext = new MultiSelectItemsViewModel();
}
private void ListView_ItemTapped(object sender, ItemTappedEventArgs e)
{
Model m = e.Item as Model;
if(m!=null)
{
m.Selected = !m.Selected;
if(m.background==Color.White)
{
m.background = Color.BlueViolet;
}
else
{
m.background = Color.White;
}
}
}
}
public class Model:ViewModelBase
{
public string DisplayName { get; set; }
private bool _Selected;
public bool Selected
{
get { return _Selected; }
set
{
_Selected = value;
RaisePropertyChanged("Selected");
}
}
private Color _background;
public Color background
{
get { return _background; }
set
{
_background = value;
RaisePropertyChanged("background");
}
}
}
public class MultiSelectItemsViewModel
{
public ObservableCollection<Model> Items { get; set; }
public MultiSelectItemsViewModel()
{
Items = new ObservableCollection<Model>();
Items.Add(new Model() { DisplayName = "AAA", Selected = false,background=Color.White });
Items.Add(new Model() { DisplayName = "BBB", Selected = false , background = Color.White });
Items.Add(new Model() { DisplayName = "CCC", Selected = false, background = Color.White });
Items.Add(new Model() { DisplayName = "DDD", Selected = false, background = Color.White });
Items.Add(new Model() { DisplayName = "EEE", Selected = false, background = Color.White });
}
}
Update:
Don't allow user to unselect the selected item.
private void ListView_ItemTapped(object sender, ItemTappedEventArgs e)
{
Model m = e.Item as Model;
if(m!=null)
{
m.Selected = true;
m.background = Color.Blue;
}
}
Depending on your needs, I've done something similar but with controls inside each row, like a checkbox.
https://xamarinhelp.com/multiselect-listview-xamarin-forms/
Use the SelectedItem property of the ListView. As long as SelectedItem property is not set back to null, the currently selected item will remain highlighted.

Xamarin Forms Navigation page searchbar entries unable to write

I have two pages MainPage and SecondPage1 .in App.xaml.cs I Navigate to Secondpage1 using this code:
App.xaml.cs :
//MainPage = new Fmkt44Application.MainPage();/*First Approach*/
MainPage = new NavigationPage(new MainPage());/*Second approach*/
MainPage.xaml.cs:
// App.Current.MainPage = new NavigationPage(new SecondPage1());/*First Approach*/
await Navigation.PushAsync(new SecondPage1());/*Second approach*/
Problem is if I use both approaches I can navigate to secondpage1 but if I use second approach I cant write on searchbar or any entries. What is the reason and how can I Fix it?
Here is MainPage.xaml.cs
namespace Fmkt44Application
{
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
}
public async System.Threading.Tasks.Task LoginControlAsync(Object sender, EventArgs args)
{
User.UserName = entry_user.Text;
User.Password = entry_passw.Text;
if (User.CheckUserInformation() == false)
{
DisplayAlert("Login", "Kullanıcı Adını veya şifresini giriniz", "OK");
}
else
{
String val = entry_user.Text + "$" + entry_passw.Text;
CallIasWebService.Login();
String rval = CallIasWebService.CallIASService("PROFILECONTROL", val);
CallIasWebService.Logout();
User.Profile = rval.ToString();
if (rval != "0" )
{
if (User.Profile != "" && User.Profile != null)
{
// App.Current.MainPage = new NavigationPage(new SecondPage1());if I Call Like this I can write on Secondpage1 (First approach)
await Navigation.PushAsync(new SecondPage1());/*I cannot reach SecondPage1 controls/* (second approach)*/
}
else
{
DisplayAlert("Login", "Kayıt yapma yetkiniz yoktur.", "OK");
}
}
else
{
DisplayAlert("Login", "Kullanıcı Adını veya şifresi hatalıdır.", "OK");
}
}
}
public async System.Threading.Tasks.Task scanncontrolAsync(Object sender, EventArgs E)
{
// await Navigation.PushAsync(new SecondPage1());
App.Current.MainPage = new SecondPage1();
}
}
}
App.cs is
public App ()
{
InitializeComponent();
//MainPage = new Fmkt44Application.MainPage();(First apploach)
MainPage = new NavigationPage(new MainPage());/*second approach*/
}
Secondpage1.xaml is
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Fmkt44Application.SecondPage1">
<ContentPage.Content>
<StackLayout>
<SearchBar Placeholder="Ara..." TextChanged="TextChange" x:Name="searchbar" />
<ListView x:Name="Materials" ItemTapped="MakineSec" HasUnevenRows="True">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout>
<StackLayout Orientation="Horizontal" >
<Label Text="{Binding Material}"/>
<Label Text="{Binding Stext}"/>
</StackLayout>
<Entry Text="{Binding SerialNumber}" />
</StackLayout>
<ViewCell.ContextActions>
<MenuItem Text="Seç" Clicked="MakineSec" CommandParameter="{Binding .}"/>
</ViewCell.ContextActions>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ContentPage.Content>
Problem comes from Android Emulator. I tried a real tablet problem solved.

How can I set up binding context in XAML to a different class?

I've got this code I'm trying to bind to a class named BandInfoRepository.cs which is located in the same folder as this XAML named PaginaB.I can't see no syntax error displayed on VisualStudio, still the text is not showing(I added backgroundColor just to see if the label was being displayed and they are, but the text isn't).
Maybe it's important to point out I'm using syncfusion's listview.
PaginaB.xaml :
<syncfusion:SfListView x:Name="listView"
ItemsSource="{Binding Source={local2:BandInfoRepository}, Path=BandInfo}"
ItemSize="100"
AbsoluteLayout.LayoutBounds="1,1,1,1"
AbsoluteLayout.LayoutFlags="All" >
<syncfusion:SfListView.ItemTemplate>
<DataTemplate>
<Grid Padding="10">
<Grid.RowDefinitions>
<RowDefinition Height="0.4*" />
<RowDefinition Height="0.6*" />
</Grid.RowDefinitions>
<Label Text="{Binding Source={local2:BandInfoRepository}, Path=BandName}"
BackgroundColor="Olive"
FontAttributes="Bold"
TextColor="Black"
FontSize="20" />
<Label Grid.Row="1"
BackgroundColor="Navy"
Text="{Binding Source={local2:BandInfoRepository}, Path= BandDescription}"
TextColor="Black"
FontSize="14"/>
</Grid>
</DataTemplate>
</syncfusion:SfListView.ItemTemplate>
</syncfusion:SfListView>
And this is the BandInfoRepository.cs file:
public class BandInfoRepository
{
private ObservableCollection<BandInfo> bandInfo;
public ObservableCollection<BandInfo> BandInfo
{
get { return bandInfo; }
set { this.bandInfo = value; }
}
public BandInfoRepository()
{
GenerateBookInfo();
}
internal void GenerateBookInfo()
{
bandInfo = new ObservableCollection<BandInfo>();
bandInfo.Add(new BandInfo() { BandName = "Nirvana", BandDescription = "description" });
bandInfo.Add(new BandInfo() { BandName = "Metallica", BandDescription = "description" });
bandInfo.Add(new BandInfo() { BandName = "Frank Sinatra", BandDescription = "description" });
bandInfo.Add(new BandInfo() { BandName = "B.B. King", BandDescription = "description" });
bandInfo.Add(new BandInfo() { BandName = "Iron Maiden", BandDescription = "description" });
bandInfo.Add(new BandInfo() { BandName = "Megadeth", BandDescription = "description" });
bandInfo.Add(new BandInfo() { BandName = "Darude", BandDescription = "description" });
bandInfo.Add(new BandInfo() { BandName = "Coldplay", BandDescription = "description" });
bandInfo.Add(new BandInfo() { BandName = "Dream Evil", BandDescription = "description" });
bandInfo.Add(new BandInfo() { BandName = "Pentakill", BandDescription = "description" });
}
}
In your DataTemplate you don't set Source in binding normally, unless you want to do some magic. XAML sets DataContext to each item of ItemsSource.
Try:
<Label Text="{Binding BandName}" BackgroundColor="Olive" FontAttributes="Bold" />
and remember to implement INotifyPropertyChanged for BandInfo if you want XAML to track changes in its properties
Thank you for using Syncfusion Products.
We looked into you code and found that you have defined the ItemTemplate wrongly. You can bind the data objects in the underlying collection directly into the view defined in the ItemTemplate property. SfListView itself creates a view for each items in the ItemsSource property and defines the binding context to it.
For your reference, we have attached the sample and you can download it from the below link.
Sample: http://www.syncfusion.com/downloads/support/directtrac/general/ze/ListViewSample607957192
For more information about working with SfListView, please refer the following UG documentation link.
https://help.syncfusion.com/xamarin/sflistview/getting-started
Please let us know if you require further assistance.
Regards,
Dinesh Babu Yadav

Enable and disable buttons in the AppBar using Binding

I have an applicationbar with 2 buttons "edit" and "save" on a xaml page.
When the pages is loaded the "edit" button has to be enabled and the "save" button disabled.
When you press the "edit" button the "save" button gets enabled same for when you press the "save" button.
The problem is that both buttons are disabled when the page is loaded.
My code:
Button properties:
private bool _editButtonIsEnabled;
public bool EditButtonIsEnabled
{
get
{
return _saveButtonIsEnabled;
}
set
{
_editButtonIsEnabled = value;
RaisePropertyChanged("EditButtonIsEnabled");
}
}
private bool _saveButtonIsEnabled;
public bool SaveButtonIsEnabled
{
get
{
return _saveButtonIsEnabled;
}
set
{
_saveButtonIsEnabled = value;
RaisePropertyChanged("SaveButtonIsEnabled");
}
}
Xaml page with binding:
<Sh:AdvancedApplicationBar>
<Grid>
<Sh:AdvancedApplicationBarIconButton Text="edit"
IconUri="/Assets/ActionBarButtons/btn_actionbar_edit.png"
Command="{Binding EditFavorithProgramsCommand}"
VerticalAlignment="Bottom"
IsEnabled="{Binding EditButtonIsEnabled}"/>
<Sh:AdvancedApplicationBarIconButton Text="save"
IconUri="/Assets/ActionBarButtons/btn_actionbar_save.png"
Command="{Binding SaveFavorithProgramsCommand}"
VerticalAlignment="Bottom"
IsEnabled="{Binding SaveButtonIsEnabled}" />
</Grid>
</Sh:AdvancedApplicationBar>
you got a typo in your EditButtonIsEnabled getter
public bool EditButtonIsEnabled
{
get
{
return _saveButtonIsEnabled;
}
//...
}