I have some mysterious ArgumentException I have been beating the whole day - still have no idea why does it happen.
I have the next simple method in my MainPage:
public void FavsRefresh()
{
favsCanvas.Children.Clear();
for (short i = 0; i < (App.Current as App).favUnits.Count; i++)
{
FavsItems tmpUnit;
(App.Current as App).favUnits.TryGetValue((App.Current as App).ids[i], out tmpUnit);
Canvas.SetTop(tmpUnit.subCanvas, i * 120);
favsCanvas.Children.Add(tmpUnit.subCanvas);
}
}
Here tmpUnit is an instance of my class FavsCanvas. Its code doesn't matter - it merges some elements into Canvas, which is called here subCanvas and a series of them must be added into parent Canvas, called favsCanvas.
The sense in all this, that we have several items initially and the user may delete existing and add new. Every time an item is deleted or added I call this procedure (including initially program loading).
The joke is that it works during loading and when I call it from another pages, but when I call it from class method throws an exception, besides it adds the first element properly and refuses to do that with others.
Every item has unique name, I even tried not to use names at all or use random ones - not a chance. I have no idea why this exception appears?!
I call this method using following:
MainPage.MPInstance.FavsRefresh();
This way works good from another pages, but from class - fails. I even left only one line (simple reload those items in Canvas):
private void FavMenuItem_Click(object sender, RoutedEventArgs e)
{
//Delete favorite
if (((MenuItem)sender).Header.ToString() == AppRes.FavsMenuDeleteFav)
{
MainPage.MPInstance.FavsRefresh();
}
}
The fun is that this code worked when I wrote it first a couple weeks ago, but now somehow stopped.
Another thing I tried is to make this particular call from a method in App.xaml.cs, which in its turn is called from the class, but it didn't help either.
In fact I have studied most of parameters - everything is the same in both cases: when it works and when not, except the place from where the method is called. But I don't see any proper alternative.
--- added 05 Aug.
I am not sure if it is important, but it always point the next line after the line where exception is thrown:
(the forum does not allow me to post images, so here.
I tried to move this method to class both to class itself and to App.xaml.cs - the same problem.
It works properly when is called during loading (my MainPage is Pivot and this page which contains this favCanvas is one of the pivots, but not the first) and when I call it from another page while overriding its OnNavigatingFrom. And when it is called while the the MainPage and this pivot is active. May be something with that?
Well guys, I still can't catch the reason itself, but at last have found a dirty way to walk around.
The page, for some reason, does not like to be modified when it is active (at least this way). So for now I am forced to simply redirect to another page, where I just call my method and then go back.
If you have some ideas, they are still of demand as my current was is like a crutch and I dislike it
Related
This is my first question here so please go easy on me. :)
I'm also new to Blazor but not c#.
I am building a Blazor server-side application where a user can enter some information and check if it's valid or not based on some data on the server.
So far I have no issues with calling the function of the class that does the lookup and returns a record to display on the browser.
My problem comes when I want to display that information.
In the c# code, I have a variable called SdItem which contains the record that comes back from the query.
To display the data on the razor page I use the following lines.
#if (SdItem != null)
{
<div>
Code: #SdItem.Code<br />
Desc.: #SdItem.Desc<br />
</div>
}
When SdItem gets the data it obviously does not display the information until I call StateHasChanged();
This of course throws an exception so I had to change it to await InvokeAsync(StateHasChanged);
Although after this change the information shows on the screen and all seems to be fine, I came across a new issue which I could not find a solution or an explanation anywhere on the internet.
During debugging, MS Edge automatically starts and displays the website.
To test this strange issue I also start Firefox to point to the same local address.
Then I use my smartphone as well and that is where I start the query.
When I get the results back, not only do they show up on the phone but on all active browsers that are currently displaying the site.
Why does this happen and how can I stop it.
At the moment I managed to stop this from happening with an ugly code
try { StateHasChanged(); } catch { }
This suppresses the exception and the result is only being displayed on the browser that does the request. This is ugly and I don't like to use it.
Any help would be appreciated.
Just as information, in case this could be the reason. The queried data is in a List in a class which is added as a scoped service. But T is a private variable in the code on the razor file.
"When SdItem gets the data it obviously does not display the information until I call StateHasChanged" Why is this obvious? I would expect Blazor to update the display whenever displayed data is changed. You should very rarely need to call StateHasChanged. This makes me wonder what else is going on.
First thought that springs to mind is that SdItem should be a property...
public Whatever SdItem { get; set; }
...and not a private field...
private Whatever SdItem;
I'm not sure if needs to be public, but when using properties, Blazor (almost) always updates the display. When using private fields, if often doesn't.
"This of course throws an exception" Again, I don't see why this is so obvious that you say "of course." It all depends on where you are calling StateHasChanged. Yes, if you're inside an async block then you'll need to call InvokeAsync, but if you arent, then you shouldn't need to do that.
More code would be useful, as its hard to know exactly what you're doing from the small snippet you provided, but try using a property (if you aren't already), and see if that avoids the need to call StateHasChanged.
If not, please update your question with more information.
I am trying to use the Selenium WebDriverWait type to wait for the page to fully load before checking if an element exists. I tried doing this two different ways.
The First Method uses IgnoreExceptionTypes, and then calls FindElement inside the Until Method. This immediately throws the NoSuchElementException without waiting. I expected this continue to try to find the element until the timeout, while ignoring the NoSuchElementException. It does not appear to work this way. Why doesn't Method1 work?
The Second Method uses ExpectedConditions.ElementExists, and seems to wait correctly.
driver.Navigate().GoToUrl("http://www.google.com");
var myId = "myId";
//Method 1
var wait1 = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
wait1.IgnoreExceptionTypes(typeof(NoSuchElementException));
//Does not wait. Immediately throws NoSuchElementException
var result1 = wait1.Until(x => x.FindElement(By.Id(myId)));
//Method 2 - works as expected
var wait2= new WebDriverWait(driver,TimeSpan.FromSeconds(10))
.Until(ExpectedConditions.ElementExists(By.Id(myId)));
Answering the newly rephrased question...
So I do this all the time. I use the page object model to write automation so this works well for that but you can still use it even if you aren't using the page object model.
The basic concept is this... you find an element that loads last and wait for that element. At that point, you know that the page is done loading and your script can continue without fear of interacting with some element on the page that hasn't finished loading.
The caveat... how in the world do I know which element is the last to load? I have no idea. You basically make a guess (hopefully educated guess) and use it until it fails. If your page isn't terribly dynamic, then just choose about any element. If there's a part of the page that loads late, choose an element inside that portion of the page.
Here's how this typically goes for me. I write a page object for some page. I pick a unique element on the page and declare that as By waitForLocator. Now when I want to wait for the page to finish loading I call
By waitForLocator = By.Id("myId");
new WebDriverWait(Driver, TimeSpan.FromSeconds(10)).Until(ExpectedConditions.ElementIsVisible(waitForLocator));
Now I'm (fairly) confident that the page is done loading and I go about writing methods for the page object and so on. I write a script that consumes that page object and interact with the page according to my test case and then I run the script. Hopefully I picked my waitForLocator well. If I haven't, at some point during the script run I'll get some exception because some element wasn't fully loaded (it loaded after the element I picked). So, I change the waitForElement to the element that I just interacted with that threw the exception and now I should have a better guess at the last loading element. You basically repeat this process until you get no more exceptions.
You might say, this is a very haphazard way to do this. It really seems more haphazard than it really is. If you know your site and your pages, you will make a pretty good first guess. It's pretty rare that I have to change that guess once and it's REALLY rare that I have to change it more than once. That said, changing it is really easy. You already have the locator for the element that threw the exception, you just paste it into the declaration for waitForLocator and you're done.
So one exception that you might run into is if you've properly chosen your waitForLocator and after the page has loaded, you click on some element on the page which dynamically loads some other portion of the page. This scenario is beyond the scope of waiting for the page to load. In this case, you would have to build in another wait that waits for the newly loading portion of the page to finish loading after a click is performed. It will not affect the page loading mechanism.
Additional comments
After going back and reading your question, here's some additional info that will make your life easier.
Your original question had a method that I've simplified/modified below to demonstrate this principle
public void ClickElementById(RemoteWebDriver driver, string id)
{
driver.FindElement(By.Id(id)).Click();
}
The way this method is written, you forced yourself to create a method for each locator type, ID, name, CSS selector, XPath, etc. Rather than pass in a string, pass in a By locator.
public void ClickElement(RemoteWebDriver driver, By locator)
{
driver.FindElement(locator).Click();
}
Now with this new method, it's completely flexible. You can pass in any locator type and it will work. To call it you use something like
ClickElement(driver, By.Id("someId"));
I use a TreeView to display some informations in two levels :
A
B
1
D
1
2
...
Sometimes, the informations stored in the treeview differs with the one displayed. It seems that it's because Paint() is not called after Invalidates().
I already tried answer from this question : C# Treeview doesn't refresh after moving nodes, without success.
Tree (re)Creation code :
using System.Windows.Forms.TreeNode;
using System.Windows.Forms.TreeView;
[...]
private void createTree()
{
[...]// Creation code
// Check update of the treeview
foreach (TreeNode n in viewDataTreeView.Nodes)
{
Console.WriteLine(n.Name);
foreach (TreeNode child in n.Nodes)
{
Console.WriteLine(" " + child.Name);
}
}
Console.WriteLine("done");
this.Invalidate(true);
}
Which always output the correct tree that I have in the treeview. And sometimes, newly added node are not displayed on the screen.
Working case:
callstack:
Functions of working callstack :
private void toolStripDeleteTemplateButton_Click(object sender, EventArgs e)
{
//Some confirmation stuff
[...]
// Delete the template file
GraphTemplateNode node = this.viewDataTreeView.SelectedNode as GraphTemplateNode;
File.Delete(node.GetTemplateFilePath());
createTree();
}
Not working case:
callstack:
See the Test 4 is missing.
Functions of unworking callstack :
//LineGraphUIControl.cs
private void saveTemplateToolStripButton_Click(object sender, EventArgs e)
{
base.SaveGraphTemplate(lineGraphControl1.Graph);
}
//GraphUIControl.cs
public void SaveGraphTemplate(Graph graph)
{
//Getting file name
[...]
//Creating template
ViewDataSubControl.AddNewUserTemplate(tmplt);
}
// ViewDataSubControl.cs
public void AddNewUserTemplate(GraphTemplate tmplt)
{
//Some string calculations
[...]
tmplt.SaveTemplate(fullName);
createTree();
}
I tried to use the method Refresh(), Update() and BeginUpdate() & EndUpdate() with no luck. The event Invalidated is always fired, but I can't get Paint() to be called everytime. If I force call with InvokePaint() the TreeView is not updated either.
What can I do to make it works ?
That issue is unusual, and I suspect that it is something wrong in the logic that renders the TreeView. You wrote in a comment that the code is long, you did not create it and you don't want to copy/paste it.
I understand this.
In general, there are many reasons why it could happen:
It might be a missing EndUpdate at some point. Check the code that runs when you delete and re-add a node.
Node display customization can be troublesome. Check any code that could have an impact on node rendering (the DrawNode event for example)
Check exception handlers. An exception could happens and break a code flow. Remove empty catch sections if it applies.
It might be a misuse of a trick like this one that disable Redraws on demand to speed up the display. In this last case, a missing ResumeDrawing could lock it the same way.
Unfortunately it is very hard to guess what is wrong without the whole code... So the best I can do to help is to give some advices to check what it is going on:
At first, comment every BeginUpdate, EndUpdate, SuspendDrawing, ResumeDrawing together, and check what happens.
If the bug is still here, have a code that populates the TreeView as simple as possible by commenting what is not related to it, Disable events that are used to customize the node display like the DrawNode event (if it applies)
...until it works as expected.
Then, uncomment pieces of codes to re-enable existing features, one by one, until you bump on the issue or notice what is wrong by looking at the code. You will isolate the bug this way.
Hope it helps at least a bit.
I'm using ObjectListView with checkboxes, I would like to run a function on selected items to delete them. So i tried this Method but it not working:
private List<Matricule> matrs;
private void button1_Click(object sender, EventArgs e)
{
//List<Song> s = this.olvSongs.CheckedObjects.Count;
//MessageBox.Show(this.olvSongs.CheckedItems.Count + " " + this.olvSongs.CheckedObjects.Count);
string s = "";
foreach (var item in olvMatrs.SelectedItems)
{
matrs.Remove((Matricule)item);
}
this.olvSongs.SetObjects(matrs);
}
how can i do this task.
You talk about check boxes. The line
foreach (var item in olvMatrs.SelectedItems)
iterates through the ITEMS that are SELECTED, not CHECKED! Is that really what you want?
To get the CHECKED OBJECTS use
objectListView1.CheckedObjects
If you really want to get the SELECTED OBJECTS, don't use Selected*Items*. Use
objectListView1.SelectedObjects;
instead. Thats what the OLV is all about. You want to work with the objects, not with ListViewItems.
If you decided WHAT you want to remove, don't remove the objects from your List, but directly from your ObjectListView using
objectListView1.RemoveObjects(myObjects);
You should probably (re-)read this. Especially the section "Mental gear shift - This is important. You need to understand this.".
well, i see that you don't show the code where it adds anything to matrs, so we are certainly short of useful source code. Also, we don't know what a Matricule is, but i can take a pretty good guess with what you already shared.
i believe 1 of 3 things must be happening if matrs is not getting any items removed.
1: are you sure your function is tied to the click event of the button? you can set a break point in the function to make sure it is even executing. or you can add a line to show a messagebox MessageBox.Show("Yes", this.Text); inside that button1_Click() method.
2: if the function is being executed (so it is not option #1), then my 2nd consideration is that perhaps the (Matricule)item is not in the matrs List to be able to be deleted. that Remove function returns a boolean value indicating whether the remove actually deleted something or not.
3: are you sure it is not getting deleted and that what is really happening is that it really is being deleted but your new updated List is not being shown to you?
I believe you think it is #2, but might want to eliminated the possibility of the other 2 easier options (#1 and #3) first. if you do deduce it to be #2, so options #1 and #3 are not happening, then here's the thing with deleting objects by referencing those objects: it easily leads to problems like what you are having. it is so easy to have code that actually attempts to delete a new object with the same properties as another object that is in a List. the clean way that i solve this is try to remove items by their index # rather than a reference to the object itself. but you are not even grabbing the object to be deleted from the List itself. you are grabbing that object from olvMatrs, which is another object list. my best guess from the information you shared is that this is why it's not working, that if you look deeper, that you are trying to Remove an object that is not in the list, so nothing is being Removed. it's an easy mistake to make. i only know because i've done it too before i learned to be super careful about this.
I am having a problem overriding the GetHeight method when developing an iPad application with MonoTouch.Dialog. I am implementing IElementSizing but my GetHeight method never gets called.
Has anyone else ran into this problem? Thanks.
I made sure that my root.UnevenRows = true;
I also tried including the dialog project and placing a breakpoint in the GetHeight() for any of the Elements that implement IElementSizing with no luck. In a previous iPhone project this worked fine but on the iPad I am still stuck. Are there any other 'gotchas' that I could be missing?
This is sort of a bug in MonoTouch.Dialog. Basically, when you assign the Root Element it wants to know whether there are uneven rows so it can create and cache the appropriate UITableViewSource object.
However, if you add Sections with Elements that implement IElementSizing to the Root element after the Source object has already been created. Then it will not call your GetHeight override. An example of this is if you fetch data async and callback and add the resulting Sections / Elements to to the RootElement...or essentially anytime you add Sections / Elements after PrepareRoot() is called.
There is a simple workaround for this:
this.Root.UnevenRows = true;
Without looking at your code however, I cannot say if this is the bug you are seeing.