Xamarin Prism binding same command in multiple views - forms

I've a page view which has TabView and each tabview item is a separate view, containing list.
<TabView>
<TabViewItem HeaderText="Comments">
<TabViewItem.Content>
<local:CommentsListView/>
</TabViewItem.Content>
</TabViewItem>
<TabViewItem HeaderText="Stock">
<TabViewItem.Content>
<local:StockListView/>
</TabViewItem.Content>
</TabViewItem>
<TabViewItem HeaderText="Labour">
<TabViewItem.Content>
<local:LabourListView/>
</TabViewItem.Content>
</TabViewItem>
</TabView>
In each child view I've enabled pulldown and pulldown command in each view is pointing to the same 'RefreshCommand'. I want RefreshCommand to be called once no matter from which view pulldown was performed.
Problem is that if I have say 5 child views then refresh command is called 5 times. Obviously I could bind 5 different commands which calls the same method, but would be nice if I could reuse same command.
Is this possible?
Edit: added sample of view in each tab. They all are the same except pointing to different ItemSource:
<?xml version="1.0" encoding="utf-8" ?>
<ContentView xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:prism="http://prismlibrary.com"
prism:ViewModelLocator.AutowireViewModel="True"
xmlns:custom="clr-namespace:Controls"
xmlns:converter="clr-namespace:Converters"
x:Class="CommentsListView">
<ContentView.Resources>
<ResourceDictionary>
<converter:NegateBooleanConverter x:Key="inverter" />
</ResourceDictionary>
</ContentView.Resources>
<custom:ObjectGridView
x:Name="commentsListView"
ItemsSource="{Binding CommentsList}"
IsPullToRefreshEnabled="{Binding InEditMode, Converter={StaticResource inverter}}"
IsRefreshing="{Binding IsRefreshing, Mode=TwoWay}"
PullToRefreshCommand="{Binding RefreshCommand}"
RowTapCommand="{Binding CommentTapCommand}"
ShowAddButton="True"
AddButtonVisible="{Binding InEditMode}"
AddButtonCommand="{Binding AddButtonCommand}"/>
</ContentView>

Related

MAUI Community Toolkit EventToCommandBehavior

I'm desperately trying to adhere to the MVVM design pattern in my App. So I'm trying to use the EventToCommandBehavior behavior from the MCT. (I'm also using the CommunityToolkit.Mvvm for [RelayCommand]) I've attached it to an Entry and am trying to forward the TextChanged event to my command. However, my command doesn't execute.
XAML:
<?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"
xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"
x:Class="MyApp.View.Accounts.AddAccountPage"
xmlns:viewmodel="clr-namespace:MyApp.ViewModel.AccountsViewModel"
Title="Add Account">
<VerticalStackLayout>
<Entry x:Name="entryAccountName"
Placeholder="Account Name"
PlaceholderColor="Black"
TextColor="{StaticResource Tertiary}"
BackgroundColor="{StaticResource Primary}"
WidthRequest="125"
HorizontalOptions="Center"
Keyboard="Text"
ClearButtonVisibility="WhileEditing"
ReturnType="Next">
<Entry.Behaviors>
<toolkit:EventToCommandBehavior
EventName="TextChanged"
Command="{Binding AccountTextChangedCommand}" />
</Entry.Behaviors>
</Entry>
....More XAML....
AccountsViewModel code:
[RelayCommand]
public void AccountTextChanged()
{
Application.Current.MainPage.DisplayAlert("Text changed", "Account Text Changed", "OK");
}
I've got a breakpoint set to the Method and it just never gets called. Any ideas as to what am I doing wrong?
If by "reference in the header", you mean the line xmlns:viewmodel=...,
all that can do is declare a namespace that can be used in the following xaml. It can't refer to a class in that namespace - the line you show is ignored because it is not a valid namespace - you need:
<ContentPage
xmlns:viewmodel="clr-namespace:MyApp.ViewModel" <--- NAMESPACE, NOT CLASS!
/>
<ContentPage.BindingContext>
<viewmodel:AccountsViewModel/>
</ContentPage.BindingContext>
lines in your xaml, to say which viewmodel is the binding context. This is equivalent to the c# code you put in constructor.
OR There is an alternative technique, using Dependency Injection.
In MauiProgram.CreateMauiApp(), add lines similar to:
mauiAppBuilder.Services.AddTransient<MyApp.ViewModel.AccountsViewModel>();
mauiAppBuilder.Services.AddTransient<MyApp.View.Accounts.AddAccountPage>();
Exact details of those lines depend on your existing CreateMauiApp code, and your namespaces.
I finally figured it out. I had forgotten to set the BindingContext to the AccountsViewModel in the constructor of the page:
using MyApp.Services;
using MyApp.ViewModel.AccountsViewModel;
namespace MyApp.View.Accounts;
public partial class AddAccountPage : ContentPage
{
public AddAccountPage()
{
InitializeComponent();
DataService dataService = new();
AccountsViewModel accountsViewModel = new(dataService);
BindingContext = accountsViewModel;
}
}
I've been having to set the BindingContext via constructors on various pages to get the data bindings to work, even though I reference the ViewModels in the XAML header. Is this intended or am I going about it wrong?

.NET MAUI TableView collapses when Entry control receives focus

I have a TableView in which I render form controls for data editing.
However, as soon as the Entry control receives focus, the ViewCell seemingly collapses, leaving only the section title and separator borders visible:
<TableView Intent="Data">
<TableRoot>
<TableSection Title="Details">
<ViewCell>
<Grid ColumnDefinitions="0.5*,0.5*">
<Label Text="Manufacturer" />
<Entry Text="{Binding Manufacturer}" Grid.Column="1" />
</Grid>
</ViewCell>
</TableSection>
</TableRoot>
</TableView>
Initial state:
After tapping the Entry element:
I've tried setting a specific height for the Grid and the Entry control, but I get the same result regardless.
Am I missing something obvious here? 🤔
It's a bug in .NET MAUI: https://github.com/dotnet/maui/issues/10322
I ran into this a while ago and reported it. For now, I have created my own table using a Grid.
You can change The TableView HeightRequest property to a large number such as 700.
This is a temporary workaround until the bug is fixed.
<TableView HeightRequest="700">
<TableRoot>
<TableSection>
<!-- Your code goes here -->
</TableSection>
</TableRoot>
</TableView>
But, in most scenarios, you don't know what the Height is so you could set it dynamically in your code behind.
Page constructor:
public MainPage()
{
InitializeComponent();
// if you want your table height to fit half of the page
Table.HeightRequest = this.Height / 2;
// Rest of logic...
}
Xaml:
<TableView x:Name="Table">
<TableRoot>
<TableSection>
<ViewCell>
<Label Text="Example"/>
</ViewCell>
</TableSection>
</TableRoot>
</TableView>

Unable to create XAML array of views with mvvm:ViewModelLocator

I want to make a xamarin forms carousel view containing 2 custom views. I have this code:
<ContentPage x:Class="MainView" xmlns:mvvm="clr-namespace:Prism.Mvvm;assembly=Prism.Forms" xmlns:views="clr-namespace:Views" x:Name="Main">
<CarouselView>
<CarouselView.ItemsSource>
<x:Array Type="{x:Type View}">
<views:View1 mvvm:ViewModelLocator.AutowirePartialView="{x:Reference Main}" />
<views:View2 mvvm:ViewModelLocator.AutowirePartialView="{x:Reference Main}" />
</x:Array>
</CarouselView.ItemsSource>
<CarouselView.ItemTemplate>
<DataTemplate>
<ContentView Content="{Binding .}" />
</DataTemplate>
</CarouselView.ItemTemplate>
</CarouselView>
</ContentPage>
When launching the app, exception is thrown:
Xamarin.Forms.Xaml.XamlParseException: 'Position 80:37. Can not find
the object referenced by Main'
If I just set both views as direct content of the main page, it works fine. What am I doing wrong?
Is there a way to make the collection of views through the MainViewModel?

Insert table in XML-view

I created a table in my controller-function onRoutePatternMatched.
Now I want to bring this table to the view.
This should be done with oTable.placeAt("sample1");
What is the right code to insert it on a specific place in my xml-view?
Home.view.xml
<?xml version="1.0" encoding="UTF-8" ?>
<mvc:View controllerName="ztest.controller.VarConf" xmlns:mvc="sap.ui.core.mvc" xmlns="sap.m"
xmlns:html="http://www.w3.org/1999/xhtml">
<Page>
<content id="sample1"></content>
<content id="sample2">
<Label text="{varConfDet>/chassisnr}" />
</content>
</Page>
</mvc:View>
Error:
sap-ui-core.js:152 Uncaught Error: DOM element with ID 'sample1' not found in page, but application tries to insert content.
put an id on on the page and not on its content aggregation(s): <Page id="myPge">
in Controller call this.getView().byId("myPage").addContent(oTable);
Because content os the default aggregation of the sap.m.Page you could also only call this.getView().byId("myPage").add(oTable);. Also be aware that you might to remove previously added content... Of course, you could also use different panels etc. with different ids and place the table somewhere in there...

Setting Window.Content to ViewModel - simple data template not working

Trying to get my head around MVVM, and getting a simple window to render its viewmodel as a view via data templating.
in App.xaml:
<Application.Resources>
<DataTemplate DataType="{x:Type vm:TestViewModel}">
<vw:TestView />
</DataTemplate>
</Application.Resources>
View definition:
<UserControl x:Class="MyNamespace.TestView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<TextBlock>TESTING</TextBlock>
</Grid>
</UserControl>
In MainWindowViewModel:
private void onOpenTestView(object sender)
{
Window w = new Window();
w.Content = new TestViewModel();
w.Show();
}
Running the app results in a window with a "MyNamespace.TestViewModel" string, instead of "TESTING", which would infer my data template is not being found.
I am very new to all this so am I missing something obvious? I don't think it's a string matching issue since if I deliberately misspell the view or model in the XAML then it doesn't compile.
Should my new window be able to access my app resources (and thus my datatemplate) ok?
Cheers,
Jeremy
EDIT: FIXED (Can't answer for 8 hours)
Due to MS Bug where resources not being read unless at least one style is set.
See http://connect.microsoft.com/VisualStudio/feedback/details/553528/defaultstylekey-style-not-found-in-inner-mergeddictionaries
Due to MS Bug where resources not being read unless at least one style is set.
See http://connect.microsoft.com/VisualStudio/feedback/details/553528/defaultstylekey-style-not-found-in-inner-mergeddictionaries