I followed the guide here to save my ViewState into the database. I did some changes to it to fit my projects code design, but the essential parts are there. But when I implant this solution all my asp:ImageButtons events stops working, but regular asp:Buttons seems to work. Why doesn't the events from asp:ImageButtons work?
Code:
public class DatabasePageStatePersister : PageStatePersister
{
//This object handles the saving and loading from database
CiroLightLibrary.BLL.ViewState myViewState;
public DatabasePageStatePersister(Page p, string GUID): base(p)
{
myViewState = new CiroLightLibrary.BLL.ViewState();
myViewState.GUID = GUID;
}
public override void Load()
{
myViewState.Load();
this.ViewState = this.StateFormatter.Deserialize(myViewState.Value);
}
public override void Save()
{
myViewState.Value = this.StateFormatter.Serialize(this.ViewState);
myViewState.Save();
}
}
public class PageViewStateDatabaseStored : Page
{
private PageStatePersister _PageStatePersister;
protected override System.Web.UI.PageStatePersister PageStatePersister
{
get
{
if (_PageStatePersister == null)
{
CiroLightLibrary.BLL.ViewState myViewState = new ViewState();
if (Request["__DATABASE_VIEWSTATE"] != null)
myViewState.GUID = Request["__DATABASE_VIEWSTATE"].ToString();
else
myViewState.GUID = Guid.NewGuid().ToString();
_PageStatePersister = new DatabasePageStatePersister(this, myViewState.GUID);
Literal l = new Literal();
l.Text = "<div><input type=\"hidden\" name=\"__DATABASE_VIEWSTATE\" value=\"" + myViewState.GUID + "\" /></div>";
this.Form.Controls.Add(l);
}
return _PageStatePersister;
}
}
}
And heres a Test page:
public partial class test : PageViewStateDatabaseStored
{
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
imgButton1.CommandArgument = "1";
btnButton1.CommandArgument = "1";
}
}
protected void imgButton_OnCommand(object sender, CommandEventArgs e)
{
Response.Write(e.CommandArgument.ToString());
}
protected void imgButton_OnClick(object sender, EventArgs e)
{
Response.Write("Click");
}
}
Asp.net Page
<form runat="server">
<asp:ImageButton ID="imgButton1" runat="server" OnCommand="imgButton_OnCommand" />
<asp:ImageButton ID="imgButton2" runat="server" OnClick="imgButton_OnClick" />
<asp:Button ID="btnButton1" runat="server" OnCommand="imgButton_OnCommand" />
<asp:Button ID="btnButton2" runat="server" OnClick="imgButton_OnClick" />
</form>
I tried to override LoadPageStateFromPersistenceMedium() and SavePageStateToPersistenceMedium() instead, and now my asp:ImageButtons also fires the events.
public class PageViewStateDatabaseStored : Page
{
protected override object LoadPageStateFromPersistenceMedium()
{
CiroLightLibrary.BLL.ViewState myViewState = new ViewState();
if (Request["__DATABASE_VIEWSTATE"] != null)
{
myViewState.GUID = Request["__DATABASE_VIEWSTATE"].ToString();
myViewState.Load();
}
LosFormatter myFormatter = new LosFormatter();
return myFormatter.Deserialize(myViewState.Value);
}
protected override void SavePageStateToPersistenceMedium(object viewState)
{
CiroLightLibrary.BLL.ViewState myViewState = new ViewState();
if (Request["__DATABASE_VIEWSTATE"] != null)
myViewState.GUID = Request["__DATABASE_VIEWSTATE"].ToString();
else
myViewState.GUID = Guid.NewGuid().ToString();
LosFormatter myFormatter = new LosFormatter();
StringWriter myStringWriter = new StringWriter();
myFormatter.Serialize(myStringWriter, viewState);
myViewState.Value = myStringWriter.ToString();
myViewState.Save();
ScriptManager.RegisterHiddenField(this, "__DATABASE_VIEWSTATE", myViewState.GUID);
}
}
I know this is an old post.... But the answer is simply that you're saving the viewstate not the controlstate.
public override void Load()
{
myViewState.Load();
var pair = (Pair)this.StateFormatter.Deserialize(myViewState.Value);
this.ViewState = pair.First;
this.ControlState = pair.Second;
}
public override void Save()
{
myViewState.Value = this.StateFormatter.Serialize(new Pair(this.ViewState, this.ControlState));
myViewState.Save();
}
Personally I'd inherit my PageStatePersister from HiddenFieldPageStatePersister then in my save method write the guid into the viewstate property and set the controlstate to null, then call the base Save method. In the Load, call the load the base.load then get the GUID from the viewstate property before pushing the db aquired values into the viewstate, controlstate properties. That way we're not modifying the control tree.... Like so:
public class MyPageStatePersister : System.Web.UI.HiddenFieldPageStatePersister
{
public MyPageStatePersister(Page page)
: base(page)
{
}
public override void Load()
{
base.Load();
this.CurrentKey = (Guid)this.ViewState;
var s = this.CurrentKey;
var state = SomeDAOManager.GetState(s);
if (state != null)
{
this.ViewState = state.First;
this.ControlState = state.Second;
}
else
{
this.ControlState = null;
this.ViewState = null;
}
}
public Guid CurrentKey {get;set;}
public override void Save()
{
if (CurrentKey == Guid.Empty)
{
this.CurrentKey = Guid.NewGuid();
}
Guid guid = CurrentKey;
SomeDAOManager.SaveState(guid, new Pair(this.ViewState, this.ControlState));
this.ViewState = guid;
this.ControlState = null;
base.Save();
}
}
Related
I thought that my bug was a Xamarin Forms issue because there was no bug in XF3.4, but it appeared after I upgraded to XF4.4.
Just to make sure, I want to show you guys the code. I have a XAML page with the loading icon:
<ActivityIndicator IsRunning="{Binding Loading}"
IsVisible="{Binding Loading}"
AbsoluteLayout.LayoutFlags="All"
AbsoluteLayout.LayoutBounds="0.5, 0.5, 0.2, 0.2">
<ActivityIndicator.Color>
<OnPlatform x:TypeArguments="Color" iOS="#2499CE" WinPhone="#2499CE" />
</ActivityIndicator.Color>
</ActivityIndicator>
The "Loading" boolean is binded in the page model here:
public class MyLoginWebPageModel : BasePageModel
{
private BrowserOptions _options;
private Action<BrowserResult> _trySetResult;
private BrowserResult _result = new BrowserResult() { ResultType = BrowserResultType.UserCancel };
private Boolean _navPopped = false;
public string StartUrl { get; private set; }
public bool Loading { get; set; } = false; // RIGHT HERE!!!!!!!!!!!!!!!!!!!!!!
public OidcLoginWebPageModel(ICoreDataRepository repository, ILoginProvider loginProvider, ICache cache, IEventTrace trace, IUsageTimer usageTimer, IPlatform platform)
: base(loginProvider, cache, trace, usageTimer, platform){}
public override void Init(object initData)
{
base.Init(initData);
Tuple<BrowserOptions, Action<BrowserResult>> initObject = initData as Tuple<BrowserOptions, Action<BrowserResult>>;
_options = initObject.Item1;
_trySetResult = initObject.Item2;
StartUrl = _options.StartUrl;
}
protected override void OnPageWasPopped(object sender, EventArgs e)
{
base.OnPageWasPopped(sender, e);
_trySetResult(_result);
}
internal async Task OnBrowserNavigated(object sender, WebNavigatedEventArgs e)
{
Loading = false;
if (!(sender is WebView browser))
{
throw new Exception($"Sender is not of type WebView");
}
if (!Uri.TryCreate(e.Url, UriKind.Absolute, out Uri uri))
{
throw new Exception($"Uri creation failed for: {e.Url}");
}
if (string.IsNullOrEmpty(_options.EndUrl))
{
if (uri.LocalPath.ToLowerInvariant() == "/account/logout")
{
_result = new BrowserResult() { ResultType = BrowserResultType.Success };
if (!_navPopped)
{
_navPopped = true;
await PopPageModel();
}
}
}
}
internal async Task OnBrowserNavigating(object sender, WebNavigatingEventArgs e)
{
Loading = true;
if (!(sender is WebView browser))
{
throw new Exception($"Sender is not of type WebView");
}
if (!Uri.TryCreate(e.Url, UriKind.Absolute, out Uri uri))
{
throw new Exception($"Uri creation failed for: {e.Url}");
}
if (string.IsNullOrEmpty(_options.EndUrl) == false)
{
if (uri.AbsoluteUri.StartsWith(_options.EndUrl))
{
_result = new BrowserResult() { ResultType = BrowserResultType.Success, Response = uri.Fragment.Substring(1) };
e.Cancel = true;
if (!_navPopped)
{
_navPopped = true;
Loading = false;
await PopPageModel();
}
}
}
}
}
Is there anything in here that would indicate a loading icon not disappearing at all?
Thanks!
edit: So this is what I'm thinking I need to do.
First I change my boolean situation
private bool Loading = false;
public bool currentlyLoading
{
get { return Loading; }
set
{
currentlyLoading = Loading;
onPropertyChanged();
}
}
Then in the same file I implement the onPropertyChanged() function to.. let the Bindable property in my xaml file know that the property has changed?
Is this a good implementation?
// Option 1
protected void OnPropertyChanged([CallerMemberName] string propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
// Option 2
protected void OnPropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyName));
}
your class (or it's base class) needs to implement INotifyPropertyChanged. Then your Loading property would look something like this
private bool loading = false;
public bool Loading
{
get { return loading; }
set
{
loading = value;
OnPropertyChanged();
}
}
Option 1 is best. But it would be good if you move your property changed logic to BasePageModel.
Try this one:
private bool _loading { get; set; }
public bool Loading { get {return _loading; } set{value = _loading } }
And in your OnBrowserNavigating:
internal async Task OnBrowserNavigating(object sender, WebNavigatingEventArgs e)
{
Loading = true;
if (!(sender is WebView browser))
{
Loading = false;
throw new Exception($"Sender is not of type WebView");
}
if (!Uri.TryCreate(e.Url, UriKind.Absolute, out Uri uri))
{
Loading = false;
throw new Exception($"Uri creation failed for: {e.Url}");
}
if (string.IsNullOrEmpty(_options.EndUrl) == false) //IF THE CONDITION OVER HERE & FOR INNER IF CONDITIONS FAILS, LOADER WASNT SET TO FALSE
{
if (uri.AbsoluteUri.StartsWith(_options.EndUrl))
{
_result = new BrowserResult() { ResultType = BrowserResultType.Success, Response = uri.Fragment.Substring(1) };
e.Cancel = true;
if (!_navPopped)
{
_navPopped = true;
Loading = false;
await PopPageModel();
}
}
}
Loading = false;
}
I used User Control and Placeholder when added uc to place holder. Count place holder is 0. And then clicking the button on uc does not fire any code. All viewstate is ok, and I don't know what happened.
I used this class to add user control:
public abstract class MasterControl : System.Web.UI.UserControl
{
protected System.Web.UI.WebControls.PlaceHolder PlaceHolder1;
public void Initial(bool postback =true)
{
this.CurrenetContorl = (BaseUserControl)this.LoadControl(this.CurrentPath);
this.CurrenetContorl.PostBack = this.FristLoad ? !FristLoad : postback;
this.CurrenetContorl.PreviousControl = this.PreviousControl;
this.CurrenetContorl.CurrentControl = this.CurrentPath;
if (!this.PlaceHolder1.Controls.OfType<BaseUserControl>().Any( x=> x.ID.Equals(this.CurrenetContorl.ID)))
{
this.PlaceHolder1.Controls.Add(this.CurrenetContorl);
this.FristLoad = false;
}
}
private BaseUserControl _currentcontrol;
public BaseUserControl CurrenetContorl
{
get { return _currentcontrol; }
set {
_currentcontrol = value;
if (_currentcontrol == null) return;
_currentcontrol.Redirecting += CurrentControlRedirecting;
_currentcontrol.ID = this.GetId;
}
}
private bool FristLoad = false;
void CurrentControlRedirecting(string url)
{
var ctrl= this.PlaceHolder1.Controls.OfType<BaseUserControl>().FirstOrDefault();
if (ctrl != null)
{
this.PlaceHolder1.Controls.Remove(ctrl);
this.PreviousControl = ctrl.GetType().Name;
}
this.CurrnetUrl = url;
this.Initial(false);
}
public string CurrnetUrl
{
get
{
return this.ViewState["currentUrl"].ToString();
}
set
{
var temp = "";
if (value.StartsWith("/"))
{
temp = "http://"+Request.Url.Authority +value;
}
this.ViewState["currentUrl"] = temp;
this.CurrentPath = this.GetPath();
}
}
private string GetPath()
{
var uri = new Uri(this.CurrnetUrl);
return uri.AbsolutePath;
}
public string PreviousControl
{
get
{
if (this.ViewState["_previousControl"] == null)
this.ViewState["_previousControl"] = string.Empty;
return this.ViewState["_previousControl"].ToString();
}
set
{
this.ViewState["_previousControl"] = value;
}
}
protected string CurrentPath
{
get
{
if (this.ViewState["_currentpath"] == null)
this.ViewState["_currentpath"] = string.Empty;
return this.ViewState["_currentpath"].ToString();
}
set
{
this.ViewState["_currentpath"] = value;
}
}
private string GetId
{
get
{
if (this.ViewState["ControlId"] == null)
this.ViewState["ControlId"] = Guid.NewGuid();
return this.ViewState["ControlId"].ToString();
}
}
public void Redirect(string url)
{
this.CurrentControlRedirecting(url);
}
public void LoadUrl(string url)
{
this.CurrnetUrl = url;
this.CurrenetContorl = (BaseUserControl)this.LoadControl(this.CurrentPath);
this.FristLoad = true;
this.PreviousControl = "";
}
}
public abstract class BaseUserControl : System.Web.UI.UserControl
{
public string PreviousControl
{
get
{
if (this.ViewState["precontrol"] == null)
this.ViewState["precontrol"] = string.Empty;
return this.ViewState["precontrol"].ToString();
}
set
{
this.ViewState["precontrol"] = value;
}
}
public string CurrentControl
{
get
{
if (this.ViewState["ccontrol"] == null)
this.ViewState["ccontrol"] = string.Empty;
return this.ViewState["ccontrol"].ToString();
}
set
{
this.ViewState["ccontrol"] = value;
}
}
public delegate void RedirectHandler(string url);
public event RedirectHandler Redirecting;
public bool PostBack
{
get
{
if (this.ViewState["_postBack"] == null)
this.ViewState["_postBack"] = false;
return this.ViewState["_postBack"].ToString().ToBol();
}
set
{
this.ViewState["_postBack"] = value;
}
}
public void Redirect(string url)
{
this.Redirecting(url);
}
}
public abstract class BaseUserControl<T> : BaseUserControl
{
public virtual void GetDataFromControl(T obj)
{
this.TryUpdateModel(obj);
}
public virtual void LoadControl(T obj)
{
this.TryBindModel(obj);
}
}
main.ascx code
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using Telerik.Web.UI;
namespace WebApplication1
{
public partial class Main : MasterControl
{
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
}
}
protected void RadMenu1_ItemClick(object sender, Telerik.Web.UI.RadMenuEventArgs e)
{
if (e.Item.Selected != null)
{
this.Redirect(e.Item.Value);
}
}
}
}
<%# Control Language="C#" AutoEventWireup="true" CodeBehind="Main.ascx.cs" Inherits="WebApplication1.Main" %>
<%# Register Assembly="Telerik.Web.UI" Namespace="Telerik.Web.UI" TagPrefix="telerik" %>
<link href="Main.css" rel="stylesheet" />
<div class="RadMenu_WebBlue">
<telerik:RadMenu ID="RadMenu1" runat="server" OnItemClick="RadMenu1_ItemClick" EnableEmbeddedSkins="False" >
<Items>
<telerik:RadMenuItem runat="server" Text="مطالب" >
<Items>
<telerik:RadMenuItem runat="server" Text="ایجاد مطلب جدید" Value="/CreatePost.ascx" />
<telerik:RadMenuItem runat="server" Text="ارشیو مطالب" Value="/ArchivePost.ascx"></telerik:RadMenuItem>
</Items>
</telerik:RadMenuItem>
<telerik:RadMenuItem runat="server" Text="تغییر رمز عبور" Value="/changePassword.ascx"></telerik:RadMenuItem>
</Items>
</telerik:RadMenu>
</div>
<asp:PlaceHolder EnableViewState="True" ID="PlaceHolder1" runat="server"></asp:PlaceHolder>
You should initialize usercontrol in main page
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
}
this.Initialize();
}
I have a UserControl and a class for updating/storing results in a database. I need to automatically refresh the UserControlResultDislpay upon storing data. I have created and event to trigger a refresh when an Update occurs. I have the following code:
Class InstrumentTest:
public delegate void UpdateResultDisplay(object sender, EventArgs e);
public event UpdateResultDisplay RefreshDisplay;
protected virtual void OnNewResult(EventArgs e)
{
if (RefreshDisplay != null)
RefreshDisplay(this, e);
}
public void UpdateResultDB(ResultDataJFTOT resultData)
{
AnalysisListCommon myresult = PContext.GetInstance().DbHandlerLocal.StoredResult(
resultData.SampleId,
resultData.TestDate.ToString("yyyy-MM-ddTHH:mm", CultureInfo.InvariantCulture),
resultData.InstrumentSn,
StringRepository.constStringSampleName);
if (myresult != null)
{
Result r = new Result(new Guid(myresult.ResultId));
ResultData rd = r.GetResultData("Rating", FindResultDataMode.byVariableIdentifier);
string xmlTubeRating = resultData.tRating.ToString().Replace("#LT#", "<");
rd.Text = xmlRating;
rd.Store();
rd = r.GetResultData("TestDate", FindResultDataMode.byVariableIdentifier);
rd.Text = resultData.Date.ToString();
rd.Store();
OnNewResult(EventArgs.Empty);
}
else
{
AddTestToQueue(resultData);
}
}
public static InstrumentTest Instance()
{
//If instance is null create a new instance of the InstrumentTest
if (instrumentTestInstance == null)
{
instrumentTestInstance = new InstrumentTest();
}
return instrumentTestInstance;
}
Code from UserControl:
public UserControlResultDisplay()
{
this.InitializeComponent();
this.InitializeUIStrings();
this.InitializePlot();
EventListener(resultChanged);
}
private InstrumentTest resultChanged = InstrumentTest.Instance();
public void EventListener(InstrumentTest resultChanged)
{
//resultChanged = (InstrumentTest)obj;
resultChanged.RefreshDisplay += DisplayNewResultData;
}
private void DisplayNewResultData(object sender, EventArgs e)
{
RefreshCurrentResult();
}
I get a problem when I am trying to show an AlertDialog in my adapter. It's showed many time when I want to delete an article (The first article for each category) or when I try to delete a category (Exactly when I remove a second category )
This is my code
ArticlesConfigurations.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Util;
using Android.Views;
using Android.Widget;
using SymaMobile.Core.Models;
using Vici.CoolStorage;
using SymaMobile.Droid.Adapters;
using Android.Database;
namespace SymaMobile.Droid
{
public class ArticlesConfiguration : Fragment
{
private ListView listViewCatgArticles;
private ListCategorieArticlesConfigAdapter adapterCatConfig;
private ListArticleConfigAdapter adapterArticles;
private List<CategoriesArticlesConfig> listCatgArticles;
private List<ArticlesConfig> listArticles;
private Button ajouterArticle;
private GridView gridArticles;
private ArticlesConfig art;
private TextView codeBarre;
private TextView libelle;
private CategoriesArticlesConfig categorieActuelle;
private Articles articleActuelle;
private CSList<CategoriesArticles, int> catglist;
private Spinner categorie;
private Spinner articles;
public override View OnCreateView (LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
View v = inflater.Inflate(Resource.Layout.fragment_configuration_articles, container, false);
listViewCatgArticles = v.FindViewById<ListView>(Resource.Id.lv_articles_fragment_configuration_articles);
ajouterArticle = v.FindViewById<Button>(Resource.Id.bt_ajouter_fragment_configuration_articles);
gridArticles = v.FindViewById<GridView>(Resource.Id.gv_articles_fragment_articles_configuration);
listCatgArticles = CategoriesArticlesConfig.List().ToList<CategoriesArticlesConfig>();
adapterCatConfig = new ListCategorieArticlesConfigAdapter(Activity, listCatgArticles);
listViewCatgArticles.Adapter = adapterCatConfig;
ajouterArticle.Click += ajouterArticle_Click;
listViewCatgArticles.ItemClick += listViewCatgArticles_ItemClick;
gridArticles.ItemClick += gridArticles_ItemClick;
return v;
}
void gridArticles_ItemClick(object sender, AdapterView.ItemClickEventArgs e)
{
if (e.Position == gridArticles.Count-1)
{
Android.Util.Log.Error("Position grid", ""+e.Position);
Android.Util.Log.Error("grid Count", "" + gridArticles.Count);
AlertDialog.Builder builder = new AlertDialog.Builder(Activity);
builder.SetTitle(Resource.String.ajouter_categorie);
LayoutInflater inflater = Activity.LayoutInflater;
View v = inflater.Inflate(Resource.Layout.alertdialog_ajouter_article_configuration, null);
codeBarre = v.FindViewById<TextView>(Resource.Id.ed_code_barre_alert_dialog_ajouter_article_configuration);
libelle = v.FindViewById<TextView>(Resource.Id.tv_nom_article_alert_dialog_ajouter_article_configuration);
categorie = v.FindViewById<Spinner>(Resource.Id.sp_categories_alert_dialog_ajouter_article_configuration);
articles = v.FindViewById<Spinner>(Resource.Id.sp_articles_alert_dialog_ajouter_article_configuration);
var adapter = new ArrayAdapter<string>(Activity, Android.Resource.Layout.SimpleSpinnerDropDownItem);
catglist = CategoriesArticles.List();
for (int i = 0; i < catglist.Count; i++)
{
adapter.Add(catglist[i].Nom);
}
categorie.ItemSelected += categorie_ItemSelected;
categorie.Adapter = adapter;
codeBarre.TextChanged+=codeBarre_TextChanged;
builder.SetPositiveButton(Resource.String.ajouter, delegate
{
if (articleActuelle != null && categorieActuelle != null)
{
ArticlesConfig a = ArticlesConfig.New();
a.Article = articleActuelle;
a.CategorieArticles = categorieActuelle;
a.Save();
listArticles.Add(a);
adapterArticles.NotifyDataSetChanged();
}
});
builder.SetNegativeButton(Resource.String.annuler, (Android.Content.IDialogInterfaceOnClickListener)null);
builder.SetView(v);
builder.Show();
}
}
void categorie_ItemSelected(object sender, AdapterView.ItemSelectedEventArgs e)
{
List<Articles> a = catglist[e.Position].Articles.ToList<Articles>();
var adapter = new ArrayAdapter<string>(Activity, Android.Resource.Layout.SimpleSpinnerDropDownItem);
for (int i = 0; i < a.Count; i++)
{
adapter.Add(a[i].Libelle);
}
articles.Adapter = adapter;
}
private void codeBarre_TextChanged(object sender, Android.Text.TextChangedEventArgs e)
{
if (codeBarre.Text.Length > 2)
{
articleActuelle = Articles.ReadFirst("CodeBarre ='" + codeBarre.Text + "'");
if (articleActuelle != null)
{
libelle.Text = articleActuelle.Libelle;
}
else
{
libelle.Text = "";
}
}
}
void listViewCatgArticles_ItemClick(object sender, AdapterView.ItemClickEventArgs e)
{
categorieActuelle = CategoriesArticlesConfig.Read((int)adapterCatConfig.GetItemId(e.Position));
listArticles = categorieActuelle.ArticlesConfig.ToList();
adapterArticles = new ListArticleConfigAdapter(Activity, listArticles);
gridArticles.Adapter = adapterArticles;
}
void ajouterArticle_Click(object sender, EventArgs e)
{
AlertDialog.Builder builder = new AlertDialog.Builder(Activity);
builder.SetTitle(Resource.String.ajouter_categorie);
LayoutInflater inflater = Activity.LayoutInflater;
View v = inflater.Inflate(Resource.Layout.alertdialog_ajouter_categorie_article_configuration, null);
TextView nom = v.FindViewById<TextView>(Resource.Id.ed_nom_ajouter_categorie_fragment_article_configuration);
builder.SetPositiveButton(Resource.String.ajouter, delegate
{
if (nom.Text.Length > 0)
{
CategoriesArticlesConfig c = CategoriesArticlesConfig.New();
c.Nom = nom.Text;
c.Save();
c = CategoriesArticlesConfig.ReadFirst("CategorieArticlesConfigID=" + c.CategorieArticlesConfigID);
listCatgArticles.Add(c);
adapterCatConfig.NotifyDataSetChanged();
}
});
builder.SetNegativeButton(Resource.String.annuler, (Android.Content.IDialogInterfaceOnClickListener)null);
builder.SetView(v);
builder.Show();
}
}
}
ListCategorieArticlesConfigAdapter.cs
namespace SymaMobile.Droid.Adapters
{
class ListCategorieArticlesConfigAdapter : BaseAdapter
{
private List<CategoriesArticlesConfig> list;
private int indice;
private Activity Activity;
public ListCategorieArticlesConfigAdapter(Android.App.Activity Activity, List<CategoriesArticlesConfig> list)
: base()
{
this.Activity = Activity;
this.list = list;
}
public override int Count
{
get { return list.Count; }
}
public override Java.Lang.Object GetItem(int position)
{
return null;
}
public override long GetItemId(int position)
{
return list[position].CategorieArticlesConfigID;
}
public override Android.Views.View GetView(int position, Android.Views.View convertView, Android.Views.ViewGroup parent)
{
var view = (convertView ??
Activity.LayoutInflater.Inflate(
Resource.Layout.list_item_categories_articles_configuration,
parent,
false)) as LinearLayout;
var nom = view.FindViewById(Resource.Id.tv_nom_list_item_categories_articles_configuration) as TextView;
var modify = view.FindViewById(Resource.Id.bt_modify_list_categories_articles_configuration) as Button;
var delete = view.FindViewById(Resource.Id.bt_delete_list_categories_articles_configuration) as Button;
modify.Click += modify_Click;
indice = position;
delete.Click +=delete_Click;
nom.Text = list[position].Nom;
return view;
}
void delete_Click(object sender, EventArgs e)
{
Android.App.AlertDialog.Builder builder = new Android.App.AlertDialog.Builder(Activity);
builder.SetMessage(Resource.String.msg_supprimer);
builder.SetPositiveButton(Resource.String.oui, delegate
{
CSDatabase.ExecuteNonQuery("DELETE FROM CategoriesArticlesConfig WHERE CategorieArticlesConfigID=" + list[indice].CategorieArticlesConfigID);
list.RemoveAt(indice);
NotifyDataSetChanged();
});
builder.SetNegativeButton(Resource.String.non, (Android.Content.IDialogInterfaceOnClickListener)null);
builder.Show();
}
void modify_Click(object sender, EventArgs e)
{
AlertDialog.Builder builder = new AlertDialog.Builder(Activity);
builder.SetTitle(Resource.String.modifier_categorie);
LayoutInflater inflater = Activity.LayoutInflater;
View v = inflater.Inflate(Resource.Layout.alertdialog_ajouter_categorie_article_configuration, null);
TextView _nom = v.FindViewById<TextView>(Resource.Id.ed_nom_ajouter_categorie_fragment_article_configuration);
_nom.Text = list[indice].Nom;
builder.SetNegativeButton(Resource.String.annuler, (Android.Content.IDialogInterfaceOnClickListener)null);
builder.SetPositiveButton(Resource.String.modifier, delegate {
CategoriesArticlesConfig c = CategoriesArticlesConfig.ReadFirst("CategorieArticlesConfigID=" + list[indice].CategorieArticlesConfigID);
if (c != null)
{
c.Nom = _nom.Text;
c.Save();
}
list[indice].Nom = _nom.Text;
NotifyDataSetChanged();
});
builder.SetView(v);
builder.Show();
}
}
}
ListArticleConfigAdapter
namespace SymaMobile.Droid.Adapters
{
class ListArticleConfigAdapter : BaseAdapter
{
Activity context;
private List<ArticlesConfig> liste;
private int indice;
public ListArticleConfigAdapter(Activity context, List<ArticlesConfig> liste)
: base()
{
this.context = context;
this.liste = liste;
}
public override int Count
{
get { return liste.Count+1; }
}
public override long GetItemId(int position)
{
return position;
}
public override Android.Views.View GetView(int position, View convertView, ViewGroup parent)
{
var view = (convertView ??
context.LayoutInflater.Inflate(
Resource.Layout.list_item_article_configuration,
parent,
false)) as LinearLayout;
var image = view.FindViewById(Resource.Id.iv_list_item_article_configuration) as ImageView;
var nom = view.FindViewById(Resource.Id.tv_nom_article_list_item_article_configuration) as TextView;
var supprimer = view.FindViewById(Resource.Id.bt_delete_list_item_article_configuration) as Button;
Android.Util.Log.Error("Position : ", ""+position+" List Count : "+liste.Count);
if (position < liste.Count)
{
nom.Text = liste[position].Article.Libelle;
image.SetImageBitmap(Tools.ImageTools.StringToBitMap(liste[position].Article.Image));
}
else
{
nom.Text = context.Resources.GetString(Resource.String.ajouter);
image.SetImageResource(Resource.Drawable.add128x128);
supprimer.Visibility = ViewStates.Invisible;
}
indice = position;
supprimer.Click += supprimer_Click;
return view;
}
void supprimer_Click(object sender, EventArgs e)
{
Android.App.AlertDialog.Builder builder = new Android.App.AlertDialog.Builder(context);
builder.SetMessage(Resource.String.msg_supprimer);
builder.SetPositiveButton(Resource.String.oui, delegate
{
CSDatabase.ExecuteNonQuery("DELETE FROM ArticlesConfig WHERE ArticlesConfigID=" + liste[indice].ArticlesConfigID);
liste.RemoveAt(indice);
NotifyDataSetChanged();
});
builder.SetNegativeButton(Resource.String.non, (Android.Content.IDialogInterfaceOnClickListener)null);
builder.Show();
}
public override Java.Lang.Object GetItem(int position)
{
return position;
}
}
}
thank you in advance
u have need to do this code on next activity onbackpress or
#Override
protected void onPause() {
// TODO Auto-generated method stub
super.onPause();
progressDialog.dismiss();
}
#Override
public void onBackPressed() {
// TODO Auto-generated method stub
super.onBackPressed();
System.exit(0);
}
In ListCategorieArticlesConfigAdapter.GetView (), you're adding new event handlers for modify and delete, even when the view has been recycled, which means it will already have those handlers. Convert your convertView ?? check into an if/else check and do not reinitialise the handlers when convertView != null.
Modified your adapter to use view holder pattern. This should solve your issues.
class ListCategorieArticlesConfigAdapter : BaseAdapter
{
private List<CategoriesArticlesConfig> list;
private Activity Activity;
public ListCategorieArticlesConfigAdapter(Android.App.Activity Activity, List<CategoriesArticlesConfig> list)
: base()
{
this.Activity = Activity;
this.list = list;
}
public override int Count
{
get { return list.Count; }
}
public override Java.Lang.Object GetItem(int position)
{
return null;
}
public override long GetItemId(int position)
{
return list[position].CategorieArticlesConfigID;
}
public override Android.Views.View GetView(int position, Android.Views.View convertView,
Android.Views.ViewGroup parent)
{
ViewHolder vh;
var view = convertView;
if (view == null)
{
view = Activity.LayoutInflater.Inflate(Resource.Layout.list_item_categories_articles_configuration,
false);
vh = new ViewHolder(list);
vh.Initialize(view);
view.Tag = vh;
}
vh = view.Tag as ViewHolder;
vh.Bind(position);
return view;
}
private class ViewHolder : Java.Lang.Object
{
private TextView _nom;
private Button _modify;
private Button _delete;
private List<CategoriesArticlesConfig> _list;
public ViewHolder(List<CategoriesArticlesConfig> list)
{
_list = list;
}
public void Initialize(View view)
{
_nom = view.FindViewById<TextView>(Resource.Id.tv_nom_list_item_categories_articles_configuration);
_modify = view.FindViewById<Button>(Resource.Id.bt_modify_list_categories_articles_configuration);
_delete = view.FindViewById<Button>(Resource.Id.bt_delete_list_categories_articles_configuration);
}
public void Bind(int position)
{
_modify.Tag = position;
_modify.Click += modify_Click;
_delete.Click += delete_Click;
_nom.Text = _list[position].Nom;
}
void delete_Click(object sender, EventArgs e)
{
var indice = (int)(((View)sender).Tag);
Android.App.AlertDialog.Builder builder = new Android.App.AlertDialog.Builder(Activity);
builder.SetMessage(Resource.String.msg_supprimer);
builder.SetPositiveButton(Resource.String.oui, delegate
{
CSDatabase.ExecuteNonQuery("DELETE FROM CategoriesArticlesConfig WHERE CategorieArticlesConfigID=" + list[indice].CategorieArticlesConfigID);
list.RemoveAt(indice);
NotifyDataSetChanged();
});
builder.SetNegativeButton(Resource.String.non, (Android.Content.IDialogInterfaceOnClickListener)null);
builder.Show();
}
void modify_Click(object sender, EventArgs e)
{
var indice = (int)(((View)sender).Tag);
AlertDialog.Builder builder = new AlertDialog.Builder(Activity);
builder.SetTitle(Resource.String.modifier_categorie);
LayoutInflater inflater = Activity.LayoutInflater;
View v = inflater.Inflate(Resource.Layout.alertdialog_ajouter_categorie_article_configuration, null);
TextView _nom = v.FindViewById<TextView>(Resource.Id.ed_nom_ajouter_categorie_fragment_article_configuration);
_nom.Text = _list[indice].Nom;
builder.SetNegativeButton(Resource.String.annuler, (Android.Content.IDialogInterfaceOnClickListener)null);
builder.SetPositiveButton(Resource.String.modifier, delegate
{
CategoriesArticlesConfig c = CategoriesArticlesConfig.ReadFirst("CategorieArticlesConfigID=" + list[indice].CategorieArticlesConfigID);
if (c != null)
{
c.Nom = _nom.Text;
c.Save();
}
_list[indice].Nom = _nom.Text;
NotifyDataSetChanged();
});
builder.SetView(v);
builder.Show();
}
}
}
I find a solution. Is not the best but it work fine.
Firstly, I declare a boolean variable :
bool entree;
and in GetView method :
if ((position == 0 && !entree) || (position != 0 && entree))
{
...
entree = true;
}
that's all.
I have a collection of generated custom controls that extend CompositeControl, defined as:
[PersistChildren(true)]
[ToolboxData("<{0}:ContractControl runat=server></{0}:ContractControl>")]
public class ContractControl : CompositeControl
{
private int contractID = 0;
private ContractTileControl tileControl = null;
private ContractDetailControl detailControl = null;
private HtmlGenericControl contractMainDiv = null;
public int ContractID
{
get { return this.contractID; }
set { this.contractID = value; }
}
public ContractTileControl TileControl
{
get { return this.tileControl; }
set { this.tileControl = value; }
}
public ContractDetailControl DetailControl
{
get { return this.detailControl; }
set { this.detailControl = value; }
}
public ContractControl()
{
this.contractMainDiv = new HtmlGenericControl("div");
this.contractMainDiv.ID = "contractMainDiv";
this.contractMainDiv.Attributes.Add("class", "contractMain");
}
#region protected override void OnPreRender(EventArgs e)
protected override void OnPreRender(EventArgs e)
{
base.OnPreRender(e);
//CreateChildControls();
}
#endregion
#region protected override void CreateChildControls()
protected override void CreateChildControls()
{
base.CreateChildControls();
if (tileControl != null)
{
this.contractMainDiv.Controls.Add(tileControl);
}
if (detailControl != null)
{
this.contractMainDiv.Controls.Add(detailControl);
}
this.Controls.Add(contractMainDiv);
//base.CreateChildControls();
}
#endregion
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
CreateChildControls();
}
protected override void OnInit(EventArgs e)
{
base.OnLoad(e);
EnsureChildControls();
}
}
Where ContractTileControl and ContractDetailControl are another custom controls derived from CompositeControl.
When I add them to a asp:PlaceHolder control set they render fine, but when I define a repeater like:
<asp:Repeater ID="myRepeater" runat="server" >
<HeaderTemplate>
<table border="0" cellpadding="0" cellspacing="0">
</HeaderTemplate>
<ItemTemplate>
<tr><td><easit:ContractControl ID="contractControl" runat="server" />
</td></tr>
</ItemTemplate>
<FooterTemplate>
</table>
</FooterTemplate>
</asp:Repeater>
And bind them to it:
private void FillContractPlaceHolder()
{
List<ContractControl> controls = new List<ContractControl>();
foreach(KeyValuePair<Customer, List<TFSContract>> pair in contractList)
{
Label customerNameLbl = new Label();
customerNameLbl.ID = "customerNameLbl";
customerNameLbl.CssClass = "customerName";
customerNameLbl.Text = pair.Key.Name;
contractListPlaceHolder.Controls.Add(customerNameLbl);
foreach (TFSContract contract in pair.Value)
{
ContractStatusBarControl status = new ContractStatusBarControl();
status.WidthPercent = GetFillPercent(contract.NumberOfTasks, contract.NumberOfFinishedTasks);
string[] contractNameParts = Regex.Split(contract.Contract.Name, #"[A-Z]{3}-[0-9|A-Z]{2}-[0-9|A-Z]{2}", RegexOptions.IgnoreCase);
ContractDetailControl detail = new ContractDetailControl();
detail.ContractName = contractNameParts.Last();
detail.DateStarted = contract.StartDate;
detail.DateFinished = contract.FinishDate;
detail.StatusBar = status;
ContractTileControl tile = new ContractTileControl();
Match match = Regex.Match(contract.Contract.Name, #"[A-Z]{3}-[0-9|A-Z]{2}-[0-9|A-Z]{2}", RegexOptions.IgnoreCase);
if (match.Value.Length != 0)
{
tile.ContractNumber = match.Value;
}
tile.ContractTasksFinished = contract.NumberOfFinishedTasks;
tile.ContractTasksTotal = contract.NumberOfTasks;
ContractControl contractControl = new ContractControl();
contractControl.ContractID = contract.Contract.Id;
contractControl.TileControl = tile;
contractControl.DetailControl = detail;
//contractListPlaceHolder.Controls.Add(contractControl);
controls.Add(contractControl);
}
}
myRepeater.DataSource = controls;
myRepeater.DataBind();
}
The table gets created, but only the non-composite part contractMainDiv of ContractControl gets rendered, as the Repeater insists that both tileControl and detailControl are null, even though they are properly set to instances of their respective types.
When the Repeater is data-bound, it creates an instance of the ItemTemplate for each item in the data-source, set its DataItem to the item from the data-source, and data-binds the children.
In this case, the item from the data-source is an instance of your ContractControl, and your ItemTemplate has no data-binding, so you'll end up with a blank instance of the ContractControl for each item you've added to the list.
The quick and dirty solution is to add a handler for the ItemDataBound event of your Repeater, and copy the properties to the real control:
protected void myRepeater_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
switch (e.Item.ItemType)
{
case ListItemType.Item:
case ListItemType.AlternatingItem:
case ListItemType.SelectedItem:
case ListItemType.EditItem:
{
var source = (ContractControl)e.Item.DataItem;
var destination = (ContractControl)e.Item.FindControl("contractControl");
destination.ContractID = source.ContractID;
destination.TileControl = source.TileControl;
destination.DetailControl = source.DetailControl;
break;
}
}
}
A better solution would be to bind your Repeater to a list of TFSContract objects, and moving the code to build the ContractControl into the ItemDataBound event handler.
EDIT
Updated to only process real items, ignoring headers, footers, etc.