MonoTouch Dialog StringElements Variable Cell Height - c#

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.

Related

Change ReorderableList maximum items from script

I'm working with reorderable lists in Unity right now and I can't seem to figure out how to update the 'max items' field that is visible in the inspector from a script. I'm a little new to Unity so I might be missing something easy but I didn't see any way from the listed methods or properties to update this field. Just looking to set the max items in a reorderable list to the size of a Dictionary that I have populated.
Any help would be appreciated. Thanks.
Edit: Just to be clear, the value I'm trying to change is the bottom one in the screenshot below:
I've tried things along the lines of listName.maxValue = X, listName.maxSize = X, but (at least out of what Visual Studio Code is showing me) there is no method available to change this value. I even tried opening the Reorderable List script (which is from an imported package) and adding my own method for it but it is still throwing an error after trying to use it.
Note that such a class name already exists namely UnityEditorInternal.ReorderableList.
Make sure on top of your file you have
using UnityEngine.UI.Extensions;
instead of
using UnityEditorInternal;

pass variables as array specflow c#

I am attempting to use Specflow to automate web tests using Selenium. So far, things are going mostly fine, but I am now running into a problem. One of my steps allow for a user to input a variable, the step looks like this:
Given I click the (VARIABLE) Menu
And the code behind it is fairly simple, just clicking on a link based on the text that is passed:
driver.FindElement(By.XPath("Xpath to get to the variable")).Click();
However, there is a later step that must use this information. That is fine, you can use "ScenarioContext.Current.Add(string, variable)" and I know about that and have been using it. It functions for the needs that I was first informed of.
My problem is that now the business wants to be able to add multiple items at the same time. This presents two problems. Attempting to just call the step a second time throws an exception: "An item with the same key has already been added." and if I put this into a Scenario Outline, which would allow me to call the variable a second time in a second run, I cannot use the first variable in the final step.
Logically, this means that passing in a variable multiple times is the problem (which makes sense, given it's passing in as a string) and so passing the variable in as an array seems the logical way to go. The idea is that when I pass the parameter from one step to another as an array instead of as a string I theoretically won't run into this error and then I will be able to iterate through the items in the array in that later step with a for loop. This seems like something that SpecFlow should be able to do, but I am having issues finding out just how to achieve this. Does anyone have an idea on how to do this? I attempted to merely use:
Scenario.Context.Current.Add(string, variable).ToArray();
However, that does not work, and all of the examples of "ToArray" I can find in the SpecFlow documentation doesn't seem to be actually changing the variables you pass from one step to another into an array, it seems to be used solely inside of individual steps and never passed between steps. Is passing parameters using ScenarioContext.Current.Add(string, variable) as an array possible in SpecFlow?
Thanks in advance.
the simplest solution to your problem is to add an array (or list) to the context in the first step and then to get it out and add to it and then replace it again in future steps:
List<string> list = new List<String>();
list.Add(variable)
ScenarioContext.Current.Add(name, list);
then later
List<String> currentList = (List<String>) ScenarioContext.Current[string];
currentList.Add(variable);
ScenarioContext.Current[name]=list;
However I feel duty bound to point out some issues with your current solution. You should investigate the PageObject pattern and hide your element selection XPath inside your page objects. Imagine the business decides to change the element that information is stored in. Now you have to change every test that does this:
driver.FindElement(By.XPath("Xpath to get to the variable")).Click();
for that variable. Using the page object pattern this is hidden inside the page object and you would only have a single place to change.
I personally would also consider sharing data using context injection as I find this allows strong typing of the data (so no cast is required like in the example above) and it allows you to know what data is stored, its not just a random bag of stuff).

WPF DependencyObject calling thread exception

I have the following code which creates a temporary folder and uses a FileSystemWatcher to poll for files added to the folder on the Location property, and add them to a list: Scratchdisk.cs on Pastebin. The idea is to create a Scratchdisk object, and have FFmpeg extract video frames into it, the FileSystemWatcher builds a list of these files as FFmpeg creates them, and the list is presented as a DependencyObject that my UI binds to.
I'm binding to the Scratchdisk object like so:
<ItemsControl ItemsSource="{Binding Source=ThumbnailScratchdisk, Path=FileList}">
...
</ItemsControl>
On actually creating the object though, I get the following exception:
A first chance exception of type 'System.InvalidOperationException' occurred in WindowsBase.dll
Additional information: The calling thread cannot access this object because a different thread owns it.
on line 28 get { return (List<string>)GetValue(FileListProperty); }
I think I need a Dispatcher.Invoke somewhere but I have no idea where, I don't know where the second thread is being created. I'm assuming it has something to do with the FileSystemWatcher writing to the file list.
Any help?
Thanks!
The way I access it is like this. It gets the UI Thread's Dispatcher
System.Windows.Application.Current.Dispatcher.Invoke(
(Action)(() =>
{
//Access the UI from here
}));
The main thing to note here between what I have and what you have listed in the comments is that mine will work regardless if you're in the behind code, the view model, a service class, wherever. Not all items have a Dispatcher on them so this.Dispatcher doesn't always work.
Even though this is a fairly old thread, I wanted to give a hint to anyone who ran into the same thing I did. This is an intentionally verbose description so the search engines can find it for the next guy/gal who hits this obscure behaviour.
After getting the SetValue/GetValue compile error described here, I needed to derive my VM from a DependencyObject.
I wanted to continue deriving my VM from our ViewModelBase, which was derived from our AbstractNotifyPropertyChanged class (can't derive from 2 full classes in C#, of course). Being the super smart guy I am, I figured I would add the DependencyObject derivation to my AbstractNotifyPropertyChanged class. I couldn't see any reason why this little change would have any detrimental effects. For many weeks, the application was running fine.
There is always a big hairy "however". During testing, it was discovered that one of my comboboxes crashed the entire application when an item was selected. This was due to an unhandled InvalidOperationException. "The calling thread cannot access this object because a different thread owns it." The only thing that made this combobox different was the fact that it used DependencyProperty for some values.
Four days of frustrating debugging led nowhere because none of my code was making the call. It was all coming from WPF, and blowing up when the call stack reached VerifyAccess in GetValue. Obviously when it is being called by the framework, attempting to call Invoke to cross threads was not going to happen? Where would you put the Invoke call?
Since normal debugging failed, I had to go about it the hard way. I retraced my checkin steps to find the last time the code worked. I already had the idea that it was somehow related to the DependencyProperty of the combobox, so seeing the code changes, my suspicions pointed to the DependencyObject derivation.
After some finagling of the code derivations to remove DependencyObject from the chain for all of my ViewModels (through ViewModelBase), and placing that derivation only in the exact locations that I needed it, The problem has been solved.
You can wrap your call inside an Action() being called from Dispatcher like this:
this.Dispatcher.BeginInvoke(new Action(() =>
{
// your code accessing UI elements here
}));

ArgumentException when trying to add a child to Canvas

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

set XAML Properties at runtime from an other C# Application (AutomationProperties.AutomationId)

given 2 applications:
1 WPF application, where not all controls have a AutomationId, and which I cannot change. In addition the application adds controls at runtime without setting the AutomationId.
1 console application which automates the above WPF application
I need that, because I want to access all elements within nearly the same amount of time. (searching for an automationelement right before using seems to differ a lot (from ms to s) in the time - depending on the amount of elements / and tree-tiers)
I would like to set AutomationIds of WPFs controls within the console application during WPFs runtime. Would be great to know, if you can think of any solution for this problem!
What I have tried until now:
1.)Reflections
Type type = element.GetType();
FieldInfo fi = type.GetField("AutomationIdProperty");
fi.SetValue(element, "x"); //Error
Error message: "Object of type 'System.String' cannot be converted to type 'System.Windows.Automation.AutomationProperty'" But I would like to hand over a value, not a property type...
if I use the following instead, it throws no error, but changes nothing in the XAML
fi.SetValue(element, AutomationElement.AutomationIdProperty);
2.)directly
AutomationElement element; // = my AutomationElement
element.Current.AutomationId = "x"; //since AutomationId is Readonly - its not possible
3.) DependencyObjects and DependencyProperties seem also promising, but I couldn't come up with an solution so far. Does someone have experience with that??
IDK how it is possible but WPF Inspector is exactly able to do what I was looking for (now I need to know how they attach to the WPF application :) ).
____OLD ANSWER____
It seems impossible to change the XAML of other programs. If the developers are "too lazy" to set the AutomationId, I've come up with a alternative solution.
The automation app iterates over all controls in the beginning, giving them unique names which are stored in a dictionary, together with their references. In case a component gets added/deleted/changed in the hierarchy, the component and their descendants get deleted in the dictionary and the app re-iterates over this sub-tree again.

Categories