UWP Cannot bind ICommand to User control - data-binding

I am currently working on a UWP project and I am trying to bind some command from the current page to an usercontrol.
While every other properties seems to be correctly bound, the command is not and thus is not working.
Do you have any idea from where it might come ?
Here is my code (main page):
<Grid Visibility="{Binding LoginStep, Converter={StaticResource LogConverter}, ConverterParameter='InputPin'}"
Height="450px" Width="280px">
<PIN:PinInput Pin="{Binding CurrentUser.Pin, Mode=TwoWay}" x:Uid="btnPin" SubmitCommand="{Binding AddPinCommand, Mode=TwoWay}"></PIN:PinInput>
</Grid>
View model:
private ICommand _addPinCommand;
public ICommand AddPinCommand
{
get
{
return _addPinCommand ?? (_addPinCommand = new CommandBase((o) =>
{
this.LoginStep = LoginStep.ChoseCompany;
}));
}
}
User control:
DataContext="{Binding RelativeSource={RelativeSource Self}}"
<Grid Grid.Row="3">
<Grid.ColumnDefinitions>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<Button Style="{StaticResource btnStyle}" Command="{Binding SubmitCommand, Mode=TwoWay}">
<StackPanel>
<Border Style="{StaticResource btnInnerStyle}" Width="100px" CornerRadius="10">
<TextBlock Text="{Binding SubmitButtonText}" Style="{StaticResource btnText}"></TextBlock>
</Border>
</StackPanel>
</Button>
</Grid>
public static readonly DependencyProperty submitCommandProperty = DependencyProperty.Register("SubmitCommand", typeof(ICommand), typeof(PinInput), null);
public ICommand SubmitCommand
{
get
{
return (ICommand)GetValue(submitCommandProperty);
}
set
{
SetValue(submitCommandProperty, value);
}
}
Note:
in the error log I have:
Error: BindingExpression path error: 'AddPinCommand' property not found on 'PAT.Mobile.UTrakk.UWP.Views.Components.PinInput'. BindingExpression: Path='AddPinCommand' DataItem='PAT.Mobile.UTrakk.UWP.Views.Components.PinInput'; target element is 'PAT.Mobile.UTrakk.UWP.Views.Components.PinInput' (Name='null'); target property is 'SubmitCommand' (type 'ICommand')
Thanks in advance,
Thomas K. T.

Ok this one was weird but here is what seems to do the trick:
<PIN:PinInput SubmitCommand="{Binding DataContext.AddPinCommand, ElementName=curPage}" Pin="{Binding CurrentUser.Pin, Mode=TwoWay}" x:Uid="btnPin" ></PIN:PinInput>
With "curPage" = name of the current page.
I do not fully understand why I have to do this, since CurrentUser.Pin is working perfectly fine without this work around.
Can someone explain ?

Related

xamarin System.InvalidOperationException: 'Cannot convert "VerticalGrid, 2" into Xamarin.Forms.IItemsLayout'

I'm getting the error System.InvalidOperationException: 'Cannot convert "VerticalGrid, 2" into Xamarin.Forms.IItemsLayout' during InitalizeComponent() of my ContentPage containing a CollectionsView.
The code works properly on UWP, and the error occurs when running on Android. Being new to xamarin.forms, I'm not really sure what to start looking for.
EDIT: it works if I choose "VerticalList".
Here's a bit of my xaml:
<ContentPage ... >
<StackLayout>
<CollectionView
x:Name="DetailGrid"
ItemsLayout="VerticalGrid, 2" >
<CollectionView.ItemTemplate>
<DataTemplate>
<StackLayout Padding="20" BackgroundColor="Crimson">
<Image Source= "{Binding Path}" WidthRequest="300"/>
<Label Text="{Binding FileName}" TextColor ="Bisque" LineBreakMode="WordWrap" />
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</StackLayout>
</ContentPage>
And here's some code-behind:
namespace varlist
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class CollectionPage : ContentPage
{
public ObservableCollection<NodeData> nodes = new ObservableCollection<NodeData>();
public CollectionPage ()
{
InitializeComponent ();
nodes.Add (new ImageData { FileName = "image_chair_pk.jpg" });
...
DetailGrid.ItemsSource = nodes;
}
}
}
I got the same error with you when I use a Xamarin.forms version 4.5.0.725.
After I update my Xamarin.forms to the latest version 4.8.0.1687, everything works well.
Please update your Xamarin.forms version to fix this problem:
I found a workaround. This appears to be a framework bug.
According to Xamarin.Forms CollectionView Layout the syntax I used should work - and it does work for UWP.
They also show an alternate declaration to specify ItemsLayout:
<CollectionView.ItemsLayout>
<GridItemsLayout Orientation="Vertical" Span="2" />
</CollectionView.ItemsLayout>
And, this syntax works on Android.
I filed a bug on github:[Bug] CollectionView with ItemsLayout=VerticalGrid crashes on Android #12920
You can omit this property if you wish it vertical, the default is set to VerticalList. If you want your collectionView to be Horizontal, just use HorizontalList.
See https://learn.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/collectionview/layout

Caliburn Micro Binding on Dependency Property

I have an custom control with following DP:
public FrameworkElement NoResultContent
{
get { return (FrameworkElement)GetValue(NoResultContentProperty); }
set { SetValue(NoResultContentProperty, value); }
}
public static readonly DependencyProperty NoResultContentProperty =
DependencyProperty.Register("NoResultContent", typeof(FrameworkElement), typeof(AdvancedAutoCompleteBox), new PropertyMetadata(null));
The ControlTemplate of my custom control shows this DP in a ContentControl:
<ContentControl Content="{TemplateBinding NoResultContent}" />
It's used in a view to provide arbitrary functions:
<Controls:AdvancedAutoCompleteBox
x:Name="Box"
ItemsSource="{Binding Persons}"
SelectedItem="{Binding SelectedPerson}"
Watermark="Search here">
<Controls:AdvancedAutoCompleteBox.NoResultContent>
<StackPanel>
<Button
Content="Add by ICommand"
Command="{Binding AddPerson}" />
<Button
x:Name="AddPerson"
Content="Add by Caliburn" />
</StackPanel>
</Controls:AdvancedAutoCompleteBox.NoResultContent>
</Controls:AdvancedAutoCompleteBox>
The Command-Binding to a ICommand works just fine. Buy why does it not work with Caliburn.Micro?
I also tried to attach the context to the second Button manually by cal:Bind.Model

Image flickering on Listview Search - xamarin.forms

In my xamarin.forms application, I have a Listview.The Listview contains images which are binded to photoURL.I have implemented a searchbox at the top of listview.Everything worked fine.But the problem now I facing is whenever I search for anything in list,the item appears.But the image will be gets flicker on each character type.I am getting the data from API that binding to the listview.
Please refer the link : https://gfycat.com/WaterloggedBeneficialGlobefish
My Image binding
<Grid>
<ci1:CircleImage
HeightRequest="200"
Source="empavatar.png"
Aspect="AspectFit">
</ci1:CircleImage>
<ci1:CircleImage
HeightRequest="200"
Source="{Binding PhotoURL}"
Aspect="AspectFit">
</ci1:CircleImage>
</Grid>
Iam using circular imageview and a template image when ImageURL is null.
My Search
private void SearchBar_TextChanged(object sender, TextChangedEventArgs e)
{
if (string.IsNullOrEmpty(e.NewTextValue))
{
EmployeeListView.ItemsSource = resultObjForEmployee;
}
else
{
EmployeeListView.ItemsSource = resultObjForEmployee.Where(x => x.Name.ToLower().StartsWith(e.NewTextValue));
}
}
resultObjForEmployee is the result that I getting from json.
Please help me to recover this problem.
Try setting the CachingStrategy of Listview as "RecycleElement"
<ListView CachingStrategy="RecycleElement">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid>
<ci1:CircleImage
HeightRequest="200"
Source="empavatar.png"
Aspect="AspectFit"></ci1:CircleImage>
<ci1:CircleImage
HeightRequest="200"
Source="{Binding PhotoURL}"
Aspect="AspectFit"></ci1:CircleImage>
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>

How to detect list view scrolling direction in xamarin forms

I have tried to detect the scrolling direction of the list view. My requirement is need to implement different functionality while list view scrolling up and scrolling down. Please suggest any idea for detecting list view scrolling direction. I have tried below syntax in my list view.
Sample code:
<StackLayout>
<Label x:Name="Direction" />
<ListView ItemsSource="{Binding Items}" HasUnevenRows = "true" ItemAppearing="Handle_ItemAppearing" IsPullToRefreshEnabled = "true">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout>
<Label Text = "{Binding}" />
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
I don't think you can do it by default, you can only act on a item that is appearing or disappearing. So, you either need to work with that by creating some code which gets the index of (dis)appearing items and and see if the indexes are getting higher or lower to determine whether someone is scrolling up or down. Or you need to hook up a custom renderer, but I'm not sure the native controls have anything to detect this either.
I've whipped up a very basic example for you, you can find the full code here.
Basically hook into the event available, keep track of the last index in a class variable and compare it to the current index of the item that is appearing.
private void Handle_ItemAppearing (object sender, Xamarin.Forms.ItemVisibilityEventArgs e)
{
var currentIdx = Items.IndexOf ((string)e.Item);
if (currentIdx > _lastItemAppearedIdx)
Direction.Text = "Up";
else
Direction.Text = "Down";
_lastItemAppearedIdx = Items.IndexOf ((string)e.Item);
}
In this code I simply show it in a Label, but of course you can create some enum to return or fire an event or something to make the code some more reusable. Here is the code in action:
Recently came through this problem and fixed it this way:
<StackLayout>
<Label x:Name="Direction" />
<ListView ItemsSource="{Binding Items}" HasUnevenRows = "true" ItemAppearing="Handle_ItemAppearing" ItemDisappearing="Handle_ItemDisappearing" IsPullToRefreshEnabled = "true">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout>
<Label Text = "{Binding}" />
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
string ScrollingDirection;
int visibleTabIndex;
int disappearingTabIndex;
public async void Handle_ItemAppearing(object sender, ItemVisibilityEventArgs e)
{
var visibleTab = e.Item;
visibleTabIndex = MyItemsList.IndexOf(visibleTab);
if (disappearingTabIndex > visibleTabIndex) ScrollingDirection = "DOWN";
else ScrollingDirection = "UP";
}
public async void Handle_ItemDisappearing(object sender, ItemVisibilityEventArgs e)
{
var invisibleTab = e.Item as TicketsList;
disappearingTabIndex = tvm.Tickets.IndexOf(invisibleTab);
}

Rendering a Heterogeneous Collection of View Models in Silverlight 2

I have a hierarchy of view models representing formatted content:
public abstract class ContentPartViewModel : ViewModel
{
}
public class TextContentPartViewModel : ContentPartViewModel
{
public string Text { ... }
}
public class TitleContentPartViewModel : TextContentPartViewModel
{
}
public class HyperlinkContentPartViewModel : TextContentPartViewModel
{
public string Uri { ... }
}
I have an encompassing view model that contains a collection of ContentPartViewModels to be rendered:
public class ContentViewModel
{
public ICollection<ContentPartViewModel> ContentParts { ... }
}
I then have a ContentView that renders all parts of the content:
<UserControl ...>
<ItemsControl ItemsSource="{Binding ContentParts}"/>
</UserControl>
In an ideal world, I would just define a DataTemplate for each of the content part types and they would be rendered accordingly. However, Silverlight does not support the DataType property on the DataTemplate class, so that is not an option.
Another option would be to provide a DataTemplateSelector and do the mapping from view model type to DataTemplate myself. Alas, ItemsControl in SL2 does not have an ItemTemplateSelector property - only an ItemTemplate property.
That left me with no option but to provide an ItemTemplate that then uses a converter to turn off all the UI apart from the piece relevant to that content part:
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<TextBlock Text="{Binding Text}" FontWeight="Bold" Visibility="{Binding Converter={StaticResource TitleContentPartConverter}}"/>
<TextBlock Text="{Binding Text}" Visibility="{Binding Converter={StaticResource TextContentPartConverter}}"/>
<HyperlinkButton Content="{Binding Text}" NavigateUri="{Binding Uri}" Visibility="{Binding Converter={StaticResource HyperlinkContentPartConverter}}"/>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
This is obviously rather awful, both for performance and for readability/correctness of code. It also makes it much harder for me to format the output correctly. So, questions:
Can anyone recommend a better way to do this in SL2?
Can anyone confirm whether the situation has improved in SL3?
Thanks,
Kent
Yes. DataType in DataTemplate is not supported in Silverlight 2 or Silverlight 3.
You can work around ItemTemplateSelector in Silverlight. Please take a look at this sample.
http://silverlight.net/forums/t/12598.aspx
protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
{
base.PrepareContainerForItemOverride(element, item);
DataTemplateSelector selector = this.ItemTemplateSelector;
if (null != selector)
{
((ContentPresenter)element).ContentTemplate = selector.SelectTemplate(item, element);
}
}

Resources