Alternative to ItemContainerGenerator with LongListSelector in WP8? - windows-phone-8

is there an alternative to ItemContainerGenerator when working with a grouped LongListSelector?
I have a context menu on every ListBoxItem. One option is "delete item". This works fine with the following code (not really neat, but it works; better ways to implement?):
private void deleteItem(object sender, RoutedEventArgs e)
{
ViewModel drink = (sender as FrameworkElement).DataContext as ViewModel;
for (int i = 0; i < LLSGroups.Count; i++)
{
if (LLSGroups[i].Remove(drink))
break;
}
}
I'd like to animate the item upon deletion. Therefore I need the FrameworkElement of that ListBoxItem. With a usual ListBox it works with
FrameworkElement element = (MyList.ItemContainerGenerator.ContainerFromItem(((MenuItem)sender).DataContext) as ListBoxItem) as FrameworkElement;
The Problem: LongListSelectors do not implement ItemContainerGenerator. How do I get the FrameworkElement for the animation?
Best Regards,
Marc

I build a workaround with the VisualTreeHelper: The input consists of the element which should be searched through and the element I like to find.
private FrameworkElement SearchVisualTree(DependencyObject targetElement, DependencyObject comp)
{
FrameworkElement res = null;
var count = VisualTreeHelper.GetChildrenCount(targetElement);
if (count == 0)
return res;
for (int i = 0; i < count; i++)
{
var child = VisualTreeHelper.GetChild(targetElement, i);
if ((child as FrameworkElement).DataContext == (comp as FrameworkElement).DataContext)
{
res = child as FrameworkElement;
return res;
}
else
{
res = SearchVisualTree(child, comp);
if (res != null)
return res;
}
}
return res;
}
The call looks like this:
FrameworkElement element = SearchVisualTree(myList, (sender as FrameworkElement));
This works fine for manipulations on a visiual list element =)

Related

How can I enumerate an ASP listview control?

Below I take a list and convert it to a data table and bind it to an ASP listview control.
I'd like a function to convert it back to a List from an asp listview control and cannot figure out how to get the items? In Visual Studio debugging, the dataitems are null? It has the proper count but no values? I'd like to enumerate through all rows.
private void createLvwTable(List<string> table)
{
int index = 0;
DataTable dt = new DataTable();
foreach (string row in table)
{
string[] cells = row.Split('|');
if (index == 0) // header column
{
for (int j = 0; j < cells.Length; j++)
{
dt.Columns.Add(cells[j]);
//dt.Rows.Add();
}
}
else
{
DataRow dr = dt.NewRow();
for (int j = 0; j < cells.Length; j++)
{
dr[j] = cells[j];
}
dt.Rows.Add(dr);
}
index++;
}
lvwOutput.DataSource = dt;
lvwOutput.DataBind();
}
This is idiotic IMO so there is most likely a better way, but it appears you have to bind the data to an object during the listview creation. I couldn't find a good answer anywhere, this is a compilation of hours of searching and trying different combinations of semi-related answers.
On the html side you have to set the 'onitemdatabound' to a c# function. The code below also does not need to have the segmentation I'm going with a "|", I left that in to make it easier to read if you copy/paste my function.
I'd be happy to still read replies on how to do this better so I can learn.
html:
<asp:ListView ID="lvwOutput" runat="server" onitemdatabound="lvwOutput_ItemDataBound">
asp:
private List<string> lvwOutputItemsDataBoundToList = new List<string>();
private List<string> lvwOutputItemsDataBoundToListOriginal = new List<string>();
protected void lvwOutput_ItemDataBoundToList(object sender, ListViewItemEventArgs e)
{
if (e.Item.ItemType == ListViewItemType.DataItem)
{
ListViewDataItem dataItem = (ListViewDataItem)e.Item;
object o = (object)dataItem.DataItem;
System.Data.DataRowView rowView = e.Item.DataItem as System.Data.DataRowView;
object[] itemArray = rowView.Row.ItemArray;
string itemBound = "";
foreach(object item in itemArray)
{
itemBound += item.ToString() + "|";
}
if (itemBound.EndsWith("||"))
{
int index = itemBound.Length;
itemBound = itemBound.Remove(index - 2);
}
if (itemBound.EndsWith("|"))
{
int index = itemBound.Length;
itemBound = itemBound.Remove(index - 1);
}
lvwOutputItemsDataBoundToList.Add(itemBound);
}
ViewState["lvwOutputItemsDataBoundToList"] = lvwOutputItemsDataBoundToList;
}
private void filter()
{
lvwOutputItemsDataBoundToList = (List<string>)ViewState["lvwOutputItemsDataBoundToList"];
lvwOutputItemsDataBoundToListOriginal = lvwOutputItemsDataBoundToList;
foreach (string item in lvwOutputItemsDataBoundToList)
{
string[] itemSplit = item.Split('|');
}
}
To enumerate the ListViewItems see ListView.ListViewItemCollection Class and ListViewItem.SubItems Property.
List<string> lstItems = new List<string>():
foreach(ListViewItem itemRow in lvwOutput)
{
for (int i = 0; i < itemRow.SubItems.Count; i++)
{
lstItems.Add(itemRow.SubItems[i].Text);
}
}

Flex tree expand slowly/lazy loading when there are more than 30000 nodes

I want to open all nodes of Flex mx Tree in such a way that UI is responsive at all times. Normally when there are limited no of nodes then this code works just fine.
public function expandAllNodes():void {
for (var i:int = 0; i < this.dataProvider.length; i++) {
expandChildrenOf(this.dataProvider.getItemAt(i), true);
}
}
maybe i need to callLater instead of directly calling the function
public function expandAllNodes():void {
for (var i:int = 0; i < this.dataProvider.length; i++) {
calllater(expandChildrenOf,[this.dataProvider.getItemAt(i), true]);
}
}
but this is not working either.
Using callLater won't help in this case. From the documentation,
The callLater method queues an operation to be performed for the next screen refresh, rather than in the current update.
Using callLater in your loop will simply push all the expandChildrenOf() calls to the next screen refresh -- which will still put way too much work into a single update cycle.
Instead, you could spread your loop over several frames and limit work done per frame:
private var processingLimit:int = 10; //experiment to get a reasonable value for this
private var totalNodes:int = 0;
private var nodesProcessed:int = 0;
public function expandAllNodes():void {
this.totalNodes = this.dataProvider.length;
this.addEventListener(Event.ENTER_FRAME, expandNextNode);
}
private function expandNextNode(e:Event):void {
var numToProcess = Math.min(processingLimit + nodesProcessed, totalNodes);
for (var i:int = nodesProcessed; i < numToProcess; i++) {
nodesProcessed++;
expandChildrenOf(this.dataProvider.getItemAt(i), true);
}
if (numToProcess == totalNodes) {
this.removeEventListener(Event.ENTER_FRAME, expandNextNode);
}
}
n.b. Make sure that expandChildrenOf doesn't recursively open children of children -- if it does, then you could still end up expanding the entire tree based on a single call to expandChildrenOf(1);!
This is how i solved the issue
private const PROCESSING_LIMIT:int = 25;
public var _expandNodesStack:Vector.<Object>;
private function expandNextNode(e:Event):void {
for (var i:int = 0; i < PROCESSING_LIMIT; i++) {
var item:* = _expandNodesStack.pop();
if (item)
expandItem(item, true);
else
break;
}
if (_expandNodesStack.length == 0) {
this.removeEventListener(Event.ENTER_FRAME, expandNextNode);
}
}
public function expandAllNodes():void {
if(this.dataProvider == null || this.dataProvider.length <= 0) return;
if (_expandNodesStack != null && _expandNodesStack.length > 0) {
//already expanding so abort this operation
return;
}
if (_expandNodesStack == null) _expandNodesStack = new <Object>[];
iterateAndPushToStack(this.dataProvider.getItemAt(0));
_expandNodesStack.reverse();
this.addEventListener(Event.ENTER_FRAME, expandNextNode);
}
private function iterateAndPushToStack(item:Object):void {
if (iterator == null)
return;
// if it is not a branch item there's nothing to do
if (item != null && item.children is ArrayCollection && item.children.length > 0) {
_expandNodesStack.push(item);
var childItems:ArrayCollection;
childItems = item.children;
if (childItems) {
for each (var object:Object in childItems) {
iterateAndPushToStack(object);
}
}
}
}

Asp.net dynamically hide div's with for loop from code behind

Imagine I have infinite divs with id="div1", id="div2", id="div3", etc...
How can I hide them from code behind using a for loop? Something like:
for(i = 1; i <= DropDownList1.SelectedValue; i++)
{
string div = "div" + i;
div.Visible = false;
}
The above code doesn't work it's just to give you an idea of what I pretend to do.
Add the runat="server" to your divs.
I've use
the following method to find the controls that I got from http://blog.codinghorror.com/recursive-pagefindcontrol/
for(i = 1; i <= DropDownList1.SelectedValue; i++)
{
var ctrl = FindControlRecursive(this.Page, string.Format("div{0}", i + 1))
if (ctrl != null)
{
ctrl .Visible = false;
}
}
Method for finding controls:
public static Control FindControlRecursive(Control root, string id)
{
if (root != null && !string.IsNullOrWhiteSpace(id))
{
if (root.ID == id)
{
return root;
}
foreach (Control c in root.Controls)
{
Control t = FindControlRecursive(c, id);
if (t != null)
{
return t;
}
}
}
return null;
}
In order to access controls from code-behind, they need to be actual server controls. You can do that by placing the runat="server" attribute.
<div runat="server" id="div1"></div>
<div runat="server" id="div2"></div>
Then in code-behind you can access them like this:
int x = 0;
int.TryParse(DropDownList1.SelectedValue, out x);
for (int i = 0; i < x; i++)
{
Control ctrl = Page.FindControl(string.Format("div{0}", i + 1));
if (ctrl != null)
ctrl.Visible = false;
}
Obviously you can place this inside a loop and generate the id string to get all controls.
Beware that:
This method will find a control only if the control is directly contained by the specified container; that is, the method does not search throughout a hierarchy of controls within controls.
More information: here

Issue with for loop in an Array

Initially the array holds the default values as 100. Once if the enemy looses its health then i want to set the default values from 100 to 0. When all the array elements gets a value of 0 then the message will trace as game win.
var enemyHealth:Array = new Array(100,100,100,100,0);
for (var i = 0; i< enemyHealth.length; i++)
{
if (enemyHealth[i] == 0)
{
trace ("game win");
}
}
Actually the issue is if any one of the array element holds a value of 0 then it trace a massage as game win.
So can any one help me in this regard.
You need to check all elements, not just one:
var allZero:Boolean = true;
var enemyHealth:Array = new Array(100,100,100,100,0);
for (var i = 0; i< enemyHealth.length; i++)
{
if (enemyHealth[i] != 0)
{
allZero = false;
break; // We know it's not a win, so we can stop the loop early
}
}
if (allZero) {
trace ("game win");
}
I would do something like this
var enemyHealth:Array = new Array(100,100,100,100,0);
var isDead:Boolean = true;
for (var i = 0; i< enemyHealth.length; i++)
{
if (enemyHealth[i] != 0)
{
isDead = false;
break;
}
}
if(isDead)
{
trace ("Game Win");
}
You can do what the other answerers have said or something like this which might help you more to get the exact amount of enemies dead.
var enemyHealth:Array = new Array(100,100,100,100,0);
var enemiesDead:int=0;
for (var i = 0; i< enemyHealth.length; i++)
{
if (enemyHealth[i] == 0)
{
enemiesDead++;
}
}
if(enemiesDead==enemyHealth.length)
{
trace("Game Over");
}
You can use the every method to check that every element of your array (or vector) meet a criterion.
const enemyHealth:Vector.<uint> = new <uint>[100,100,100,100,0];
const zeroHealth:Function = function(item:uint, index:int, vector:Vector.<uint>):Boolean {
return item === 0;
}
if (enemyHealth.every(zeroHealth)) {
trace("Game win")
}
I have changed the array to a Vector because they are more efficient, and you can specify the type of the elements, but it also works fine with array.

how to trace "depth" or stacking order of a display object?

How can you trace the "depth" or stacking order of a display object with AS3?
I'm trying to figure out if my sprite is behind another sprite...
container.getChildIndex(displayObject);
but that will only tell you how deep it is, not necessarily if anything is in front of it.
Function comparing two DisplayObject instances to determine which one is at a higher "depth" on the display list:
private function higher(a:DisplayObject, b:DisplayObject):DisplayObject
{
// Parent chains
var ac:Array = [a];
var bc:Array = [b];
// Pointers to individual nodes
var an:DisplayObject = a.parent;
var bn:DisplayObject = b.parent;
while (an != null) {
ac.push(an);
an = an.parent;
}
while (bn != null) {
bc.push(bn);
bn = bn.parent;
}
var acl:int = ac.length;
var bcl:int = bc.length;
var n:int = Math.min(acl, bcl);
var i:int = 0;
for (; i < n; i++) {
an = ac[acl - i - 1];
bn = bc[bcl - i - 1];
// First uncommon ancestor
if (an != bn)
break;
}
var ca:DisplayObjectContainer = an.parent;
if (!ca)
return null;
if (ca.getChildIndex(an) > ca.getChildIndex(bn))
return a;
else
return b;
}
Note: If one of the objects is not on the display list, the function returns null. You can change it to return the other object instead.
You can almost certainly optimize this, but this is a first cut.
Just a refactored version of Manish answer using vectors and which won't return weird result if you ever call higher(a,a.parent).
parents() may be used for other purpose too :
public function higher(a:DisplayObject, b:DisplayObject):DisplayObject
{
var aParents:Vector.<DisplayObject> = parents(a);
var bParents:Vector.<DisplayObject> = parents(b);
var commonDepth:int = Math.min(aParents.length, bParents.length);
for (var depth:int = 0; depth < commonDepth; depth++)
if (aParents[depth] != bParents[depth])
break;
if (depth == 0 || depth == commonDepth)
return null;
var commonAncestor:DisplayObjectContainer = aParents[depth].parent;
if (commonAncestor.getChildIndex(aParents[depth]) > commonAncestor.getChildIndex(bParents[depth]))
return a;
else
return b;
}
private function parents(d:DisplayObject):Vector.<DisplayObject>
{
var result:Vector.<DisplayObject> = new Vector.<DisplayObject>;
while (d != null)
{
result.unshift(d);
d = d.parent;
}
return result;
}
private function getDepth(clip:DisplayObject):uint
{
var depth:uint = 0;
var currentClip:DisplayObject = clip;
while (currentClip.parent && currentClip.parent != this)
{
depth++;
currentClip = currentClip.parent;
}
return depth;
}
container.getChildIndex(child) should do it, it returns the index of the child
This is a revised version of what jauboux did from a version Manish did.
Namely, adding a null return value from highestOf() when depths match.
/**
* #param ifDepthsMatchReturnObjectA
* #return Whichever DisplayObject is higher on the display list.
* Optionally returns `null` if they're at the same depth.
*/
public function highestOf(a:DisplayObject, b:DisplayObject, ifDepthsMatchReturnObjectA:Boolean = false):DisplayObject
{
var aParents:Vector.<DisplayObject> = ancestorsOf(a);
var bParents:Vector.<DisplayObject> = ancestorsOf(b);
var commonDepth:int = Math.min(aParents.length, bParents.length);
for (var depth:int = 0; depth < commonDepth; depth++)
if (aParents[depth] != bParents[depth])
break;
if (depth == 0 || depth == commonDepth)
return null;
var commonAncestor:DisplayObjectContainer = aParents[depth].parent;
var aDepthOnCommonAncestor:int = commonAncestor.getChildIndex(aParents[depth]);
var bDepthOnCommonAncestor:int = commonAncestor.getChildIndex(bParents[depth]);
if (aDepthOnCommonAncestor > bDepthOnCommonAncestor)
return a;
else if (aDepthOnCommonAncestor < bDepthOnCommonAncestor)
return b;
else
return ifDepthsMatchReturnObjectA ? a : null;
}
/**
* #return Whether a is higher than b.
*/
public function isHigher(a:DisplayObject, b:DisplayObject):Boolean
{
return highestOf(a, b) === a;
}
/**
* #return All ancestors of given display.
*/
private function ancestorsOf(display:DisplayObject):Vector.<DisplayObject>
{
var result:Vector.<DisplayObject> = new Vector.<DisplayObject>;
while (display != null)
{
result.unshift(display);
display = display.parent;
}
return result;
}