Memory leak handling Xamarin.Forms - c#

I have a memory leak issue in my application which I have created with Xamarin.Forms. My app consists of A ListView with Images. If I click on an item and come back to the ListPage I can see a memory hog in my Output window. I have tried calling GC.Collect() in OnDisappearing() of my ContentPage.
I have seen a base.Dispose() in my Android project. But I don't know how to use it.
ArticleListPage.xaml
<?xml version="1.0" encoding="utf-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:converters="clr-namespace:NewsArticles.Mobile.Converters;assembly=Something.NewsArticles.Mobile"
xmlns:themes="clr-namespace:NewsArticles.Mobile.Themes;assembly=Something.NewsArticles.Mobile"
x:Class="NewsArticles.Mobile.Pages.ArticlesListPage"
Title="{Binding PageTitle, Mode=OneWay}"
BackgroundColor="{x:Static themes:ColorResources.ArticleListPageBackgroundColor}">
<RelativeLayout>
<ContentPage.Resources>
<ResourceDictionary>
<converters:BooleanNegationConverter x:Key="booleanNegationConverter" />
<converters:StringToImageSourceConverter x:Key="stringToImageSourceConverter" />
</ResourceDictionary>
</ContentPage.Resources>
<ListView x:Name="ArticlesList"
StyleId="ArticlesList"
Grid.Row="1"
IsVisible="{Binding IsProcessing, Mode=OneWay, Converter={StaticResource booleanNegationConverter}}">
<ListView.BackgroundColor>
<OnPlatform x:TypeArguments="Color" iOS="Transparent" />
</ListView.BackgroundColor>
<ListView.RowHeight>
<OnPlatform x:TypeArguments="x:Int32" iOS="150" Android="180" WinPhone="170" />
</ListView.RowHeight>
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<ContentView BackgroundColor="{x:Static themes:ColorResources.ArticleListViewBackgroundColor}">
<ContentView.Padding>
<OnPlatform x:TypeArguments="Thickness"
iOS="10,5"
Android="10,10"
WinPhone="10,10" />
</ContentView.Padding>
<Grid BackgroundColor="White" Padding="10">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="120"/>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Image Grid.Column="0"
Source="{Binding ImageUrl, Mode=OneWay, Converter={StaticResource stringToImageSourceConverter}}"
HorizontalOptions="FillAndExpand"
Aspect="AspectFill" />
<Grid Grid.Column="1" RowSpacing="0">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="20" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Label Grid.Row="0" Text="{Binding Title, Mode=OneWay}"
VerticalOptions="Start"
LineBreakMode="WordWrap"
TextColor="{x:Static themes:ColorResources.MainArticleTitleColor}"
Font="{x:Static themes:FontResources.ListArticleTitle}" />
<ContentView Grid.Row="1" Padding="0,2">
<Label Text="{Binding Author, Mode=OneWay }"
TextColor="Silver"
Font="{x:Static themes:FontResources.VerySmall}" />
</ContentView>
<Label Grid.Row="2" Text="{Binding Body, Mode=OneWay}"
LineBreakMode="TailTruncation"
TextColor="Gray"
Font="{x:Static themes:FontResources.VerySmall}" />
</Grid>
</Grid>
</ContentView>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ContentPage>

I had this problem a while back and this article solved it for me.
Basically you need to make a custom Renderer and place that in your droid project:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Views.InputMethods;
using Android.Widget;
using Android.Util;
using Application.Droid.CustomControls;
using ApplicationClient.CustomControls;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
[assembly: ExportRenderer(typeof(ApplicationClient.CustomControls.LSImage), typeof(LSImageRenderer))]
namespace Application.Droid.CustomControls
{
public class LSImageRenderer : ImageRenderer
{
Page page;
NavigationPage navigPage;
protected override void OnElementChanged(ElementChangedEventArgs<Image> e)
{
base.OnElementChanged(e);
if (e.OldElement == null)
{
if (GetContainingViewCell(e.NewElement) != null)
{
page = GetContainingPage(e.NewElement);
if (page.Parent is TabbedPage)
{
page.Disappearing += PageContainedInTabbedPageDisapearing;
return;
}
navigPage = GetContainingNavigationPage(page);
if (navigPage != null)
navigPage.Popped += OnPagePopped;
}
else if ((page = GetContainingTabbedPage(e.NewElement)) != null)
{
page.Disappearing += PageContainedInTabbedPageDisapearing;
}
}
}
void PageContainedInTabbedPageDisapearing (object sender, EventArgs e)
{
this.Dispose(true);
page.Disappearing -= PageContainedInTabbedPageDisapearing;
}
protected override void Dispose(bool disposing)
{
Log.Info("**** LSImageRenderer *****", "Image got disposed");
base.Dispose(disposing);
}
private void OnPagePopped(object s, NavigationEventArgs e)
{
if (e.Page == page)
{
this.Dispose(true);
navigPage.Popped -= OnPagePopped;
}
}
private Page GetContainingPage(Xamarin.Forms.Element element)
{
Element parentElement = element.ParentView;
if (typeof(Page).IsAssignableFrom(parentElement.GetType()))
return (Page)parentElement;
else
return GetContainingPage(parentElement);
}
private ViewCell GetContainingViewCell(Xamarin.Forms.Element element)
{
Element parentElement = element.Parent;
if (parentElement == null)
return null;
if (typeof(ViewCell).IsAssignableFrom(parentElement.GetType()))
return (ViewCell)parentElement;
else
return GetContainingViewCell(parentElement);
}
private TabbedPage GetContainingTabbedPage(Element element)
{
Element parentElement = element.Parent;
if (parentElement == null)
return null;
if (typeof(TabbedPage).IsAssignableFrom(parentElement.GetType()))
return (TabbedPage)parentElement;
else
return GetContainingTabbedPage(parentElement);
}
private NavigationPage GetContainingNavigationPage(Element element)
{
Element parentElement = element.Parent;
if (parentElement == null)
return null;
if (typeof(NavigationPage).IsAssignableFrom(parentElement.GetType()))
return (NavigationPage)parentElement;
else
return GetContainingNavigationPage(parentElement);
}
}
}
Then Extend the Image class and place that in the PCL, or wherever your pages reside.
namespace ApplicationClient.CustomControls
{
public class LSImage : Image
{
}
}
Then you have to modify the XAML to work with this as well.
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:ctrls="clr-namespace:ApplicationClient.CustomControls;assembly=ApplicationClient"
... >
<ctrls:LSImage ... />
</ContentPage>

Related

Cannot reach xaml element from cs file in Xamarin.Forms

I have a XAML page. In this page i have x:Name="grid1", x:Name="stackY", x:Name="mylabel". I try to reach grid1 and stackY and mylabel from cs file. I write grid1.... or mylabel.... but cs file does not recognise grid1 and stackY and mylabel in cs file. It throws error as "The name 'mylable' does not exist in the current context". I am using Visual Studio 2019 and Xamarin.Forms.
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:XCMob"
x:Class="XCMob.testpage3"
Title ="Expendable ListView "
BackgroundColor="Bisque">
<ContentPage.BindingContext>
<local:MainListView/>
</ContentPage.BindingContext>
<ListView x:Name="list1" Margin="0,80"
ItemTapped="ListViewItem_Tabbed"
ItemsSource="{Binding Products}"
HasUnevenRows="True"
BackgroundColor="Black">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout x:Name="stackY" Padding="20">
<Label Text="{Binding Title}"
FontSize="25"
TextColor="Azure"/>
<StackLayout x:Name="stackX" IsVisible="{Binding Isvisible}"
Orientation="Horizontal"
Margin="0,0,80,0">
<Button Text="Place Order"
WidthRequest="110"
FontSize="15"
BackgroundColor="Chocolate"
TextColor="White"/>
<Grid x:Name="grid1">
<Label x:Name="mylabel" Text="....." TextColor="White" HorizontalTextAlignment="Center" HorizontalOptions="Center" VerticalOptions="CenterAndExpand" FontSize="Large"/>
</Grid>
</StackLayout>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
CS file is :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace XCMob
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class testpage3 : ContentPage
{
public testpage3()
{
InitializeComponent();
}
private void ListViewItem_Tabbed(object sender, ItemTappedEventArgs e)
{
var product = e.Item as Product;
var vm = BindingContext as MainListView;
vm?.ShoworHiddenProducts(product);
}
void showit()
{
mylabel.Text = "xxxxxxx";
}
}
}

Binding in generic control is null

I have several generic buttons. Both title and the corresponding icon are displayed correctly, but the tap function does not work.
HomePage.xaml with the ScanningApp control
<?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="primetals.ScannerApp.Views.HomePage"
xmlns:controls="clr-namespace:primetals.ScannerApp.Controls"
xmlns:resource="clr-namespace:primetals.ScannerApp"
xmlns:prism="clr-namespace:Prism.Mvvm;assembly=Prism.Forms"
prism:ViewModelLocator.AutowireViewModel="True"
BackgroundColor="White"
x:Name="self"
Title="{Binding Title}">
<ContentPage.Resources>
<ResourceDictionary>
<Style TargetType="controls:ScanningApp">
<Setter Property="WidthRequest" Value="220"></Setter>
<Setter Property="HeightRequest" Value="220"></Setter>
</Style>
</ResourceDictionary>
</ContentPage.Resources>
<Grid Margin="10">
<Grid.RowDefinitions>
<RowDefinition Height="3*"></RowDefinition>
<RowDefinition Height="3*"></RowDefinition>
<RowDefinition x:Name="backgroundImageRow" Height="4*"></RowDefinition>
</Grid.RowDefinitions>
<StackLayout Grid.Row="0" HorizontalOptions="CenterAndExpand" Margin="0,10,0,10">
<!-- Application Logo -->
<Image Source="icon_scannerapp.png" WidthRequest="96" HeightRequest="96"></Image>
<!-- Welcome Text -->
<Label Text="{x:Static resource:ApplicationResources.WelcomeMessageLine1}" FontSize="Large">
</Label>
<Label FontSize="Large">
<Label.FormattedText>
<FormattedString>
<Span Text="{x:Static resource:ApplicationResources.WelcomeMessageLine2}"></Span>
<Span Text="{x:Static resource:ApplicationResources.WelcomeMessageSpareParts}" FontAttributes="Bold" FontSize="Large"></Span>
<Span Text="{x:Static resource:ApplicationResources.WelcomeMessageOr}"></Span>
<Span Text="{x:Static resource:ApplicationResources.WelcomeMessageSensorData}" FontAttributes="Bold" FontSize="Large"></Span>
<Span Text="!"></Span>
</FormattedString>
</Label.FormattedText>
</Label>
</StackLayout>
<!-- Scanning Applications -->
<StackLayout Orientation="Horizontal" Grid.Row="1" BindableLayout.ItemsSource="{Binding Apps}" HorizontalOptions="Center" VerticalOptions="Start">
<BindableLayout.ItemTemplate>
<DataTemplate>
<controls:ScanningApp Margin="0,0,5,0"
ImageSource="{Binding ImageUrl}"
TapImageSource="{Binding TapImageUrl}"
Text="{Binding Title}"
TappedCommand="{Binding BindingContext.AppTappedCommand, Source={x:Reference self}}"
TappedCommandParameter="{Binding}">
</controls:ScanningApp>
</DataTemplate>
</BindableLayout.ItemTemplate>
</StackLayout>
<!-- Background Image -->
<Image x:Name="backgroundImage" Grid.Row="2" Source="background_scannerapp_PT.jpg" Aspect="AspectFit" HorizontalOptions="Fill" VerticalOptions="Fill"></Image>
</Grid>
</ContentPage>
HomepageViewModel.cs:
AppTappedCommand is set correctly
this.AppTappedCommand = new DelegateCommand<ScanApplication>((app) => OnGotoScanPage(app));
this.Title = ApplicationResources.ApplicationTitleCaption;
public async void OnGotoScanPage(ScanApplication app)
{
NavigationParameters parameters = new NavigationParameters();
parameters.Add(Constants.Parameters.App, app.AppId);
await this.NavigationService.NavigateAsync($"{nameof(ScanPage)}", parameters);
}
ScanningApp.xaml.cs:
After Clicking the button TappedCommand is null.
public static readonly BindableProperty TappedCommandProperty = BindableProperty.Create(nameof(TappedCommand), typeof(ICommand), typeof(ScanningApp), default(ICommand), Xamarin.Forms.BindingMode.OneWay);
public ICommand TappedCommand
{
get
{
return (ICommand)GetValue(TappedCommandProperty);
}
set
{
SetValue(TappedCommandProperty, value);
}
}
public static readonly BindableProperty TappedCommandParameterProperty = BindableProperty.Create(nameof(TappedCommandParameter), typeof(object), typeof(ScanningApp), null, Xamarin.Forms.BindingMode.OneWay);
public object TappedCommandParameter
{
get
{
return GetValue(TappedCommandParameterProperty);
}
set
{
SetValue(TappedCommandParameterProperty, value);
}
}
private bool OnExecuteTap()
{
img.Source = this.ImageSource;
if (this.TappedCommand != null && this.TappedCommand.CanExecute(this.TappedCommandParameter))
{
this.TappedCommand.Execute(this.TappedCommandParameter);
}
return false;
}
ScanningApp.xaml
<?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="clr-namespace:Prism.Mvvm;assembly=Prism.Forms"
prism:ViewModelLocator.AutowireViewModel="True"
x:Class="primetals.ScannerApp.Controls.ScanningApp"
x:Name="self">
<Grid Padding="1" BackgroundColor="{StaticResource PrimetalsLightGrayColor}">
<Grid>
<Grid.GestureRecognizers>
<TapGestureRecognizer Tapped="TapGestureRecognizer_Tapped"></TapGestureRecognizer>
</Grid.GestureRecognizers>
<Grid.RowDefinitions>
<RowDefinition Height="5*"></RowDefinition>
<RowDefinition Height="1*" ></RowDefinition>
</Grid.RowDefinitions>
<Image x:Name="img" Grid.Row="0" Source="{Binding ImageSource, Source={x:Reference self}}" Aspect="AspectFit" VerticalOptions="CenterAndExpand"
Margin="20"></Image>
<Label Grid.Row="1" Text="{Binding Text, Source={x:Reference self}}"
Margin="10,0,10,10"
FontSize="Medium" TextColor="{StaticResource PrimetalsAccentColor}"
VerticalTextAlignment="Center" HorizontalTextAlignment="Center"></Label>
</Grid>
</Grid>
</ContentView>
Originally this sourcecode worked (about one year ago) (but there may be problems with new packages in VS). I hope you can help me. Thanks a lot!
br
It seems that there should be a TapGestureRecognizer_Tapped event handler in ScanningApp.xaml.cs from your code.
<TapGestureRecognizer Tapped="TapGestureRecognizer_Tapped"></TapGestureRecognizer>
So you could do like :
private void TapGestureRecognizer_Tapped(object sender, EventArgs e)
{
img.Source = this.ImageSource;
if (this.TappedCommand != null && this.TappedCommand.CanExecute(this.TappedCommandParameter))
{
this.TappedCommand.Execute(this.TappedCommandParameter);
}
}

Picker not showing Items

Am new in xamarin forms,i have a picker and populated it with items but it can't display the items.here is my code.
Picker in Xaml
<StackLayout Margin="1">
<Picker x:Name="curr_picker" Title="select currency">
</Picker>
</StackLayout>
How i populated it in cs
curr_picker.Items.Add("UGX");
curr_picker.Items.Add("USD");
curr_picker.Items.Add("JPY");
Here is my full code
xaml
ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="FX2.ForexRates"
Title="Forex Rates"
>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height=".3*" />
<RowDefinition Height=".7*" />
</Grid.RowDefinitions>
<StackLayout Orientation="Vertical">
<!--Frame 1 -->
<Frame Margin="5" HasShadow="True" BackgroundColor="White" >
<Frame.OutlineColor>
<OnPlatform x:TypeArguments="Color" Android="Gray" iOS="#DCDCDC" />
</Frame.OutlineColor>
<StackLayout Orientation="Vertical">
<Image Source="searchbox.png" HorizontalOptions="EndAndExpand"/>
<Image Source="flag_uganda.png" HorizontalOptions="StartAndExpand"/>
</StackLayout>
</Frame>
<Frame Margin="5" HasShadow="True" BackgroundColor="White" >
<Frame.OutlineColor>
<OnPlatform x:TypeArguments="Color" Android="Gray" iOS="#DCDCDC" />
</Frame.OutlineColor>
<StackLayout Orientation="Vertical">
<Label Text="UGANDA" HorizontalOptions="Center" TextColor="#5dade2"/>
<Image Source="searchbox.png" HorizontalOptions="EndAndExpand"/>
<Label Text="Compare With" HorizontalOptions="Center" TextColor="#5dade2"/>
<StackLayout Margin="1">
<Picker x:Name="curr_picker" Title="select currency">
</Picker>
</StackLayout>
<Picker x:Name="option_picker" Title="BUY or SELL">
</Picker>
<Button Text="VIEW RATES" BackgroundColor="#0711a7" HorizontalOptions="FillAndExpand" TextColor="White" HeightRequest="65" Clicked="Button_Clicked"/>
</StackLayout>
</Frame>
</StackLayout>
</Grid>
</ContentPage>
cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace FX2
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class ForexRates : ContentPage
{
public ForexRates()
{
InitializeComponent();
curr_picker.Items.Add("UGX");
curr_picker.Items.Add("USD");
curr_picker.Items.Add("JPY");
option_picker.Items.Add("BUY");
option_picker.Items.Add("SELL");
}
private void Button_Clicked(object sender, EventArgs e)
{
//await Navigation.PushAsync(new MainActivity());
}
}
}
If you are using newest Xamarin.Forms, like version 2.5 or later, you probably should use ItemsSource instead of Items for data binding. In XAML it will look like this:
<Picker x:Name="picker">
<Picker.ItemsSource>
<x:Array Type="{x:Type x:String}">
<x:String>Baboon</x:String>
<x:String>Capuchin Monkey</x:String>
<x:String>Blue Monkey</x:String>
</x:Array>
</Picker.ItemsSource>
</Picker>
In CS like this:
var monkeyList = new List<string>();
monkeyList.Add("Baboon");
monkeyList.Add("Capuchin Monkey");
monkeyList.Add("Blue Monkey");
picker.ItemsSource = monkeyList;
Instead of simple string you can also use complex types, check more here:
https://developer.xamarin.com/guides/xamarin-forms/user-interface/picker/populating-itemssource/
From the docs:
However, a Picker doesn't show any data when it's first displayed. Instead, the value of its Title property is shown as a placeholder on the iOS and Android platforms:
When the Picker gains focus, its data is displayed and the user can select an item:

ListBox doesn't refresh?

i have an issue on Visual Studio(wpf) with the listbox.
If i want to insert or delete some data from the database, then they are working,but the listbox will just be refreshed if i'm clicking the menuitem for once. I think this is due to the load method, but why isn't it refreshing the data?
This is my XAML-Code:
<UserControl x:Class="WpfApplication1.AutorenBearbeiten"
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"
xmlns:local="clr-namespace:WpfApplication1"
mc:Ignorable="d"
d:DesignHeight="400" d:DesignWidth="300" Loaded="UserControl_Loaded">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="28*" />
<ColumnDefinition Width="36*" />
</Grid.ColumnDefinitions>
<TextBlock Text="Medien" Grid.ColumnSpan="2"
FontSize="16" />
<ListBox x:Name="box" Grid.Row="1">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=at_nachname}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<StackPanel DataContext="{Binding ElementName=box,Path=SelectedItem}" Grid.Column="1" Grid.Row="1" >
<TextBlock Text="Autoren_id" />
<TextBox Text="{Binding Path=at_id}" MaxLength="5"/>
<TextBlock Text="Vorname" />
<TextBox Text="{Binding Path=at_vorname}" MaxLength="30"/>
<TextBlock Text="Nachname" />
<TextBox Text="{Binding Path=at_nachname}" MaxLength="30"/>
<TextBlock Text="Geburtsdatum" />
<TextBox MaxLength="30" Text="{Binding Path=at_gebDatum, StringFormat=dd.MM.yyyy}" />
<Button Name="speichern" Height="23" Margin="4" Click="speichern_Click">Änderungen speichern</Button>
<Button Name="loeschen" Height="23" Margin="4" Click="loeschen_Click">Löschen</Button>
<StackPanel DataContext="{Binding ElementName=box}" Grid.Column="1" Grid.Row="1" >
<TextBlock Text="Autoren_id" />
<TextBox x:Name="id" MaxLength="5"/>
<TextBlock Text="Vorname" />
<TextBox x:Name="vorname" MaxLength="30"/>
<TextBlock Text="Nachname" />
<TextBox x:Name="nachname" MaxLength="30"/>
<TextBlock Text="Geburtsdatum" />
<TextBox x:Name="datum" MaxLength="30"/>
<Button x:Name="neubutton" Height="23" Margin="4" Click="neu_Click">Neu</Button>
<TextBlock Name="submitfehler" FontWeight="Bold" Foreground="Red" />
</StackPanel>
</StackPanel>
</Grid>
</UserControl>
And this is the xaml.cs file :
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace WpfApplication1
{
/// <summary>
/// Interaction logic for AutorenBearbeiten.xaml
/// </summary>
public partial class AutorenBearbeiten : UserControl
{
libraryEntities6 db = new libraryEntities6();
public AutorenBearbeiten()
{
InitializeComponent();
}
private void UserControl_Loaded(object sender, RoutedEventArgs e)
{
var erg = db.a_autor;
erg.Load();
box.ItemsSource = erg.Local.OrderBy(m => m.at_id);
box.ItemsSource =
(from m in db.a_autor
orderby m.at_id
select m).ToList();
}
private void speichern_Click(object sender, RoutedEventArgs e)
{
try
{
db.SaveChanges();
}
catch(Exception e1)
{
submitfehler.Text = e1.Message;
}
}
private void loeschen_Click(object sender, RoutedEventArgs e)
{
a_autor am = (a_autor)box.SelectedItem;
if (am != null)
{
db.a_autor.Remove(am);
db.SaveChanges();
box.Items.Refresh();
}
}
private void neu_Click(object sender, RoutedEventArgs e)
{
a_autor autor = new a_autor();
autor.at_id = id.Text;
autor.at_vorname = vorname.Text;
autor.at_nachname = nachname.Text;
autor.at_gebDatum = Convert.ToDateTime(datum.Text);
//s1.s_k_klasse = liklassen.SelectedValue.ToString() setzt die Klasse via foreign key
//db.schuelers.AddObject(s1);
db.a_autor.Add(autor);
box.Items.Refresh();
/*
((klassen))liklassen.SelectedItem).schuelers.Add(s1); //setzt die klasse durch zuweisen zum nav.Property
lischueler.Items.Refresh(); //nötig weil das navigational seit ER 5 nicht observable ist
*/
}
}
}
A Picture from the window is below:
Window
There is no magic connection between the ListBox and the database so when you are calling the Add or Remove method of the DbContext the ListBox won't be affected.
What you should do is to set the ItemsSource property of the ListBox to an ObservableCollection<a_autor> and then call the Add/Remove method of this one besides calling the Add/Remove method of the DbContext:
System.Collections.ObjectModel.ObservableCollection<a_autor> _sourceCollection;
private void UserControl_Loaded(object sender, RoutedEventArgs e)
{
var erg = db.a_autor;
erg.Load();
_sourceCollection = new System.Collections.ObjectModel.ObservableCollection<a_autor>((from m in db.a_autor
orderby m.at_id
select m).ToList());
box.ItemsSource = _sourceCollection;
}
private void loeschen_Click(object sender, RoutedEventArgs e)
{
a_autor am = (a_autor)box.SelectedItem;
if (am != null)
{
_sourceCollection.Remove(am);
db.a_autor.Remove(am);
db.SaveChanges();
box.Items.Refresh();
}
}
private void neu_Click(object sender, RoutedEventArgs e)
{
a_autor autor = new a_autor();
autor.at_id = id.Text;
autor.at_vorname = vorname.Text;
autor.at_nachname = nachname.Text;
autor.at_gebDatum = Convert.ToDateTime(datum.Text);
_sourceCollection.Add(autor);
db.a_autor.Add(autor);
box.Items.Refresh();
}
You can create an ObservableCollection instead of binding to the List. ObservableCollection implements INotifyPropertyChanged so it can send a notification whenever something is changed in the container.
Also, I would suggest you to try
public void RefreshListBox()
{
box.ItemsSource =
(from m in db.a_autor
orderby m.at_id
select m).ToList();
}
and call this after db.SaveChanges()
You should use MVVM pattern instead of code behind and use property changes. First result in Google:
https://www.codeproject.com/Articles/819294/WPF-MVVM-step-by-step-Basics-to-Advance-Level
I hope it helps you.
Juan

Border Color for Editor in Xamarin.Forms

How can i make a border color for Editor in Xamarin.Forms?
I used this link, but it works only for Android. I want it to work in all platforms!
I'm a little bit newbie to this.
Please help me.
Any idea?
You may also archieve this by wrapping your Editor with a StackLayout with BackgroundColor="your color" and Padding="1" and set the BackgroundColor of your Editor to the same color of the form.
Something like this:
<StackLayout BackgroundColor="White">
<StackLayout BackgroundColor="Black" Padding="1">
<Editor BackgroundColor="White" />
</StackLayout>
...
</StackLayout>
Not that fancy, but this will at least get you a border!
Here's the complete solution I used. You need three things.
1 - A custom class that implements Editor in your forms project.
public class BorderedEditor : Editor
{
}
2 - A custom renderer for your custom Editor in your iOS project.
public class BorderedEditorRenderer : EditorRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Editor> e)
{
base.OnElementChanged(e);
if (Control != null)
{
Control.Layer.CornerRadius = 3;
Control.Layer.BorderColor = Color.FromHex("F0F0F0").ToCGColor();
Control.Layer.BorderWidth = 2;
}
}
}
3 - An ExportRenderer attribute in your iOS project that tells Xamarin to use your custom renderer for your custom editor.
[assembly: ExportRenderer(typeof(BorderedEditor), typeof(BorderedEditorRenderer))]
Then use your custom editor in Xaml:
<custom:BorderedEditor Text="{Binding TextValue}"/>
The easiest way is to add a frame around it.
<Frame BorderColor="LightGray" HasShadow="False" Padding="0">
<Editor/>
</Frame>
in your portable project add this control
public class PlaceholderEditor : Editor
{
public static readonly BindableProperty PlaceholderProperty =
BindableProperty.Create("Placeholder", typeof(string), typeof(string), "");
public PlaceholderEditor()
{
}
public string Placeholder
{
get
{
return (string)GetValue(PlaceholderProperty);
}
set
{
SetValue(PlaceholderProperty, value);
}
}
}
in your android project add this renderer:
[assembly: ExportRenderer(typeof(PlaceholderEditor), typeof(PlaceholderEditorRenderer))]
namespace Tevel.Mobile.Packages.Droid
{
public class PlaceholderEditorRenderer : EditorRenderer
{
public PlaceholderEditorRenderer() { }
protected override void OnElementChanged(ElementChangedEventArgs<Editor> e)
{
base.OnElementChanged(e);
if (e.NewElement != null)
{
var element = e.NewElement as PlaceholderEditor;
this.Control.Background = Resources.GetDrawable(Resource.Drawable.borderEditText);
this.Control.Hint = element.Placeholder;
}
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
if (e.PropertyName == PlaceholderEditor.PlaceholderProperty.PropertyName)
{
var element = this.Element as PlaceholderEditor;
this.Control.Hint = element.Placeholder;
}
}
}
}
in your Resources > drawable add an XML file borderEditText.xml
<?xml version="1.0" encoding="UTF-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_focused="true">
<shape android:shape="rectangle">
<gradient
android:startColor="#FFFFFF"
android:endColor="#FFFFFF"
android:angle="270" />
<stroke
android:width="3dp"
android:color="#F8B334" />
<corners android:radius="12dp" />
</shape>
</item>
<item>
<shape android:shape="rectangle">
<gradient android:startColor="#FFFFFF" android:endColor="#FFFFFF" android:angle="270" />
<stroke android:width="3dp" android:color="#ccc" />
<corners android:radius="12dp" />
</shape>
</item>
</selector>
Xaml:
Header - xmlns:ctrls="clr-namespace:my control namespace;assembly= my assembly"
control:
<ctrls:PlaceholderEditor VerticalOptions="Fill" HorizontalOptions="StartAndExpand" Placeholder="add my comment title">
</ctrls:PlaceholderEditor>
You will need to implement a Custom Renderer (guide from Xamarin) for each platform since customizing the BorderColor of an Entry is not yet supported in Xamarin.Forms.
Since you've already managed to change the BorderColor on Android, you can find a solution for iOS here: http://forums.xamarin.com/discussion/comment/102557/#Comment_102557
This works for sure, try this.
Android Renderer
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
using Android.Graphics;
[assembly: ExportRenderer(typeof(Entry), typeof(some.namespace.EntryRenderer))]
namespace some.namespace
{
public class EntryRenderer : Xamarin.Forms.Platform.Android.EntryRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
{
base.OnElementChanged(e);
if (Control == null || Element == null || e.OldElement != null) return;
var customColor = Xamarin.Forms.Color.FromHex("#0F9D58");
Control.Background.SetColorFilter(customColor.ToAndroid(), PorterDuff.Mode.SrcAtop);
}
}
}
easy way to android renderer
if (((Editor)Element).HasBorder)
{
GradientDrawable gd = new GradientDrawable();
gd.SetColor(Android.Resource.Color.HoloRedDark);
gd.SetCornerRadius(4);
gd.SetStroke(2, Android.Graphics.Color.LightGray);
Control.SetBackground(gd);
}
Build a Custom Control as a Grid. Build BoxViews around it and place the Editor in the middle with margin.
Not nice but simple...
<Grid xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:CustomControls="clr-namespace:xxx.CustomControls"
x:Class="xxx.CustomControls.EditorWithBorder" BackgroundColor="White"
x:Name="this">
<Grid.RowDefinitions>
<RowDefinitionCollection>
<RowDefinition Height="1"/>
<RowDefinition Height="1*"/>
<RowDefinition Height="1"/>
</RowDefinitionCollection>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinitionCollection>
<ColumnDefinition Width="1"/>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="1"/>
</ColumnDefinitionCollection>
</Grid.ColumnDefinitions>
<Editor Text="{Binding Source={x:Reference this},Path=EditorText, Mode=TwoWay}" TextColor="Orange" Margin="20,10,20,10" FontSize="{StaticResource FontSizeLarge}"
Grid.Row="1" Grid.Column="1" />
<BoxView Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="3" BackgroundColor="Orange"
></BoxView>
<BoxView Grid.Row="0" Grid.Column="0" Grid.RowSpan="3" BackgroundColor="Orange"
></BoxView>
<BoxView Grid.Row="0" Grid.Column="2" Grid.RowSpan="3" BackgroundColor="Orange" HeightRequest="1"
></BoxView>
<BoxView Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="3" BackgroundColor="Orange" HeightRequest="1"
></BoxView>
</Grid>

Categories