Hi
I have created online quiz. I have added Count-down timer,label for question & radiobuttonlist for answers and next button for next question. I have code for timer but this timer gets start again when i click next button as i want count down timer for whole questions(Quiz).
Count down timer code(Javascript) is as follows:
var hour=0; //specify hours for counter
var min= '<%= Session["timer"] %>'; // specify minutes
var second = '<%= Session["second"] %>'; // specify the seconds
var lab = 'cd'; // id of the entry on the page where the counter(for question) is to be inserted & cd is span id in aspx page where i am displaying countdown timer
function start()
{
displayCountdown(setCountdown(hour,min,second),lab);
}
loaded(lab,start);
var pageLoaded = 0;
window.onload = function() {pageLoaded = 1;}
function loaded(i,f)
{
if (document.getElementById && document.getElementById(i) != null)
f();
else if (!pageLoaded)
setTimeout('loaded(\''+i+'\','+f+')',100);
}
function setCountdown(hour,min,second)
{
if(hour>0)
min=min*hour*60;
c = setC(min,second);
return c;
}
function setC(min,second)
{
if(min>0)
second=min*60*second;
return Math.floor(second);
}
function displayCountdown(countdn,cd)
{
if (countdn < 0)
{
document.getElementById(cd).innerHTML = "Sorry, you are too late.";
__doPostBack('__Page');
}
else
{
var secs = countdn % 60;
if (secs < 10)
secs = '0'+secs;
var countdn1 = (countdn - secs) / 60;
var mins = countdn1 % 60;
if (mins < 10)
mins = '0'+mins;
countdn1 = (countdn1 - mins) / 60;
var hours = countdn1 % 24;
document.getElementById(cd).innerHTML = hours+' : '+mins+' : '+secs;
setTimeout('displayCountdown('+(countdn-1)+',\''+cd+'\');',999);
}
}
You must keep a reference on "present" time relatively of the "start" time and the duration of the quiz. So, you would substract "present" time from start time.
protected int HoursDuration {
get {
if (Session["HoursDuration"] == null) { Session["HoursDuration"] = 0; }
return Convert.ToInt32(Session["HoursDuration"]);
}
set { Session["HoursDuration"] = value; }
}
protected int MinutesDuration {
get {
if (Session["MinutesDuration"] == null) { Session["MinutesDuration"] = 0; }
return Convert.ToInt32(Session["MinutesDuration"]);
}
set { Session["MinutesDuration"] = value; }
}
protected int SecondsDuration {
get {
if (Session["SecondsDuration"] == null) { Session["SecondsDuration"] = 0; }
return Convert.ToInt32(Session["SecondsDuration"]);
}
set { Session["SecondsDuration"] = value; }
}
protected int HoursLeft {
get {
return (this.EndTime - this.BeginTime).Hours;
}
}
protected int MinutesLeft {
get {
return (this.EndTime - this.BeginTime).Minutes;
}
}
protected int SecondsLeft {
get {
return (this.EndTime - this.BeginTime).Seconds;
}
}
protected DateTime EndTime {
get {
if (Session["EndTime"] == null) { Session["EndTime"] = DateTime.Now; }
return Convert.ToDateTime(Session["EndTime"]);
}
set { ViewState["EndTime"] = value; }
}
protected DateTime BeginTime {
get {
if (Session["BeginTime"] == null) { Session["BeginTime"] = DateTime.Now; }
return Convert.ToDateTime(Session["BeginTime"]);
}
set { ViewState["BeginTime"] = value; }
}
protected override void OnInit(EventArgs e) {
this.BeginTime = DateTime.Now; // Present time
if (!IsPostBack) {
// The countdown
this.HoursDuration = 0;
this.MinutesDuration = 10;
this.SecondsDuration = 0;
// Only on !postback, you set up when it ends
this.EndTime = this.BeginTime.AddHours(this.HoursDuration)
.AddMinutes(this.MinutesDuration)
.AddSeconds(this.SecondsDuration);
}
base.OnInit(e);
}
Then, in you javascript, call the HoursLeft, MinutesLeft and secondeLeft. I think this should work.
Related
I have 4 children (page1,page2,page3, and page4) in a CarouselPage, I need to auto-scroll the children in every 3 seconds. Initially, page1 is showing on the UI, then page2 -> page3 -> page 4 again starting from page1.
I have done like below for this feature using OnCurrentPageChanged() and await Task.Delay(TimeSpan.FromSeconds(3));:
protected async override void OnCurrentPageChanged()
{
base.OnCurrentPageChanged();
await Task.Delay(TimeSpan.FromSeconds(3));
int index = Children.IndexOf(CurrentPage);
if (index == 0)
{
CurrentPage = Children[1];
}
else if (index == 1)
{
CurrentPage = Children[2];
}
else if (index == 2)
{
CurrentPage = Children[3];
}
else if (index == 3)
{
CurrentPage = Children[0];
}
}
The auto-scroll is successful by this approach.
But if I manually scroll the page in between the auto-scroll, then the time delay is reducing. Suddenly(less than 3 sec) the next page is showing on the screen. If I manually swipe the page I need to wait on the page for 3 seconds. How can I solve this issue?
There is a Exciting Library CardsView please look into it.
it will not only solve your problem but your apps looks cool as well.
here is Source Project , https://github.com/AndreiMisiukevich/CardView .
check CarouselSampleXamlView in that, SlideShowDuration property for carousel which handles all stuff.
Hope it helps.
Please do not put the transfer page to the OnCurrentPageChanged method.
You can put it in your Page's constructor.
public partial class MainPage : CarouselPage
{
bool isStart = true;
public MainPage()
{
InitializeComponent();
Device.StartTimer(new TimeSpan(0, 0, 3), () =>
{
Device.BeginInvokeOnMainThread(() =>
{
int index = Children.IndexOf(CurrentPage);
if (index == 0)
{
CurrentPage = Children[1];
isStart = true;
}
else if (index == 1)
{
CurrentPage = Children[2];
isStart = true;
}
else if (index == 2)
{
CurrentPage = Children[3];
isStart = true;
}
else if (index == 3)
{
CurrentPage = Children[0];
isStart = true;
}
});
return isStart; // runs again, or false to stop
});
}
}
If you change the page by swipe, the time delay is not reducing.
However, If you want to wait on the page for 3 seconds after swiping. You have to use custom renderer to achieve it. You should monitor the viewpager's onTouchEventin android(but I cannot found a solution in IOS). This way will have caton, so above way will be better.
[assembly: ExportRenderer(typeof(CarouselPage), typeof(CustomCarouselPageRenderer))]
namespace CarouselPageDemo.Droid
{
public class CustomCarouselPageRenderer: CarouselPageRenderer
{
public CustomCarouselPageRenderer(Context context) : base(context) {
}
protected override void OnElementChanged(ElementChangedEventArgs<CarouselPage> e)
{
base.OnElementChanged(e);
if (this.ChildCount > 0 && this.GetChildAt(0) is ViewPager viewPager)
{
viewPager.Touch -= ViewPagerTouched;
viewPager.Touch += ViewPagerTouched;
}
}
private void ViewPagerTouched(object sender, TouchEventArgs e)
{
MessagingCenter.Send<App, string>(App.Current as App, "OpenPage", "stop");
}
}
}
CarouselPage_CurrentPageChanged method
private async void CarouselPage_CurrentPageChanged(object sender, EventArgs e)
{
var tokenSource = new CancellationTokenSource();
await Task.Delay(TimeSpan.FromSeconds(3), tokenSource.Token);
MessagingCenter.Subscribe<App, string>(App.Current, "OpenPage", (snd, arg) =>
{
tokenSource.Cancel();
});
int index = Children.IndexOf(CurrentPage);
if (index == 0)
{
CurrentPage = Children[1];
}
else if (index == 1)
{
CurrentPage = Children[2];
}
else if (index == 2)
{
CurrentPage = Children[3];
}
else if (index == 3)
{
CurrentPage = Children[0];
}
}
I have a desktop app which is downloading 1 or more small files (jpg with less than 400KB in size and no more than 20 at a time) simultaneously using a CustomWebClient object and calling OpenReadAsync(). The download process is working just fine if there is no problem in the process. I want to limit the response to a certain time (15 sec) so I have introduced a timeOut handling which is Aborting the request. Even the timeout is working and after that my “OpenReadCompletedEventHandler” method is receiving System.Net.WebException: The request was aborted: The request was canceled (which is the right behaviour).
Now, my problem is that I want to allow the user to try re-loading the picture(s). So the next webClient request(s) are failing with the same WebException. Below is my code.
Here is my Custom WebClient class (used in order to have more than 2 async connections at a time):
internal class ExtendedWebClient : WebClient
{
private Timer _timer;
public int ConnectionLimit { get; set; }
public int ConnectionTimeout { get; set; }
public ExtendedWebClient()
{
this.ConnectionLimit = 2;
}
protected override WebRequest GetWebRequest(Uri address)
{
var request = base.GetWebRequest(address) as HttpWebRequest;
if (request != null){_timer = new Timer(TimeoutRequest, request, ConnectionTimeout, Timeout.Infinite);
request.ServicePoint.ConnectionLimit = this.ConnectionLimit;
request.ServicePoint.MaxIdleTime = 5000;
request.ServicePoint.ConnectionLeaseTimeout = 5000;
}
return request;
}
private void TimeoutRequest(object state)
{
_timer.Dispose();
_timer = null;
((WebRequest)state).Abort();
}
protected override void Dispose(bool disposing)
{
if (_timer != null)
{
_timer.Dispose();
_timer = null;
}
base.Dispose(disposing);
}
}
Here is the code to download the files using my custom WebClient class:
internal struct PageWaitHandleState
{
public int WaitHandleIndexInPage;
public bool ImageIsLoaded;
public string ErrMessage;
}
public Image[] downloadedImages;
private PageWaitHandleState[] waitHandlesInPage;
private OpenReadCompletedEventHandler[] downloadComplete;
private EventWaitHandle[] pagesEWH = null;
private EventWaitHandle[] downloadImageEvent;
private int availableImages = 1; // Set here to simplify, but as I stated in my description, it may be more than 1.
int downloadTimeOut = 15000;
int maxSimultaneousDownloads = 20;
private void DownloadImages(int pageIndex = 0, string[] imageUrl)
{
if (pagesEWH[pageIndex] != null)
{
ReloadImages(pageIndex, imageUrl); // Executed in the second request
return;
else
{
pagesEWH[pageIndex] = new EventWaitHandle[availableImages];
downloadedImages = new Image[availableImages];
downloadComplete = new OpenReadCompletedEventHandler[availableImages];
downloadImageEvent = new EventWaitHandle[availableImages];
waitHandlesInPage = new PageWaitHandleState[availableImages];
// Set the downloadComplete deletages
for (int i = 0; i < availableImages; i++)
{
downloadComplete[i] = ProcessImage;
}
}
for (int imgCounter = 0; i < availableImages; i++)
{
waitHandlesInPage[imgCounter] = new PageWaitHandleState() { ImageIsLoaded = false, WaitHandleIndexInPage = imgCounter, ErrMessage = null };
downloadImageEvent[imgCounter] = GrabImageAsync(imageUrl[imgCounter], downloadComplete[imgCounter], imgCounter, downloadTimeOut, maxSimultaneousDownloads);
pagesEWH[imgCounter] = downloadImageEvent[imgCounter];
}
offenderIndex++;
}
}
private static EventWaitHandle GrabImageAsync(string url, OpenReadCompletedEventHandler openReadCompletedEventHandler, int imgCounter, int downloadTimeOut, int maxSimultaneousDownloads)
{
var myClient = new ExtendedWebClient();
myClient.ConnectionLimit = maxSimultaneousDownloads;
myClient.ConnectionTimeout = downloadTimeOut;
myClient.OpenReadCompleted += openReadCompletedEventHandler;
var iewh = new ImageEventWaitHandle() { ewh = new EventWaitHandle(false, EventResetMode.ManualReset), ImageIndex = imgCounter };
myClient.OpenReadAsync(new Uri(url), iewh);
return iewh.ewh;
}
internal void ProcessImage(object sender, OpenReadCompletedEventArgs e)
{
ImageEventWaitHandle iewh = (ImageEventWaitHandle)e.UserState;
bool disposeObject = false;
try
{
if (e.Cancelled)
{
this.waitHandlesInPage[iewh.ImageIndex].ImageIsLoaded = false;
this.waitHandlesInPage[iewh.ImageIndex].ErrMessage = "WebClient request was cancelled";
}
else if (e.Error != null)
{
this.waitHandlesInPage[iewh.ImageIndex].ImageIsLoaded = false;
this.waitHandlesInPage[iewh.ImageIndex].ErrMessage = e.Error.Message;
iewh.ewh.Set();
this.downloadImageEvent[iewh.ImageIndex].Close();
}
else
{
using (Stream inputStream = e.Result)
using (MemoryStream ms = new MemoryStream())
{
byte[] buffer = new byte[4096];
int bytesRead;
int totalReadBytes = 0;
do
{
bytesRead = inputStream.Read(buffer, 0, buffer.Length); // Exception fired here with the second request
ms.Write(buffer, 0, bytesRead);
totalReadBytes += bytesRead;
} while (inputStream.CanRead && bytesRead > 0);
this.downloadedImages[iewh.ImageIndex] = Image.FromStream(ms);
this.waitHandlesInPage[iewh.ImageIndex].ImageIsLoaded = true;
this.waitHandlesInPage[iewh.ImageIndex].ErrMessage = null;
}
disposeObject = true;
}
}
catch (Exception exc)
{
this.downloadedImages[iewh.ImageIndex] = null;
}
finally
{
// Signal the wait handle
if (disposeObject)
{
iewh.ewh.Set();
((WebClient)sender).Dispose();
}
}
}
private void ReloadImages(int pageIndex, string[] imageUrl)
{
for (int imgCounter = 0; imgCounter < availableImages; imgCounter++)
{
this.downloadComplete[imgCounter] = this.ProcessImage;
this.waitHandlesInPage[imgCounter] = new PageWaitHandleState() { ImageIsLoaded = false, WaitHandleIndexInPage = imgCounter, ErrMessage = null };
this.downloadImageEvent[imgCounter] = GrabImageAsync(ImageUrl[imgCounter],this.downloadComplete[imgCounter], imgCounter, downloadTimeOut, maxSimultaneousDownloads);
this.pagesEWH[imgCounter] = this.downloadImageEvent[imgCounter];
}
}
Finally, when I want to access the images I check if they are ready by using:
private bool ImagesInPageReady(int pageIndex, int recordsInCurrentPage)
{
if (_PagesEWH[pageIndex] != null)
{
int completedDownloadsCount = 0;
bool waitHandleSet;
// Wait for the default images first (imgCounter = 0). When moving page or asking for more pictures, then wait for the others.
for (int ewhIndexInPage = 0; ewhIndexInPage < recordsInCurrentPage; ewhIndexInPage++)
{
if (this.pagesEWH[ewhIndexInPage].WaitOne(this.downloadTimeOut))
{
if (this.WaitHandlesInPage[ewhIndexInPage].ImageIsLoaded)
{
completedDownloadsCount++;
}
}
else
{
this.pagesEWH[ewhIndexInPage].Set();
}
}
return (completedDownloadsCount > 0);
}
return false;
}
#usr, thanks for pointing me in the right direction. HttpClient was the solution. So I basically encapsulated my HttpClient object in a new class, together with the ProcessImage() method and exposing and event fired by the same method.
I'm porting a v2 to v3 app map and there's one thing I can't get to work.
I have a custom control that is not shown, anything.
I'm not sure where is the problem so I'll post everything i think is relevant, ask for some more if needed
Here's the constructor:
Note that there's still the comments from v2
function Semaforo(){}
//Semaforo.prototype = new GControl();
Semaforo.prototype.semaforo = document.createElement("img");
Semaforo.prototype.initialize = function(map) {
var container = document.createElement("div");
var semaforoDiv = document.createElement("img");
semaforoDiv.setAttribute("class", "semaforo");
this.setButtonStyle_(semaforoDiv);
this.semaforo = semaforoDiv;
container.appendChild(semaforoDiv);
semaforoDiv.setAttribute("src", "img/semaforo_rojo.png");
map.getContainer().appendChild(container);
return container;
}
And some of the methods:
Semaforo.prototype.setColor = function(color, mapa) {
this.semaforo.setAttribute("src", "img/semaforo_" + color + ".png");
if(color == "rojo")
{
this.semaforo.setAttribute("alt", "Tr�fico dif�cil");
this.semaforo.setAttribute("title", "Tr�fico dif�cil");
}
else if(color == "ambar")
{
this.semaforo.setAttribute("alt", "Tr�fico irregular");
this.semaforo.setAttribute("title", "Tr�fico irregular");
}
else
{
this.semaforo.setAttribute("alt", "Tr�fico fluido");
this.semaforo.setAttribute("title", "Tr�fico fluido");
}
}
Semaforo.prototype.getDefaultPosition = function() {
return new google.maps.ControlPosition.TOP_RIGHT;
//return new GControlPosition(G_ANCHOR_TOP_RIGHT, new GSize(0, 0)); //TO DO
}
Semaforo.prototype.setButtonStyle_ = function(button) {
button.style.width = "19px";
button.style.height = "53px";
button.style.cursor = "default";
}
function getIconoSemaforo(color, mapa){
var semaforo = new Semaforo();
semaforo.setColor(color, mapa);
return semaforo;
}
Here is where I call the constructor and try to make/show the control
function incluirDatosXML()
{
for (var i=0; i<ciudadDato.length; i++)
{
if (i==0)
{
if (semaforoDato[i]!="no")
{
var semaforo = new Semaforo(this.semaforo, map[1]);
map[1].controls[google.maps.ControlPosition.TOP_RIGHT].push(this.semaforo);
//map[1].addControl(semaforo);
semaforo.setColor(semaforoDato[i], map[1]);
/*google.maps.event.addListener(map[1], 'idle', function() {
map[1].controls[google.maps.ControlPosition.TOP_RIGHT].push(this.semaforo);
});*/
}
}
if (i==1)
{
if (semaforoDato[i]!="no")
{
var semaforo = new Semaforo(this.semaforo, map[2]);
//map[2].addControl(semaforo);
semaforo.setColor(semaforoDato[i], map[2]);
//map[2].controls[google.maps.ControlPoistion.TOP_RIGHT].push(this.semaforo);
}
}
if (i==2)
{
if (semaforoDato[i]!="no")
{
var semaforo = new Semaforo(this.semaforo, map[3]);
//map[3].addControl(semaforo);
semaforo.setColor(semaforoDato[i], map[3]);
//map[3].controls[google.maps.ControlPoistion.TOP_RIGHT].push(this.semaforo);
}
}
$("#clima"+(i+1)).attr("class",climaDato[i]+"_mini");
$("#temp"+(i+1)).html(temperaturadDato[i]+"°");
}
}
So all you can see there is what i tested so far even there's still some comments from previous testings
I met a very strange Problem.
The basic idea is that I have a class to save data received from a trading api about forex price. Each property has been set with NotifyPropertyChanged method like below.
class RealTimeBar
{
public event PropertyChangedEventHandler PropertyChanged;
private const double EPSILON = 0.0000001;
private int _id;
private string _symbol;
private int _time;
private float _open;
private float _high;
private float _low;
private float _close;
int _volume;
public RealTimeBar(int id, string symbol)
{
_id = id;
_symbol = symbol;
}
private void NotifyPropertyChanged(String info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
public int Id
{
get
{
return _id;
}
set
{
_id = value;
}
}
public string Symbol
{
get
{
return _symbol;
}
set
{
if (value != _symbol)
{
_symbol = value;
NotifyPropertyChanged("Symbol");
}
}
}
public int Time
{
get
{
return _time;
}
set
{
if (value != _time)
{
_time = value;
NotifyPropertyChanged("Time");
}
}
}
public float Open
{
get
{
return _open;
}
set
{
if (value != _open)
{
_open = value;
NotifyPropertyChanged("Open");
}
}
}
public float High
{
get
{
return _high;
}
set
{
if (value != _high)
{
_high = value;
NotifyPropertyChanged("High");
}
}
}
public float Low
{
get
{
return _low;
}
set
{
if (value != _low)
{
_low = value;
NotifyPropertyChanged("Low");
}
}
}
public float Close
{
get
{
return _close;
}
set
{
if (value != _close)
{
_close = value;
NotifyPropertyChanged("Close");
}
}
}
public int Volume
{
get
{
return _volume;
}
set
{
if (value != _volume)
{
_volume = value;
NotifyPropertyChanged("Volume");
}
}
}
}
It is quote a long class but with simple structure as you can see. Now I connected to api which fire event to me and I handle it by set the value from api to the class i defined.
BindingList<RealTimeBar> _realTimeBarList = new BindingList<RealTimeBar>();
public Hashtable _iForexHashtable = new Hashtable();
private void _UpdateForexQuote(int tickerId, int time, double open, double high, double low, double close, int volume,
double wap, int count)
{
///MessageBox.Show(tickerId.ToString());
((RealTimeBar)_iForexHashtable[tickerId]).Open = (float)open;
((RealTimeBar)_iForexHashtable[tickerId]).High = (float)high;
((RealTimeBar)_iForexHashtable[tickerId]).Low = (float)low;
((RealTimeBar)_iForexHashtable[tickerId]).Close = (float)close;
((RealTimeBar)_iForexHashtable[tickerId]).Volume = volume;
}
After some setting up, the method _UpdateForexQuote would distribute the coming info into properties of RealTimeBar class. Everything is fine.
When I start the program, it does not update. I thought that there is no data coming in. But when I randomly click somewhere in the A1cell of gridcontrol, then click another B1cell, the previous A1cell would update. Then if i click C1cell, then the B1cell would update. If you do not click one cell , it would never update. I show you the picture:
As you can see, that after clicking first three lines, the first three lines showed delayed data and since I never touch the fourth line, it shows zero. And the condition is that I just clicked the fifth line Low cell, that is why the Low does not update but other cells updated. It is very strange. I use same code before under devexpress 11 with vs 2010. But now with devexpress 12 with vs 2012, I met this problem which never occurred before.
UPDATE:
Below is the method I use to 1. define bindinglist and a hashtable, 2. put objects into the hashtable first and add the object from hashtable to bindinglist 3. bind the bindinglist to gridcontrol.
private void earningButtonItem_ItemClick(object sender, ItemClickEventArgs e)
{
_iTimer.AutoReset = false;
_iTimer.Enabled = false;
switchStockPool = "Earning Stock";
disconnectButtonItem.PerformClick();
connectButtonItem.PerformClick();
_iheitanshaoEarningDBConnect = new DBConnect("heitanshaoearning");
List<string>[] tempList;
int tempHash;
tempList = _iheitanshaoEarningDBConnect.SelectSymbolHighLow();
_quoteEarningOnGridList.Clear();
///tempList[0].Count
for (int i = 0; i < tempList[0].Count; i++)
{
tempHash = Convert.ToInt32(tempList[0][i].ToString().GetHashCode());
_iStockEarningHistHashtable[tempHash] = new QuoteOnGridHist(tempList[0][i], (float)Convert.ToSingle(tempList[1][i]), (float)Convert.ToSingle(tempList[2][i]), (float)Convert.ToSingle(tempList[3][i]));
_iStockEarningHashtable[tempHash] = new QuoteOnGrid(tempList[0][i], 0, 0);
_quoteEarningOnGridList.Add((QuoteOnGrid)_iStockEarningHashtable[tempHash]);
reqMktDataExStock(tempHash, tempList[0][i].ToString());
}
List<string>[] tempVolumeList;
tempVolumeList = _iheitanshaoEarningDBConnect.SelectAverageVolume();
for (int i = 0; i < tempList[0].Count; i++)
{
tempHash = Convert.ToInt32(tempVolumeList[0][i].ToString().GetHashCode());
((QuoteOnGrid)_iStockEarningHashtable[tempHash]).Average_Volume = ((float)Convert.ToSingle(tempVolumeList[1][i])) / volumeDenominator;
}
gridControl.DataSource = _quoteEarningOnGridList;
}
/////////////////////
Now when the price update event comes, the method below will update the object properties in hashtable. Since I defined Notifypropertychanged in object, it should update the object in bingdinglist and gridcontrol.
private void _UpdateStockMarketQuote(int tikcerId, int field, double price, int canAutoExecute)
{
////MessageBox.Show(tikcerId.ToString() + field.ToString() + price.ToString());
if (switchStockPool == "Selected Stock")
{
if (field == 4)
{
((QuoteOnGrid)_iStockHashtable[tikcerId]).Gap_From_High = ((float)price - ((QuoteOnGridHist)_iStockHistHashtable[tikcerId]).High) / ((QuoteOnGridHist)_iStockHistHashtable[tikcerId]).Close;
((QuoteOnGrid)_iStockHashtable[tikcerId]).Gap_From_Low = ((float)price - ((QuoteOnGridHist)_iStockHistHashtable[tikcerId]).Low) / ((QuoteOnGridHist)_iStockHistHashtable[tikcerId]).Close;
((QuoteOnGrid)_iStockHashtable[tikcerId]).Last_Price = (float)price;
}
//else if (field == 1)
//{
// ((QuoteOnGrid)_iStockHashtable[tikcerId]).Gap_From_High = ((float)price - ((QuoteOnGridHist)_iStockHistHashtable[tikcerId]).High) / ((QuoteOnGridHist)_iStockHistHashtable[tikcerId]).Close;
// ((QuoteOnGrid)_iStockHashtable[tikcerId]).Gap_From_Low = ((float)price - ((QuoteOnGridHist)_iStockHistHashtable[tikcerId]).Low) / ((QuoteOnGridHist)_iStockHistHashtable[tikcerId]).Close;
//}
}
else if (switchStockPool == "Earning Stock")
{
if (field == 4)
{
((QuoteOnGrid)_iStockEarningHashtable[tikcerId]).Gap_From_High = ((float)price - ((QuoteOnGridHist)_iStockEarningHistHashtable[tikcerId]).High) / ((QuoteOnGridHist)_iStockEarningHistHashtable[tikcerId]).Close;
((QuoteOnGrid)_iStockEarningHashtable[tikcerId]).Gap_From_Low = ((float)price - ((QuoteOnGridHist)_iStockEarningHistHashtable[tikcerId]).Low) / ((QuoteOnGridHist)_iStockEarningHistHashtable[tikcerId]).Close;
((QuoteOnGrid)_iStockEarningHashtable[tikcerId]).Last_Price = (float)price;
}
//else if (field == 1)
//{
// ((quoteongrid)_istockearninghashtable[tikcerid]).gap_from_high = ((float)price - ((quoteongridhist)_istockearninghisthashtable[tikcerid]).high) / ((quoteongridhist)_istockearninghisthashtable[tikcerid]).close;
// ((quoteongrid)_istockearninghashtable[tikcerid]).gap_from_low = ((float)price - ((quoteongridhist)_istockearninghisthashtable[tikcerid]).low) / ((quoteongridhist)_istockearninghisthashtable[tikcerid]).close;
//}
}
}
Not only you need to have PropertyChanged event in a class, you need to implement INotifyPropertyChanged. That's how the grid knows a class can inform of changes.
I've a tree control with checkboxes that uses the control from http://www.sephiroth.it/file_detail.php?id=151#
Somehow I can't get the control to update when I change the dataProvider (i.e. by clicking a checkbox) the only way I can get it to update is to use the scrollbar. How do I force the update? I've tried all possible methods I can figure out? (see update below)
Also how can I reset the Tree (collpasing all nodes, scroll to the top in a large tree)?
package offerta.monkeywrench.components
{
import offerta.monkeywrench.components.componentClasses.TreeCheckBoxItemRenderer;
import mx.collections.ArrayCollection;
import mx.events.TreeEvent;
public class WatchTree extends TreeCheckBox
{
public var idProperty:String;
public var watchFactory:Function;
private var _wSet:Boolean = false;
/* clientId: */
private var _clientId:String;
[Bindable]
public function get clientId():String
{
return _clientId;
}
public function set clientId(value:String):void
{
this._clientId = value;
}
/* //clientId */
/* watching: */
private var _watching:ArrayCollection;
[Bindable]
public function set watching(value:ArrayCollection):void
{
this._watching = value;
}
public function get watching():ArrayCollection
{
return this._watching;
}
/* //watching */
override public function initialize() :void
{
super.initialize();
addEventListener("itemCheck", onItemCheck, false, 0, true);
}
private function isWatching(id:String):Boolean
{
for each(var w:Object in this._watching)
{
if(w[this.idProperty]==id) return true;
}
return false;
}
private function onItemCheck(event:TreeEvent):void
{
var item:Object = event.item as Object;
var currentValue:uint = (event.itemRenderer as TreeCheckBoxItemRenderer).checkBox.checkState;
if(item.children==null)
{
currentValue==2 ? addWatch(item.Id) : removeWatch(item.Id);
}
else
{
for each(var x:Object in item.children)
{
currentValue==2 ? addWatch(x.Id) : removeWatch(x.Id);
}
}
updateParents(item, currentValue);
updateChilds(item, currentValue);
this.dataProvider.refresh();
super.invalidateProperties();
super.invalidateDisplayList();
super.updateDisplayList(this.unscaledWidth, this.unscaledHeight);
}
private function updateParents(item:Object, value:uint):void
{
var checkValue:String = (value == ( 1 << 1 | 2 << 1 ) ? "2" : value == ( 1 << 1 ) ? "1" : "0");
var parentNode:Object = item.parent;
if(parentNode)
{
for each(var x:Object in parentNode.children)
{
if(x.checked != checkValue)
{
checkValue = "2"
}
}
parentNode.checked = checkValue;
updateParents(parentNode, value);
}
}
private function updateChilds(item:Object, value:uint):void
{
var middle:Boolean = (value&2<<1)==(2<<1);
if(item.children!=null && item.children.length>0&&!middle)
{
for each(var x:Object in item.children)
{
x.checked = value == (1<<1|2<<1) ? "2" : value==(1<<1) ? "1" : "0";
updateChilds(x, value);
}
}
}
private function addWatch(id:String):void
{
if(isWatching(id)) return;
this._watching.addItem(this.watchFactory(id, this.clientId));
}
private function removeWatch(id:String):void
{
for(var i:int=0, n:int=this._watching.length; i<n; ++i)
{
if(this._watching[i][this.idProperty]==id)
{
this._watching.removeItemAt(i);
return;
}
}
}
public function update(__watching:ArrayCollection, __clientId:String):void
{
clientId = __clientId;
watching = __watching;
if(this.dataProvider!=null)
{
var ws:ArrayCollection = ArrayCollection(this.dataProvider);
for each(var group:Object in ws)
{
var count:int = 0;
for each(var child:Object in group.children)
{
if(isWatching(child.Id))
{
child.checked = "1";
count++;
}
}
group.checked = (count==0 ? "0" : (count==group.children.length ? "1" : "2"));
}
this._wSet = false;
var dp:ArrayCollection = ArrayCollection(this.dataProvider);
dp.refresh();
super.invalidateProperties();
super.invalidateDisplayList();
super.updateDisplayList(this.unscaledWidth, this.unscaledHeight);
//scroll up the list???
//collapse? (doesn't work)
this.expandItem(null, false);
}
}
}
}
I've found the Tree control a little touchy in Flex. The way I ended up forcing a redraw was to disconnect the dataProvider and reconnect it, then force validation, something a bit like this :
private function forceRedraw(tree:Tree, dataProvider:Object):void
{
var scrollPosition:Number = tree.verticalScrollPosition;
var openItems:Object = tree.openItems;
tree.dataProvider = dataProvider;
tree.openItems = openItems;
tree.validateNow();
tree.verticalScrollPosition = scrollPosition;
}
I guess this incidentally answers the second part of your question since all you'd have to do is null out the openItems collection and set the verticalScrollPosition to 0.
You might have another problem: whenever you check an item the tree scrolls to the top and this is just annoying. To solve this problem you should update the TreeCheckBox.as file this way:
in function checkHandler:
private function checkHandler( event: TreeEvent ): void;
comment the commitProperties(); call.
Now it should work well.
Cheers.
I've had some minor problem with this solution, var scrollPosition:Number = tree.verticalScrollPosition; is constantly 0??