I am trying to lightly customise by inheritance some Elements in Mvvmcross Dialog implementation.
Colors and fonts are getting set fine, but if I try to set the Text Labels frame (to 100 X ... in this example) I cannot get it to stick.
Can anyone point me in the direction of where I am going wrong here? tried it in a couple different places.
public class MyBooleanElement : BooleanElement {
public MyBooleanElement (string caption) : base(caption, false)
{
}
protected override UISwitch CreateSwitch()
{
UISwitch s = base.CreateSwitch();
s.BackgroundColor = UIColor.Clear;
s.Opaque = false;
s.Layer.Opacity = 0.25f;
return s;
}
protected override UITableViewCell GetCellImpl(UITableView tv)
{
var cell = base.GetCellImpl(tv);
if (cell.BackgroundColor != UIColor.Clear) {
cell.BackgroundColor = UIColor.Clear;
cell.TextLabel.Font = Theme.GetContentFont();
cell.TextLabel.TextColor = UIColor.White;
cell.TextLabel.Frame = new RectangleF(100, 0, 320, 20); // this is not holding, resets to 15
cell.ContentView.Frame = new RectangleF(50, cell.ContentView.Frame.Top, cell.ContentView.Frame.Width, cell.ContentView.Frame.Height); // try this also?
}
return cell;
}
protected override void UpdateCaptionDisplay(UITableViewCell cell)
{
base.UpdateCaptionDisplay(cell);
if (cell != null) {
cell.TextLabel.Frame = new RectangleF(100, 0, 320, 20); // this is not holding, resets to 15
cell.TextLabel.BackgroundColor = UIColor.Blue; // Yet this works? some constraints somewhere cannot see in source!
}
}
}
The dialog part of the framework is positioning the headers (labels) and controls for you.
You should look at the source code a bit, maybe try to understand how it works a little bit.
You can start with a breakpoint and step into the source code while debugging. I'm sure you are going to see where the 15 value is being set.
I'm sorry I can't give you an exact answer. I had some issues myself with the incorrect positioning of dialog elements on iPad, and I had to dig a bit.
Related
I am using Blazor. I have a grid of buttons in a component and am dynamically setting their individual background-image and border-style attributes with variables returned by methods as users perform certain clicks in other components.
#for (int id = 0; id < 24; id++)
{
var buttonId = id;
<button style="background-image: url(#GetImageFilePath(id)); border-style: #GetBorderStyle(id)"
#onclick="#(e => PlayerGridClick(e, buttonId))"></button>
}
Both methods in the above code return strings and so the code dynamically updates when NotifyStateChanged() action is invoked by the service that provides the data for the component.
If I view the source code in the browser I confirm that both attributes change just as I require, however, only the image attribute is rendered by the browser. If I refresh the browser the border-style attribute is then actioned.
I have tried Chrome and Firefox and both act the same.
Anyone out there have any clues?
Thanks
Further info requested:
The data service implements NotifyStateChanged like this:
public event Action OnChange;
private void NotifyStateChanged() => OnChange?.Invoke();
The client components subscribe like this:
// Subscribe to the state of change notification for the TurnSerice
protected override void OnInitialized()
{
turnService.OnChange += StateHasChanged;
}
// Remove subscription to avoid memory leak
public void Dispose()
{
turnService.OnChange -= StateHasChanged;
}
The client retrieves the data like this:
protected override async Task OnInitializedAsync()
{
player = await turnService.GetPlayerAsync(nPlayer);
// if player has piece in hand:
if(player.pieceInHand.pieceType!=ePieceType.none)
{
// calculate where they can place the piece without it being flipped
// which column?
int column = player.nPlotSource % 6;
// highlight all square in this column
bButtonBorderOn[column] = true;
bButtonBorderOn[column+6] = true;
bButtonBorderOn[column+12] = true;
bButtonBorderOn[column+18] = true;
// which row?
int row = player.nPlotSource / 6;
// highlight all square in this row
bButtonBorderOn[row * 6] = true;
bButtonBorderOn[row * 6+1] = true;
bButtonBorderOn[row * 6+2] = true;
bButtonBorderOn[row * 6+3] = true;
bButtonBorderOn[row * 6+4] = true;
bButtonBorderOn[row * 6+5] = true;
}
else
{
for (int i = 0; i < 24; i++)
bButtonBorderOn[i] = false;
}
//turnService.Test();
}
The setting of the bButtonBorderOn is rather crude but it is just to get it working. Finally the variable is set during the rendering of the component like this:
protected string GetBorderStyle(int id)
{
if (bButtonBorderOn[id])
return "solid";
return "none";
}
Thanks again :)
I have solved it.
The purpose of the dynamic styling was to highlight to a player of the game where they could potentially place a token and get bonus points. So despite the highlighting not working, I moved on to implement the placement rules and found that the data had not initialised properly - extra points were not being awarded.
To solve the placement rule problem I moved the data variable for the styling to the data source class. In doing this the styling problem was also solved.
I am still a beginner to Blazor. Lesson learned: Components are not reliable keepers of data :)
Thanks to all those who took the time to read my question.
I am binding the ImageSource of an ImageBrush on Windows Phone 8.1 (RT not silverlight) to a remote uri, and have a handler when the image fails to show a default image:
<ImageBrush Stretch="UniformToFill" ImageSource="{Binding MyBackgroundUrl}" ImageFailed="ImageBrush_ImageFailed"/>
in the code behind I update the image source property to set it to a local image:
protected void ImageBrush_ImageFailed(object sender, ExceptionRoutedEventArgs e)
{
var img = sender as ImageBrush;
if (img == null) return;
var uri = new BitmapImage(new Uri("ms-appx:///Assets/App/MyDefaultBackground.jpg"));
img.ImageSource = uri;
}
this works GREAT, however by doing this, I am losing the original binding, so that if I reload the same screen with a DIFFERENT binding value, it doesn't re-bind.
This makes sense given what I'm doing, so in that case my question is what did I do wrong and how can I correctly setup a fallback image while allowing the image to re-bind itself when it reloads?
Of course you are. You are overwriting the binding. You have to set the property like this:
void ImageBrush_ImageFailed(object sender, ExceptionRoutedEventArgs e)
{
var img = sender as ImageBrush;
if (img == null) return;
var uri = new BitmapImage(new Uri("ms-appx:///Assets/App/MyDefaultBackground.jpg"));
var vm = img.DataContext as MainPageViewModel;
vm.MyBackgroundUrl = uri;
}
If you don't like that, then you can have two images. One on top of the other and set its visibility based on failure. Something like this pseudo code:
var img = new Image();
// you would not new it up here, you would ref your control.
img.ImageOpened += (s, e) => OverlayImage.Visibility = Visibility.Collapsed;
img.ImageFailed += (s, e) => OverlayImage.Visibility = Visibility.Collapsed;
Make sense to you?
I just noticed you are talking about an image brush and not an image. The logic should be the same, but instead of an overlay it might need to be an underlay. Also, because it is an underlay, you might not need to toggle its visibility since the successful image brush will occlude the underlay. Might be even easier in your case.
Best of luck!
Scenario:
I want a user to see a map and their current position. Then, if they click "start", navigation will begin and they'll see their "route" drawn onto the map as their position changes, similar to how some fitness apps work that map out your run/walk. The goal is to do this in real-time as the user's position changes.
Options:
The way I see it, there are two options: 1) use a RouteQuery and Map.AddRoute from the starting position, to the next position (when the position changes), keeping track of the last position, and always drawing a new MapRoute from that position to the new, or 2) displaying the user's current position as a dot that moves as their position changes, and then maybe when they press "stop", draw a MapRoute for each of their positions in order to show their full route.
I'd really prefer option #1 because the user can see their route progression, etc., as they go.
Here is the code that I'm using:
XAML:
<maps:Map x:Name="MainMap" />
<Button x:Name="btnStart" Content="Start"/>
<Button x:Name="btnStop" Content="Stop" IsEnabled="False"/>
Code-behind:
Global Variables:
GeoCoordinateWatcher watcher;
List<GeoCoordinate> listCoordinates;
GeoCoordinate lastCoordinate;
btnStart.Tap():
private void btnStart_Tap(object sender, GestureEventArgs e)
{
if (watcher == null)
{
watcher = new GeoCoordinateWatcher(GeoPositionAccuracy.High);
watcher.MovementThreshold = 20;
watcher.StatusChanged += watcher_StatusChanged;
watcher.PositionChanged += watcher_PositionChanged;
}
watcher.Start();
}
watcher.StatusChanged():
private void watcher_StatusChanged(object sender, GeoPositionStatusChangedEventArgs e)
{
switch (e.Status)
{
case GeoPositionStatus.Initializing:
btnStart.IsEnabled = false;
btnStop.IsEnabled = true;
break;
case GeoPositionStatus.NoData:
lblStatus.Text = "location data is not available.";
break;
case GeoPositionStatus.Ready:
lblStatus.Text = "location data is available.";
break;
}
}
watcher.PositionChanged():
void watcher_PositionChanged(object sender, GeoPositionChangedEventArgs<GeoCoordinate> e)
{
if (listCoordinates == null)
{
// first time through:
listCoordinates = new List<GeoCoordinate>();
listCoordinates.Add(e.Position.Location);
lastCoordinate = e.Position.Location;
return;
}
else
{
listCoordinates.Add(e.Position.Location);
DrawRoute(e.Position.Location);
lastCoordinate = e.Position.Location;
}
}
DrawRoute function:
private void DrawRoute(GeoCoordinate newPosition)//
{
RouteQuery query = new RouteQuery()
{
TravelMode = TravelMode.Driving,
Waypoints = new List<GeoCoordinate>() { MainMap.Center, newPosition }
};
query.QueryCompleted += RouteQueryCompleted;
query.QueryAsync();
MainMap.Center = newPosition;
lastCoordinate = newPosition;
}
And finally, RouteQueryCompleted():
void RouteQueryCompleted(object sender, QueryCompletedEventArgs<Route> e)
{
mapRoute = new MapRoute(e.Result);
MainMap.AddRoute(mapRoute);
}
What happens:
It appears to work for a second as I begin driving, a short line is drawn where my start position is, but then about 10 second in, a line is randomly drawn down a nearby street (probably equivalent to 3 or 4 blocks long) and then down another block on a side road (while the whole time I haven't even driven ONE block, let alone make any turns!). It's very bizarre and definitely not accurate. I can upload a screenshot to better illustrate it if need be.
Can anyone see what I'm doing wrong in my code or is there a better way to accomplish this? I wasn't sure if this was the best way but I wasn't able to find any examples suggesting otherwise.
I ended up using MapPolyLine to draw a line between the last GeoCoordinate and the new one.
MapPolyline line = new MapPolyline();
line.StrokeColor = Colors.Blue;
line.StrokeThickness = 15;
line.Path.Add(lastCoordinate);
line.Path.Add(pos);
MainMap.MapElements.Add(line);
I am not sure why you are using RouteQuery for your task. Generally, you use this when you want the map sdk to determine a route for you given a set of coordinates. In your case however, you always know where you are through PositionChanged event. It will be easier to plot directly on the map as you move.
Something like this
void watcher_PositionChanged(object sender, GeoPositionChangedEventArgs<GeoCoordinate> e) {
Plot(e.Position.Location);
}
void Plot(GeoCoordinate pos) {
var ellipse = new Ellipse();
ellipse.Fill = new SolidColorBrush(System.Windows.Media.Colors.Blue);
ellipse.Height = 15;
ellipse.Width = 15;
ellipse.Opacity = 25;
var mapOverlay = new MapOverlay();
mapOverlay.Content = ellipse;
mapOverlay.PositionOrigin = new System.Windows.Point(0.5, 0.5);
mapOverlay.GeoCoordinate = pos;
var mapLayer = new MapLayer();
mapLayer.Add(mapOverlay);
MainMap.Layers.Add(mapLayer);
}
Imagine a tablet app that displays two content areas side by side. They completely fill the display, so are 100% in height and 50% in width.
Lets assume we add a list to one container. Naturally this list will consume half the space of the whole display.
Now to my problem, is it possible that high framerate scrolling is kind of impossible with lists of this size? I've got the most basic AS3 ItemRenderer and still can't get anything higher than 30fps during scrolling. Now the odd part, if I add stuff the other container, lets say another list or other components, the list scrolling performance drops to the low 20s.
So nowhere near the 40+ fps you see Adobe advertising in their MAX shows.
I'm testing on a iPad2 and 3 and even with static values, scrolling isn't really good. Now if I enable streaming values so that the ItemRenderer's set data method is called, the framerate drops another 2 to 3 frames.
My (almost) complete renderer looks like this, but even if I strip it to just display a single textfield, disable the stuff going on in the set data and also set only the size of the single textfield in the layoutContents, performance is as described, about 30 if the list is displayed alone, low 20s if other stuff is displayed as well.
//FCStyleableTextField is just a StyleableTextField with an additional ID
private var _textFields:Vector.<FCStyleableTextField>;
private var _oldValues:Dictionary;
private var _sym:Symbol;
public function GridRenderer() {
super();
_textFields = new Vector.<FCStyleableTextField>();
_oldValues = new Dictionary();
}
override protected function createChildren():void {
var _symLabel:FCStyleableTextField = new FCStyleableTextField();
_symLabel.editable = false;
_symLabel.selectable = false;
_symLabel.multiline = false;
_symLabel.id="sym";
_symLabel.setStyle("fontSize", fontSize);
_symLabel.textColor = 0xc0c0c0;
_textFields.push(_symLabel);
addChild(_symLabel);
var fidLen:int = fids.length;
for (var i:int = 0; i<fidLen; i++) {
var _fid_lbl:FCStyleableTextField = new FCStyleableTextField();
_fid_lbl.selectable = false;
_fid_lbl.editable = false;
_fid_lbl.multiline = false;
_fid_lbl.id = String(fids[i]);
_fid_lbl.textColor = 0xc0c0c0;
_fid_lbl.setStyle("textAlign", "right");
_fid_lbl.setStyle("fontSize", fontSize);
_fid_lbl.text = " ";
_textFields.push(_fid_lbl);
addChild(_fid_lbl);
if(i>visibleColumns) {
_fid_lbl.includeInLayout = false;
_fid_lbl.visible = false;
}
}
}
override public function set data(value:Object):void {
if(!value) return;
if(data) {
// check if the value's symbolName is different than the current
// data's symbolName, if so, the itemRenderer has been
// recycled, thus we need to reset the old fid values
if((value as Symbol).symbolName != (data as Symbol).symbolName)
_oldValues = new Dictionary();
}
super.data = value;
_sym = data as Symbol;
try {
var textLen:int = _textFields.length;
for (var i:int = 0; i<textLen;i++) {
var lbl:FCStyleableTextField = _textFields[i];
if(lbl.id == "sym") {
lbl.text = _sym.symbolName;
lbl.truncateToFit();
} else {
if(lbl.id == _sym.fidList.fidMap[lbl.id].fidId && lbl.text != _sym.fidList.fidMap[lbl.id].fieldValue) {
var time:int = new Date().time;
var timerName:String = _sym.symbolName+","+lbl.id+","+grid;
globalTimer.addTimer(timerName, time, "reset", lbl, null, null);
var _oldVal:* = _oldValues[lbl.id];
var _newVal:* = _sym.fidList.fidMap[lbl.id].fieldValue;
// basic color formatting
if(Number(_newVal) > Number(_oldVal))
lbl.textColor = 0x40c040;
else if(Number(_newVal) < Number(_oldVal))
lbl.textColor = 0xf05050;
// add + to change and changePercent fids if value is positive
if(lbl.id == "56") {
if(_newVal >0)
lbl.text = "+" + _newVal;
else
lbl.text = String(_newVal);
} else if(lbl.id == "11") {
if(_newVal >0)
lbl.text = "+" + _newVal;
else
lbl.text = String(_newVal);
} else
lbl.text = String(_newVal);
if(!_sym.fidList.fidMap[lbl.id].fieldValue)
lbl.text =" ";
_oldValues[lbl.id] = _newVal;
}
}
lbl.truncateToFit();
}
} catch (e:Error) { /* nothing to do here -> try/catch required due to async symbolassembly */ }
}
override protected function layoutContents(unscaledWidth:Number, unscaledHeight:Number):void {
var viewWidth:Number = unscaledWidth - paddingLeft - paddingRight;
var viewHeight:Number = unscaledHeight - paddingTop - paddingBottom;
var _previousLabel:FCStyleableTextField;
var textLen:int = _textFields.length;
for(var i:int =0; i<textLen;i++) {
var lbl:FCStyleableTextField = _textFields[i];
graphics.beginFill(0x808080, .3);
lbl.height = viewHeight;
lbl.y = paddingTop;
if(lbl.id=="sym") {
lbl.width = 95;
} else if (lbl.id == "35000") {
lbl.width = 24;
} else {
lbl.width = optimalColWidth;
}
_previousLabel ? lbl.x = (_previousLabel.x + _previousLabel.width): lbl.x = paddingLeft;
graphics.drawRect(lbl.x+lbl.width, 1, 1, unscaledHeight-1);
lbl.commitStyles();
_previousLabel = lbl;
graphics.endFill();
}
}
Still, I'm pretty sure that it is not the item renderer that causes the slowdown, cause as I said, it costs 2, maybe 3 frames compared to a renderer that displays just a single textfield.
I rather think that Flex somehow can't handle the amount of vectors being displayed at once, is something like that possible? And is there any way to boost performance?
I already disabled live streaming values as soon as the user scrolls the list, so that flex basically just has to scroll bitmaps (since LabelItemRenderer automatically enables cacheasbitmap), but that gained maybe 4 frames.
What are your guys tricks to make scrolling a little smoother?
Figured out that using setElementSize() and setElementPosition() instead of using width/height and x/y makes quite a difference. Gained 3fps in initial scrolling performance and 8fps once every item has been rendered.
So I'm pretty close to 30fps now, still not close to what you can do with a native app, but I figure that's as good as it gets with Flex and such a massive renderer.
Also disabled live updates so that the renderer doesn't need to be cached as a bitmap again when updates come in.
Grrr so close yet still failing...
I display this tree, in Flex, which contains two nodes types:
Regular nodes, which are rendered normally like text (because they are!)
Rich (HTML) nodes - that's where things get twisted
Note that my issue is when I dynamically add a new (HTML) node to my tree.
So... How do I display HTML nodes?
I subclass TreeItemRenderer
In that subclass, I override set data() and add a text child to my renderer
Therefore I now have:
[icon] [label]
[text component]
Why?
The default label is a pure text component, not HTML-capable, hence the extra component: I want to display the new guy and forget the default label.
(continued) I override updateDisplayList() and, if the node is a rich one, I set label's height to zero, set my component's x and y to label'x and and y.
So...what am I missing? Ah, yes: I need to set my node's height since HTML text can be bigger or smaller than its text counterpart.
(continued) I override measure()
If my node is not a rich one, I simply invoke super.measure() and return
If it is a rich one, I give my html component a width (htmlComponent.width = explicitWidth - super.label.x;) and its height should be automatically computed.
This gives me a fairly reliably unreliable result!
When I fold/unfold my tree, every other time, I seem to get a correct height for my HTML node. The other time I get a height of '4' which happens to be the HTML component's padding alone, without content.
I know that I must be doing something fairly stupid here...but I am not sure what. I will post my code if my rambling is too incoherent to make any sense of...
**** EDIT: here is the source code for my renderer
As you can see, only 'notes' nodes use HTML.
I add a 'htmlComponent' child that will display the rich text while the default label is zero-sized and disappears.
It's definitely very raw code, as it's in progress!
package com.voilaweb.tfd
{
import mx.collections.*;
import mx.controls.Text;
import mx.controls.treeClasses.*;
import mx.core.UITextField;
import mx.core.UIComponent;
import flash.text.TextLineMetrics;
public class OutlinerRenderer extends TreeItemRenderer
{
private function get is_note():Boolean
{
return ('outlinerNodeNote' == XML(super.data).name().localName);
}
override public function set data(value:Object):void
{
super.data = value;
var htmlComponent:Text = super.getChildByName("htmlComponent") as Text;
if(!htmlComponent)
{
htmlComponent = new Text();
htmlComponent.name = "htmlComponent";
addChild(htmlComponent);
}
if(is_note)
htmlComponent.htmlText = XML(super.data).attribute('nodeText');
else
htmlComponent.htmlText = null;
setStyle('verticalAlign', 'top');
}
/*
* Today we've learnt a valuable lesson: there is no guarantee of when createChildren() will be invoked.
* Better be dirty and add children in set data()
override protected function createChildren():void
{
super.createChildren();
var htmlComponent:Text = new Text();
htmlComponent.name = "htmlComponent";
addChild(htmlComponent);
}
*/
override protected function measure():void
{
if(is_note)
{
super.measure();
var htmlComponent:Text = super.getChildByName("htmlComponent") as Text;
//Setting the width of the description field
//causes the height calculation to happen
htmlComponent.width = explicitWidth - super.label.x;
//We add the measuredHeight to the renderers measured height
//measuredHeight += (htmlComponent.measuredHeight - label.measuredHeight);
// Note the silly trick here...hopefully in the future I figure out how to avoid it
//
// Here is what happens: we check if measuredHeight is equal to decoration such as margin, insets...rather than that + some height
// If so, then we need to come up with an actual height which we do by adding textHeight to this height
// Note that I care about text being equal to margin etc but do not have proper access to these
// For instance UITextField.TEXT_HEIGHT_PADDING == 4 but is not accessible
// I am going to check if "<10" that will cover this case...
trace("For text " + htmlComponent.htmlText);
trace("width = " + htmlComponent.getExplicitOrMeasuredWidth()+" x height = " + htmlComponent.getExplicitOrMeasuredHeight());
var m:TextLineMetrics = htmlComponent.measureHTMLText(htmlComponent.htmlText);
//if(10 > htmlComponent.measuredHeight && !isNaN(htmlComponent.explicitHeight))
//htmlComponent.explicitHeight = m.height + htmlComponent.measuredHeight;
//if(htmlComponent.measuredHeight < 10) htmlComponent.explicitHeight = 50;
//measuredHeight += (htmlComponent.getExplicitOrMeasuredHeight() - super.label.getExplicitOrMeasuredHeight());
measuredHeight += (htmlComponent.getExplicitOrMeasuredHeight() - label.getExplicitOrMeasuredHeight());
trace("m:"+m.height+" Height: " + htmlComponent.getExplicitOrMeasuredHeight());
}
else
{
super.measure();
}
}
override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
{
super.updateDisplayList(unscaledWidth, unscaledHeight);
label.height = label.getExplicitOrMeasuredHeight(); // If you tell me my height, then I shall use my variable height!
graphics.clear();
if(is_note)
{
label.height = 0;
var htmlComponent:Text = super.getChildByName("htmlComponent") as Text;
htmlComponent.x = label.x;
htmlComponent.y = label.y;
htmlComponent.height = htmlComponent.getExplicitOrMeasuredHeight();
graphics.beginFill(0x555555);
graphics.drawRect(0, 0, unscaledWidth, unscaledHeight);
graphics.endFill();
}
var complete:XMLList = XML(super.data).attribute('complete');
if(complete.length() > 0 && true == complete[0])
{
var startx:Number = data ? TreeListData(listData).indent : 0;
if(disclosureIcon)
startx += disclosureIcon.measuredWidth;
if(icon)
startx += icon.measuredWidth;
graphics.lineStyle(3, getStyle("color"));
var y:Number = label.y + label.getExplicitOrMeasuredHeight() / 2;
graphics.moveTo(startx, y);
graphics.lineTo(startx + label.getExplicitOrMeasuredWidth(), y);
}
}
}
}
You made false assumption about label component in default renderer - it is capable of displaying html content. This renderer works for me:
public class HtmlTreeItemRenderer extends TreeItemRenderer {
override protected function commitProperties():void {
super.commitProperties();
label.htmlText = data ? listData.label : "";
invalidateDisplayList();
}
}
It would certainly help if you could post some code.
I was wondering though why you are using a custom html renderer. Is it because you want to display an icon next to the label since you mention [icon] [label]? If so, you're probably better off using an iconField or iconFunction.
Another thing that comes to mind is the variableRowHeight property. You might need to set this if your nodes have different heights.
Try it.
<?xml version="1.0" encoding="utf-8"?>
<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml"
width="100%" height="100%" verticalScrollPolicy="off"
horizontalScrollPolicy="off">
<mx:Script>
<![CDATA[
import mx.core.UITextField;
private var texto:UITextField;
override protected function createChildren():void
{
super.createChildren();
texto = new UITextField();
texto.setColor(0xFFFFFF);
texto.multiline = true;
texto.wordWrap = true;
texto.autoSize = TextFieldAutoSize.LEFT;
this.addChild(texto);
//texto.text = data.title;
}
override public function set data(value:Object):void
{
super.data = value;
if (value)
{
texto.htmlText = value.title;
this.invalidateDisplayList();
}
}
override protected function measure():void
{
super.measure();
}
override protected function updateDisplayList(unscaledWidth:Number,
unscaledHeight:Number):void
{
super.updateDisplayList(unscaledWidth, unscaledHeight);
if (texto)
texto.width = this.width;
}
]]>
</mx:Script>
</mx:Canvas>