Xamarin: Change value of GridItemLayout in codebehind - c#

<CollectionView Grid.Row="2" Grid.Column="0" x:Name="collectionViewItemsLayout" ItemsSource="{Binding BaseCustomersCards}" ItemTemplate="{StaticResource CustomerCardTemplateSelector}" >
<CollectionView.ItemsLayout>
<GridItemsLayout Orientation="Vertical" Span="5" />
</CollectionView.ItemsLayout>
</CollectionView>
I've got this collectionview but am attempting to change the span for phone-tablet. Default is 5 but phone value should be 3.
var idiom = DeviceInfo.Idiom;
if (idiom == DeviceIdiom.Phone)
{
collectionViewItemsLayout.SetValue(GridItemsLayout.SpanProperty, 3);
}
I made this in the code-behind to change it, the method triggers but doesn't change anything. I've tried to put the 3 as a string and as pure value. I've also attempted to put the x:name in the attribute but it cannot go there.

Works by creating a new GridItem and setting it instead
if (idiom == DeviceIdiom.Phone)
{
var grid = new GridItemsLayout(ItemsLayoutOrientation.Vertical)
{
Span = 3,
};
collectionViewItemsLayout.SetValue(CollectionView.ItemsLayoutProperty, grid);
}

Related

How to refresh a collectionView when click on button

I would like to refresh my collectionView When I click on a button and make the app continue to run while the collectionview is filled
Here is my Xaml :
<CollectionView x:Name="WordSList" ItemsLayout="Vertical" >
<CollectionView.ItemTemplate >
<DataTemplate>
<StackLayout >
<Label Text="{Binding Word1}" />
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
What I would like :
List<MyClass> MyWordsList;
ObservableCollection<MyClass> datasource;
int ndx = 100;
public void OnRefreshing_MyCollection_View()
{
// refresh the collection view without making the app waiting for it to be filled
MyWordsList = await mywordsdatabase.GetWords();
WordSList.ItemsSource = datasource = new ObservableCollection<MyClass (MyWordsList.Take(ndx));
}
Thanks for your help
you can use the RefreshView of Xamarin.Forms like in this example of James Montemagno:
https://devblogs.microsoft.com/xamarin/refreshview-xamarin-forms/
You have a property IsRefreshing which you set on the beginning of your refreshing-method. After refreshing you set it to false.
<RefreshView IsRefreshing="{Binding IsRefreshing}"
Command="{Binding RefreshCommand}">
<CollectionView ItemsSource="{Binding Items}">
<CollectionView.ItemsLayout>
<LinearItemsLayout Orientation="Vertical"/>
</CollectionView.ItemsLayout>
<!-- Add ItemTemplate Here -->
</CollectionView>
</RefreshView>
void ExecuteRefreshCommand()
{
Items.Clear();
Items.Add(new Item { Text = "Refreshed Data", Description = "Whoa!" });
// Stop refreshing
IsRefreshing = false;
}
In the example its an drag-down-element in your collection view. But you can also do this with a button event and an async method to load your data.

How to change TextBlock Text Binding in C#

I'm working in huge application and I have one small problem
My Application has two languages (Arabic / English).
I have ComboBox And I would like to change the display content according to the language.
This is my ComboBox XAML:
<ComboBox x:Name="cmbCustomerGroup" Grid.Row="2" Grid.Column="1" Grid.ColumnSpan="5"
Margin="2" SelectedValuePath="CustomerGroupId" Validation.Error="Validation_Error"
SelectedValue="{Binding Path=CustomerGroupId, ValidatesOnDataErrors=True, UpdateSourceTrigger=PropertyChanged, NotifyOnValidationError=True}">
<!--<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}"/>
</DataTemplate>
</ComboBox.ItemTemplate>-->
</ComboBox>
This is my method:
private void FillCustomerGroups()
{
var oClsCustomers = new ClsCustomerGroups();
var lstCustGrps = oClsCustomers.GetData();
cmbCustomerGroup.ItemsSource = lstCustGrps.ToList<TbCustomerGroups>();
cmbCustomerGroup.DisplayMemberPath = Helper.CurrLang == Helper.SystemLanguage.Arabic ? "CustomerGroupAName" : "CustomerGroupEName";
cmbCustomerGroup.SelectedValuePath = "CustomerGroupId";
}
I got this result:
This is my database:
This usually occurs when DisplayMemberPath is set wrong, or bindable property is not a string and has no overriden ToString() method.
Try add new property to your TbCustomerGroups, for example CurrentGroupName like this
public string CurrentGroupName => Helper.CurrLang == Helper.SystemLanguage.Arabic ? CustomerGroupAName : CustomerGroupEName;
Then set cmbCustomerGroup.DisplayMemberPath = "CurrentGroupName"
Also check that CustomerGroupAName and CustomerGroupEName are strings or have ToString() method
UPDATE
Also don't use <ComboBox.ItemTemplate> if you use DisplayMemberPath

Exception in ZXingBarcodeImageView when removing from ObservableCollection

I'm using an ObservableCollection<BarcodeInfo> as ItemsSource of a ListView to generate ViewCells. A Cell contains 2 Labels and a ZXingBarcodeImageView with bindings to my BarcodeInfo-class, everything works as expected.
Now I've to remove several cells from the ListView, but as soon as I try to do so, I get the following Exception from the ZXingBarcodeImageView
System.ArgumentException: Found empty contents
Here's my XAML
<ListView RowHeight="50">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="3*" />
</Grid.ColumnDefinitions>
<zxing:ZXingBarcodeImageView
BarcodeFormat="{Binding Format}"
BarcodeOptions="{Binding Options}"
BarcodeValue="{Binding Text}"
HorizontalOptions="FillAndExpand"
VerticalOptions="FillAndExpand"
Margin="5"
Grid.Column="0"/>
<StackLayout Grid.Row="0" Grid.Column="1"
Spacing="0" VerticalOptions="CenterAndExpand">
<Label Text="{Binding Text}"
LineBreakMode="TailTruncation"
VerticalOptions="End"/>
<Label Text="{Binding Format}"
VerticalOptions="End"
LineBreakMode="TailTruncation"/>
</StackLayout>
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
And the Class for ObservableCollection<BarcodeInfo> _barcodeCollection; in the of the ListView
public class BarcodeInfo
{
public string Text
{ get; set; }
public string Detail
{ get; set; }
public BarcodeFormat Format
{ get; set; }
public EncodingOptions Options
{ get; set; }
}
The Exceptions happens as soon as I try
_barcodeCollection.RemoveAt(i);
I've implemented the INotifyPropertyChanged and tried to set all properties to null which works without exception, but the ZXingBarcodeImageView is not clearing the barcode-image and the Exception is still thrown if I try to remove the Item from the Collection. I'm at a point where I've no more ideas.
I hope anybody can help me.
Update
Because the i seems to be confusing here's the loop I'm using it
for (int i = 0; i < _barcodeCollection.Count; i++)
{
var response =
await _serverUrl.PostUrlEncodedAsync(
new { barcode = _barcodeCollection[i].Text })
.ReceiveString();
if (string.Equals(response, "ok", StringComparison.OrdinalIgnoreCase))
{
percentage += progressSteps;
_barcodeCollection.RemoveAt(i); //EXCEPTION!!!
i--; // index must be checked twice else one element will be skipped
await UploadProgress.ProgressTo(percentage, 250, Easing.Linear);
}
}
Not a straightforward solution, but the easiest workaround I've found was to provide FallbackValue when binding BarcodeValue
<forms:ZXingBarcodeImageView BarcodeFormat="{Binding Format}"
BarcodeValue="{Binding Content, FallbackValue='1'}" />
I have managed to identify the cause of the problem, it is a side effect of the way that the ListView is refreshed when the elements are removed and the ListViewCachingStrategy is set to RetainElement (the default).
The custom renderer OnElementPropertyChanged is called when the items are removed from the collection, and the regenerate() method in the ZXing custom renderer crashes.
This can be solved by setting the ListViewCachingStrategy to RecycleElement, this will work with Android, however there is still a problem with iOS 10, which does not correctly support a listview with ListViewCachingStrategy set to RecycleElement, iOS 10 currentlly works only with ListViewCachingStrategy set to RetainElement, this can be accommodated if you create a custom control in your portable code eg:
public class MyZXingBarcodeImageView : ZXingBarcodeImageView
{
//THERE IS NO CODE REQUIRED HERE
}
And then create your own custom renderer based on the ZXing source, but replace the void regenerate() method with the following:
void regenerate()
{
if(formsView != null && !string.IsNullOrWhiteSpace(formsView.BarcodeValue) )
{
var writer = new ZXing.Mobile.BarcodeWriter();
if(formsView != null && formsView.BarcodeOptions != null)
writer.Options = formsView.BarcodeOptions;
if(formsView != null && formsView.BarcodeFormat != null)
writer.Format = formsView.BarcodeFormat;
var value = formsView != null ? formsView.BarcodeValue : string.Empty;
Device.BeginInvokeOnMainThread(() =>
{
var image = writer.Write(value);
imageView.Image = image;
});
}
}
The change is in the very first If statement, changing from testing for null string to string.IsNullOrWhiteSpace
You do NOT have to create a custom renderer for Android if you use ListViewCachingStrategy set to RecycleElement, the base renderer for ZXingBarcodeImageView will be used without error.

How to get the value from my picker? Xamarin forms

I have trouble to get out the selected string from my picker.
This is my code:
XAML:
<Picker x:Name="thePicker" >
<Picker.Items>
<x:String>info1</x:String>
<x:String>info2 </x:String>
</Picker.Items>
</Picker>
CODE:
thePicker.SelectedIndex = 1; //here is the problem i suppose, any idea what i should type?
var ourPickedItem = thePicker.Items[thePicker.SelectedIndex];
Now I only get the value "info1" even if i select number 2. It has something to do with the SelectedIndex so it only picks the "1", but I am not sure how to write the code to make it work for the selected item.
You should take a look at this:
picker.SelectedIndexChanged += (sender, args) =>
{
if (picker.SelectedIndex == -1)
{
boxView.Color = Color.Default;
}
else
{
string colorName = picker.Items[picker.SelectedIndex];
boxView.Color = nameToColor[colorName];
}
};
Otherwise in new Xamarin Forms Release 2.3.4 exists the
Bindable Picker
you can set an ItemSource
<Picker ItemsSource="{Binding Countries}" />
and Bind the SelectedIndex property
SelectedIndex="{Binding CountriesSelectedIndex}"
XLabs is already providing it. Here is an example:
<ContentPage x:Class="XLabs.Samples.Pages.Controls.ExtendedPickerPage"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:controls="clr-namespace:XLabs.Forms.Controls;assembly=XLabs.Forms"
Title="Picker">
<ContentPage.Content>
<StackLayout x:Name="myStackLayout">
<Label Text="Xaml:" />
<controls:ExtendedPicker x:Name="myPicker"
DisplayProperty="FirstName"
ItemsSource="{Binding MyDataList}"
SelectedItem="{Binding TheChosenOne}" />
</StackLayout>
</ContentPage.Content>

Listbox databinding NewItemPlaceholder

I have an observable collection bound to a list box.
The collection has 2 items, but the list box is showing 3 items (e.g. the 2 items that are actually in the observable collection and an additional item for the NewItemPlaceholder.
I want it only to show the 2 items.
Below is my XAML.
<ListBox MinHeight="20" MinWidth="20" Name="MultipleSelectionsMultipleWagersListBox" Visibility="{Binding Path=Coupon.BarcodeText, Converter={StaticResource CouponBarcodeToVisibilityConverter1}, ConverterParameter=994450_994550}" Height="AUto" Width="Auto" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Margin="5"
ItemsSource="{Binding Path=BetViewModels}" Grid.Row="1" Grid.Column="1" >
<ListBox.ItemTemplate>
<DataTemplate>
<View:BetView DataContext="{Binding}" Name="ThisBet" Margin="5"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Here is the c#
private ObservableCollection<BetViewModel> _betViewModels = new ObservableCollection<BetViewModel>();
public ObservableCollection<BetViewModel> BetViewModels
{
get { return _betViewModels; }
set
{
if (Equals(value, _betViewModels)) return;
_betViewModels = value;
OnPropertyChanged("BetViewModels");
}
}
Here is the code to populate the betViewModels:
var betViewModel = new BetViewModel { Bet = new Bet() };
betViewModel.Bet.SelectionName = "Chelsea";
betViewModel.Bet.Price = "4/9";
betViewModel.Bet.Market = "90 Minutes";
betViewModel.Bet.ExpectedOdd = DateTime.Now;
BetViewModels.Add(betViewModel);
betViewModel = new BetViewModel { Bet = new Bet() };
betViewModel.Bet.SelectionName = "Chelsea";
betViewModel.Bet.Price = "4/9";
betViewModel.Bet.Market = "90 Minutes";
betViewModel.Bet.ExpectedOdd = DateTime.Now;
BetViewModels.Add(betViewModel);
How Do I switch of this from showing the additional item for the new item place
Here is an image of it displaying the placeholder
The DataGrid supports adding new rows, which have to start out blank. If your ItemsSource is bound to both a ListBox/ItemsControl and a DataGrid, you need to set the DataGrid 'CanUserAddRows' property to 'False'.
Where I found the answer: http://www.mindstick.com/Forum/1519/How%20do%20I%20remove%20a%20listbox%20new%20item%20placeholder
There's nothing in your code that should be adding an extra empty item. There may be some other code adding to BetViewModels or there may be a change happening to the generated ICollectionView for the collection if you have it bound to something else that you're not showing, like an editable DataGrid.
did your sample code also provide this issue?
how much items contains your _betViewModels.count in debugging there are really only 2 Items?
it seems you added an empty BetViewModel at the End
i would suggest check your logic which provides populates your items
if it is a loop it should (counter<yourDatasource.Count) just for example

Categories