Prism Button click command - mvvm

Im try to open Drawer menu (Syncfusion control) via Behaviors command
Xaml
<Button x:Name="hamburgerButton"
HeightRequest="50" WidthRequest="50"
HorizontalOptions="Start" FontSize="20"
BackgroundColor="#1aa1d6" >
<Button.Behaviors>
<b:EventToCommandBehavior EventName="Clicked"
Command="{Binding HamburgerButton}" />
</Button.Behaviors>
VM cs
public DelegateCommand HamburgerButton { get; private set; }
public QuickPartViewModel(INavigationService navigationService)
{
HamburgerButton = new DelegateCommand(HamburgerButton_Clicked);
}
public void HamburgerButton_Clicked(object sender, EventArgs e)
{
navigationDrawer.ToggleDrawer();
}
If HamburgerButton_Clicked(object sender, EventArgs e) with arguments then i have error -// Argumment: cannot convert from 'method group' to Action
if I'm remove Argumments it does't work

You're overthinking things. Just bind the command to the button.
in the page:
<Button Command="{Binding HamburgerCommand}" />
in the view model:
public QuickPartViewModel()
{
HamburgerCommand = new DelegateCommand(OnHamburger);
}
public DelegateCommand HamburgerCommand { get; }
private void OnHamburger()
{
navigationDrawer.ToggleDrawer();
}
Give the docs a try...

Related

How can I pass object while navigating? [duplicate]

This question already has an answer here:
How pass parameter when navigate to another page (Shell)
(1 answer)
Closed 4 months ago.
I have main page on which I have collection view. I want to navigate to next page after I click submit button .I am able to navigate to the next page but I also want total list of items which I have in my collection how can I achieve that?
I don't know the detail of your code, but you can try to pass the total list of items as the parameter of the next page.(suppose it's name is SecondPage)
You can refer to the following code:
MainPage.cs
public partial class MainPage : ContentPage
{
MyViewModel myViewModel;
public MainPage()
      {
            InitializeComponent();
myViewModel = new MyViewModel();
BindingContext = myViewModel;
}
      private void mCollectionView_SelectionChanged(object sender, SelectionChangedEventArgs e)
      {
string previous = (e.PreviousSelection.FirstOrDefault() as MyModel)?.Name;
string current = (e.CurrentSelection.FirstOrDefault() as MyModel)?.Name;
}
private async void Button_Clicked(object sender, EventArgs e)
{
// here we can pass the data we need.
var secondPage = new SecondPage(myViewModel.Data);
await Navigation.PushAsync(secondPage);
}
}
MainPage.xaml.cs
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="MauiCollectionApp.MainPage"
xmlns:local="clr-namespace:MauiCollectionApp"
x:Name="myPage"
>
<VerticalStackLayout>
<CollectionView ItemsSource="{ Binding Data}" x:Name="mCollectionView"
SelectionChanged="mCollectionView_SelectionChanged"
SelectionMode="Single"
>
<CollectionView.ItemTemplate>
<DataTemplate>
<HorizontalStackLayout Margin="3" >
<Label Text="{Binding Name}" BackgroundColor="Gray"/>
<Label Text="{Binding Car.Make}" Margin="5,0,5,0" />
<Button Text="delete" Margin="10,0,0,0"
BackgroundColor="Red"
Command="{Binding Path= BindingContext.RemoveEquipmentCommand,Source={Reference mCollectionView }}" CommandParameter="{Binding .}"
/>
</HorizontalStackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
<Button Text="submit" Clicked="Button_Clicked" Margin="10"/>
</VerticalStackLayout>
</ContentPage>
MyViewModel.cs
public class MyViewModel: INotifyPropertyChanged
{
public ObservableCollection<MyModel> Data { get; set; }
public ICommand RemoveEquipmentCommand => new Command<MyModel>(ReMoveItem);
private void ReMoveItem(MyModel obj)
{
System.Diagnostics.Debug.WriteLine(" the selected item's name is: " + obj.Name );
Data.Remove(obj);
}
public MyViewModel() {
Data = new ObservableCollection<MyModel>();
Data.Add(new MyModel { Name ="model_1", Car= new Vehicle {Make="Make1" } });
Data.Add(new MyModel { Name = "model_2", Car = new Vehicle { Make = "Make2" } });
Data.Add(new MyModel { Name = "model_3", Car = new Vehicle { Make = "Make3" } });
Data.Add(new MyModel { Name = "model_4", Car = new Vehicle { Make = "Make4" } });
}
bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
{
if (Object.Equals(storage, value))
return false;
storage = value;
OnPropertyChanged(propertyName);
return true;
}
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public event PropertyChangedEventHandler PropertyChanged;
}
SecondPage.cs
public partial class SecondPage : ContentPage
{
public ObservableCollection<MyModel> Items { get; set; }
public SecondPage(ObservableCollection<MyModel> data )
      { // we can get the passed data here
            InitializeComponent();
            this.Items = data;
      }
}

Popup in .Net Maui application

I use Xamarin community toolkit mauicompat to implement popup for .net maui but when I call to open the popup, it had an error like the image below
and my code here:
public partial class HomePage : ContentPage
{
public HomePage()
{
InitializeComponent();
}
private void BtPop_Clicked(object sender, System.EventArgs e)
{
Navigation.ShowPopup(new PopupServicess()
{
IsLightDismissEnabled = true,
});
}
private void CollectionView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
}
}
here my xaml file:
<xct:Popup xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:xct="http://xamarin.com/schemas/2020/toolkit"
Size="300,300"
x:Class="NailsApp.Views.PopupServicess">
<StackLayout>
<Label Text="Hello from Popup!"/>
</StackLayout>
</xct:Popup>
public partial class PopupServicess : Popup
{
public PopupServicess()
{
}
}

data is not getting in viewmodel on Icommand button click

I have a form for capturing data from user.
<StackLayout Spacing="10" Margin="20,10,20,0">
<Label Text="Job Name"></Label>
<Entry BackgroundColor="White" x:Name="JobName" Text="{Binding SelectedJob.Name,Mode=TwoWay}"/>
<Label Text="Goal"></Label>
<Entry BackgroundColor="White" x:Name="Goal" Text="{Binding SelectedJob.Goal,Mode=TwoWay}"/>
<Grid ColumnSpacing="8" HorizontalOptions="FillAndExpand">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button Text="Save" Command="{Binding SubmitCommand}" BackgroundColor="#078fc1" Grid.Column="0" HorizontalOptions="FillAndExpand"/>
<Button Text="Reset" BackgroundColor="#078fc1" Grid.Column="1" HorizontalOptions="FillAndExpand"/>
</Grid>
</StackLayout>
on button click i want to bind data to SelectedJob object.
this is my ViewModel
public class JobViewModel: INotifyPropertyChanged
{
public JobViewModel()
{
SubmitCommand = new Command(OnSubmitAsync);
}
private JobDTO selectedob { get; set; }
public JobDTO SelectedJob
{
get { return selectedob; }
set
{
selectedob = value;
OnPropertyChanged(nameof(SelectedJob));
}
}
public ICommand SubmitCommand { protected set; get; }
public async void OnSubmitAsync()
{
await.jobservice.postjob()
}
}
and this is my model
public class JobDTO:INotifyPropertyChanged
{
private string name { get; set; }
public string Name
{ get { return name;}
set
{
name = value;
OnPropertyChanged(nameof(Name));
}
}
private string goal;
public string Goal
{
get { return goal; }
set
{
goal = value;
OnPropertyChanged(nameof(Goal));
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
on button click i am getting SelectedJob as null,eventhough i made my class as JobDTO:INotifyPropertyChanged.can any one help me what i am doing here wrong.
I changed the code of ViewModel and model.
There is GIF of demo based on your code.
ViewModel of JobViewModel
If you want to used get/set method, one attribute corresponds to one get/set method, I also add OnPropertyChangedmethod.
public class JobViewModel : INotifyPropertyChanged
{
public JobViewModel()
{
SubmitCommand = new Command(OnSubmitAsync);
}
private JobDTO selectedob=new JobDTO();
public JobDTO SelectedJob
{
get { return selectedob; }
set
{
selectedob = value;
OnPropertyChanged("SelectedJob");
}
}
public ICommand SubmitCommand { protected set; get; }
public event PropertyChangedEventHandler PropertyChanged;
public async void OnSubmitAsync()
{
// i donnot know what is your aim of this part, i just pop up a alert that contains Name and Goal from Entry.
await Application.Current.MainPage.DisplayAlert("Alert", "Name: "+SelectedJob.Name+"\n"+ "Goal: "+ SelectedJob.Goal , "Ok");
}
protected virtual void OnPropertyChanged(string propertyName)
{
var changed = PropertyChanged;
if (changed != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Model of JobDTO, The changed place is same with ViewModel
public class JobDTO: INotifyPropertyChanged
{
private string name;
public string Name
{
get { return name; }
set
{
name = value;
OnPropertyChanged("Name");
}
}
private string goal;
public string Goal
{
get { return goal; }
set
{
goal = value;
OnPropertyChanged("Goal");
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
var changed = PropertyChanged;
if (changed != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
MainPage.xaml
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:DateBoundingDemo"
x:Class="DateBoundingDemo.MainPage">
<StackLayout Spacing="10" Margin="20,10,20,0">
<Label Text="Job Name"></Label>
<Entry BackgroundColor="White" x:Name="JobName" Text="{Binding SelectedJob.Name,Mode=TwoWay}"/>
<Label Text="Goal"></Label>
<Entry BackgroundColor="White" x:Name="Goal" Text="{Binding SelectedJob.Goal,Mode=TwoWay}"/>
<Grid ColumnSpacing="8" HorizontalOptions="FillAndExpand">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button Text="Save" Command="{Binding SubmitCommand}" BackgroundColor="#078fc1" Grid.Column="0" HorizontalOptions="FillAndExpand"/>
<Button Text="Reset" BackgroundColor="#078fc1" Grid.Column="1" HorizontalOptions="FillAndExpand"/>
</Grid>
</StackLayout>
</ContentPage>
MainPage.xaml.cs
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
BindingContext =new JobViewModel();
}
}

Unable to show Xamarin Forms MVVM binding result in listview

I am trying to implement MVVM approach in my xamarin forms application. During the implementations, I have hit a road block. I am unable to populate the list view with the data that i recieve from the server. I am unable to identify the binding issue.
Please let me know where is my mistake? What am I missing?
View Code
<?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="Test.Views.SubtaskPage"
Title="Select Subtask"
xmlns:viewModels="clr-namespace:Test.ViewModels; assembly=Test">
<ContentPage.BindingContext>
<viewModels:SubtaskPageViewModel/>
</ContentPage.BindingContext>
<ContentPage.ToolbarItems>
<ToolbarItem x:Name="tbiAddSubtask" Text="Add Subtask" Clicked="tbiAddSubtask_Clicked"/>
</ContentPage.ToolbarItems>
<StackLayout Orientation="Vertical" Padding="10">
<ListView x:Name="lstSubtasks" ItemSelected="lstSubtasks_ItemSelected" IsPullToRefreshEnabled="True" RefreshCommand="{Binding RefreshCommand}" IsRefreshing="{Binding IsBusy}" ItemsSource="{Binding SubtaskList}}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<ViewCell.ContextActions>
<MenuItem x:Name="menuAddTimeSpent" Clicked="menuItem_Clicked" CommandParameter="{Binding Ticket}" Text="Menu" />
</ViewCell.ContextActions>
<StackLayout Padding="20,0,0,0" HorizontalOptions="StartAndExpand" Orientation="Horizontal">
<Label Text="{Binding Subject}" VerticalTextAlignment="Center" />
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ContentPage>
Response Class Code
public class SubtasksResponse
{
public int Status { get; set; }
public string Message { get; set; }
public List<Ticket> Subtasks { get; set; }
}
View Model Code
public class SubtaskPageViewModel : INotifyPropertyChanged
{
private SubtasksResponse _subtaskList;
public SubtasksResponse SubtaskList
{
get { return _subtaskList; }
set
{
_subtaskList = value;
OnPropertyChanged(nameof(SubtaskList));
}
}
private Command _refreshCommand;
public Command RefreshCommand
{
get
{
return _refreshCommand;
}
}
bool _isBusy;
public bool IsBusy
{
get { return _isBusy; }
set
{
_isBusy = value;
OnPropertyChanged(nameof(IsBusy));
}
}
public SubtaskPageViewModel()
{
_refreshCommand = new Command(RefreshList);
}
async void RefreshList()
{
SubtaskList = await PopulateSubtaskList();
}
async Task<SubtasksResponse> PopulateSubtaskList()
{
RestService rs = new RestService();
IsBusy = true;
IsBusy = false;
var subtaskList = new SubtasksResponse();
subtaskList = await rs.GetSubtasksAsync(Convert.ToInt32(Application.Current.Properties["UserId"]));
return subtaskList;
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
For starters we see you are binding the ListView to ItemsSource="{Binding SubtaskList} - when we then look at the ViewModel it seems that SubtaskList is of type SubtasksResponse, that type only has 3 properties.
But the item template inside your ListView is not using any of those 3 properties... it's using Ticket and Subject.
Are this properties of the class Subtasks? If so you need to bind the ListView directly to the List property for it to pick up the items in that collection.

Getting MVVM ViewModel to bind to the View

I have the following code (changed object names, so syntax/spelling errors ignore).
public class ViewModel
{
ViewModelSource m_vSource;
public ViewModel(IViewModelSource source)
{
m_vSource= source;
m_vSource.ItemArrived += new Action<Item>(m_vSource_ItemArrived);
}
void m_vSource_ItemArrived(Item obj)
{
Title = obj.Title;
Subitems = obj.items;
Description = obj.Description;
}
public void GetFeed(string serviceUrl)
{
m_vFeedSource.GetFeed(serviceUrl);
}
public string Title { get; set; }
public IEnumerable<Subitems> Subitems { get; set; }
public string Description { get; set; }
}
Here is the code I have in my page's codebehind.
ViewModel m_vViewModel;
public MainPage()
{
InitializeComponent();
m_vViewModel = new ViewModel(new ViewModelSource());
this.Loaded += new RoutedEventHandler(MainPage_Loaded);
this.DataContext = m_vViewModel;
}
void MainPage_Loaded(object sender, RoutedEventArgs e)
{
m_vViewModel.GetItems("http://www.myserviceurl.com");
}
Finally, here is a sample of what my xaml looks like.
<!--TitleGrid is the name of the application and page title-->
<Grid x:Name="TitleGrid" Grid.Row="0">
<TextBlock Text="My Super Title" x:Name="textBlockPageTitle" Style="{StaticResource PhoneTextPageTitle1Style}"/>
<TextBlock Text="{Binding Path=Title}" x:Name="textBlockListTitle" Style="{StaticResource PhoneTextPageTitle2Style}"/>
</Grid>
Is there anything I'm doing wrong here?
I think your ViewModel should implement the INotifyPropertyChanged interface:
public virtual event PropertyChangedEventHandler PropertyChanged;
protected virtual void RaisePropertyChanged(string propertyName)
{
if (this.PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
Then your property would look like that:
private title;
public string Title
{
get
{
return this.title;
}
set
{
if (this.title!= value)
{
this.title= value;
this.RaisePropertyChanged("Title");
}
}
}
Michael
Well, go figure, 10 mins after I post it, I figure it out.
I was missing the INotifyProperty implementation. Thanks if anyone is looking at this.