This seems like something that should be simple but I have been unable to locate a solution for it.
I have the following defined in my sample project:
ReadOnlyField.xaml
<?xml version="1.0" encoding="UTF-8"?>
<ContentView x:Name="ReadOnlyFieldContentView" xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="TabbedPageDemo.Views.ReadOnlyField">
<StackLayout Spacing="4">
<Label FontSize="{Binding Source={x:Reference ReadOnlyFieldContentView}, Path=HeaderFontSize}" Text="{Binding Source={x:Reference ReadOnlyFieldContentView}, Path=HeaderText}" />
<Label FontSize="{Binding Source={x:Reference ReadOnlyFieldContentView}, Path=DetailFontSize}" Text="{Binding Source={x:Reference ReadOnlyFieldContentView}, Path=DetailText}" />
</StackLayout>
</ContentView>
ReadOnlyField.xaml.cs
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace TabbedPageDemo.Views
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class ReadOnlyField : ContentView
{
#region Fields
private static readonly BindableProperty DetailFontSizeProperty;
private static readonly BindableProperty DetailTextProperty;
private static readonly BindableProperty HeaderFontSizeProperty;
private static readonly BindableProperty HeaderTextProperty;
#endregion
#region Constructors
static ReadOnlyField()
{
DetailFontSizeProperty = BindableProperty.Create("DetailFontSize", typeof(double), typeof(ContentView), 12.0);
DetailTextProperty = BindableProperty.Create("DetailText", typeof(string), typeof(ContentView), null);
HeaderFontSizeProperty = BindableProperty.Create("HeaderFontSize", typeof(double), typeof(ContentView), 14.0);
HeaderTextProperty = BindableProperty.Create("HeaderText", typeof(string), typeof(ContentView), null);
}
public ReadOnlyField()
{
InitializeComponent();
}
#endregion
#region Properties
public double DetailFontSize
{
get => (double) GetValue(DetailFontSizeProperty);
set => SetValue(DetailFontSizeProperty, value);
}
public string DetailText
{
get => (string) GetValue(DetailTextProperty);
set => SetValue(DetailTextProperty, value);
}
public double HeaderFontSize
{
get => (double) GetValue(HeaderFontSizeProperty);
set => SetValue(HeaderFontSizeProperty, value);
}
public string HeaderText
{
get => (string) GetValue(HeaderTextProperty);
set => SetValue(HeaderTextProperty, value);
}
#endregion
}
}
Page2.xaml
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:v="clr-namespace:TabbedPageDemo.Views" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="TabbedPageDemo.Views.Page2">
<ContentPage.Resources>
<Style TargetType="v:ReadOnlyField">
<!-- <Setter Property="HeaderFontSize" Value="14" /> -->
<!-- <Setter Property="DetailFontSize" Value="12" /> -->
</Style>
</ContentPage.Resources>
<ScrollView x:Name="ScrollView1" Padding="4">
<StackLayout x:Name="StackLayout0">
<v:ReadOnlyField HeaderFontSize="14" DetailFontSize="12" HeaderText="Header 1" DetailText="Detail 1" />
<v:ReadOnlyField HeaderFontSize="14" DetailFontSize="12" HeaderText="Header 2" DetailText="Detail 2" />
<v:ReadOnlyField HeaderFontSize="14" DetailFontSize="12" HeaderText="Header 3" DetailText="Detail 3" />
<v:ReadOnlyField HeaderFontSize="14" DetailFontSize="12" HeaderText="Header 4" DetailText="Detail 4" />
<v:ReadOnlyField HeaderFontSize="14" DetailFontSize="12" HeaderText="Header 5" DetailText="Detail 5" />
<v:ReadOnlyField HeaderFontSize="14" DetailFontSize="12" HeaderText="Header 6" DetailText="Detail 6" />
<v:ReadOnlyField HeaderFontSize="14" DetailFontSize="12" HeaderText="Header 7" DetailText="Detail 7" />
<v:ReadOnlyField HeaderFontSize="14" DetailFontSize="12" HeaderText="Header 8" DetailText="Detail 8" />
<v:ReadOnlyField HeaderFontSize="14" DetailFontSize="12" HeaderText="Header 9" DetailText="Detail 9" />
<v:ReadOnlyField HeaderFontSize="14" DetailFontSize="12" HeaderText="Header 10" DetailText="Detail 10" />
<v:ReadOnlyField HeaderFontSize="14" DetailFontSize="12" HeaderText="Header 11" DetailText="Detail 11" />
<v:ReadOnlyField HeaderFontSize="14" DetailFontSize="12" HeaderText="Header 12" DetailText="Detail 12" />
<v:ReadOnlyField HeaderFontSize="14" DetailFontSize="12" HeaderText="Header 13" DetailText="Detail 13" />
<v:ReadOnlyField HeaderFontSize="14" DetailFontSize="12" HeaderText="Header 14" DetailText="Detail 14" />
<v:ReadOnlyField HeaderFontSize="14" DetailFontSize="12" HeaderText="Header 15" DetailText="Detail 15" />
<v:ReadOnlyField HeaderFontSize="14" DetailFontSize="12" HeaderText="Header 16" DetailText="Detail 16" />
<v:ReadOnlyField HeaderFontSize="14" DetailFontSize="12" HeaderText="Header 17" DetailText="Detail 17" />
<v:ReadOnlyField HeaderFontSize="14" DetailFontSize="12" HeaderText="Header 18" DetailText="Detail 18" />
<v:ReadOnlyField HeaderFontSize="14" DetailFontSize="12" HeaderText="Header 19" DetailText="Detail 19" />
<v:ReadOnlyField HeaderFontSize="14" DetailFontSize="12" HeaderText="Header 20" DetailText="Detail 20" />
</StackLayout>
</ScrollView>
</ContentPage>
If I uncomment either of the two lines in the <Style> element, I get the following error:
Can't resolve *propertyName* on ReadOnlyField
What I would like to do is use an implicit style such as the one I am attempting to define so that I don't have to specify property values many times over.
What am I missing / doing wrong?
The error is caused by the Access Modifiers.
Please change private to public.
Change:
private static readonly BindableProperty DetailFontSizeProperty;
private static readonly BindableProperty DetailTextProperty;
private static readonly BindableProperty HeaderFontSizeProperty;
private static readonly BindableProperty HeaderTextProperty;
To:
public static readonly BindableProperty DetailFontSizeProperty;
public static readonly BindableProperty DetailTextProperty;
public static readonly BindableProperty HeaderFontSizeProperty;
public static readonly BindableProperty HeaderTextProperty;
And you could define an style using the x:Key attribute like below. The property should match the BindableProperty you defined.
<ContentPage.Resources>
<Style x:Key="ReadOnlyFieldStyle" TargetType="v:ReadOnlyField">
<Setter Property="HeaderFontSize" Value="14" />
<Setter Property="DetailFontSize" Value="12" />
<!--<Setter Property="HeaderText" Value="Header1"></Setter>
<Setter Property="DetailText" Value="Detail"></Setter>-->
</Style>
And use the style.
<v:ReadOnlyField Style="{Binding StaticResource ReadOnlyFieldStyle}" HeaderText="Header 1" DetailText="Detail 1"></v:ReadOnlyField>
<v:ReadOnlyField Style="{Binding StaticResource ReadOnlyFieldStyle}" HeaderText="Header 2" DetailText="Detail 2"></v:ReadOnlyField>
Result:
Related
I want to customize the scrollbars on a mx|Tree component is Flex 4.
I would like to mimic this functionality: http://flexponential.com/2009/10/09/changing-the-position-of-the-scroll-bars-in-a-spark-list/
Any thoughts or reccomendations?
This can work, add your own error checking/styling, but you get the idea:
<s:VGroup gap="-1">
<s:Button width="100%" label="Scroll up" click="{tree.verticalScrollPosition--}" />
<mx:Tree id="tree" labelField="#label" showRoot="false" width="300" height="150"
verticalScrollPolicy="off">
<mx:dataProvider>
<fx:XML>
<root>
<node label="Parent 1">
<node label="Child 1" />
<node label="Child 2">
<node label="Grandchild 1" />
<node label="Grandchild 2" />
</node>
<node label="Child 3" />
<node label="Child 4" />
<node label="Child 5" />
<node label="Child 6" />
<node label="Child 7" />
<node label="Child 8" />
<node label="Child 9" />
</node>
</root>
</fx:XML>
</mx:dataProvider>
</mx:Tree>
<s:Button width="100%" label="Scroll Down" click="{tree.verticalScrollPosition++}"/>
</s:VGroup>
you could also try to use verticalScrollBarStyleName/horizontalScrollBarStyleName with a css style. But ofc it lacks the comfort of spark skins. ;)
I am trying to use ContextMenu() to display context menus in Flex 4.
Full Render code here http://pastebin.com/Kx8tJ1cY
The problem is that the context menu does not change when I add items to it.
Can anyone show me how to add a custom right click menu to a List box in flex (without using external JS, just using ContextMenu as Adobe intended.
Please and Thank you
Craig
I found the problem/solution. You cant use context menus if there are Vboxes or Tab Navigators. Which is insane because it means I cant do relative layout properly or decent variable width design.
Quoted from: http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/ui/ContextMenu.html
For example, if a DataGrid control is a child of a TabNavigator or VBox container, the DataGrid control cannot have its own context menu.
Have you tried setting the contextMenu property of the List to you context menu? FlexExamples has a similar example posted for the DataGrid component. A List shouldn't be too different.
Something along these lines:
<?xml version="1.0" encoding="utf-8"?>
<!-- http://blog.flexexamples.com/2007/08/20/using-a-custom-context-menu-with-the-flex-datagrid-control/ -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
layout="vertical"
verticalAlign="middle"
backgroundColor="white"
creationComplete="init()">
<mx:Script>
<![CDATA[
import mx.controls.Alert;
[Bindable]
private var cm:ContextMenu;
private var alert:Alert;
private function init():void {
var cmi:ContextMenuItem = new ContextMenuItem("View item...", true);
cmi.addEventListener(ContextMenuEvent.MENU_ITEM_SELECT, contextMenuItem_menuItemSelect);
cm = new ContextMenu();
cm.hideBuiltInItems();
cm.customItems = [cmi];
cm.addEventListener(ContextMenuEvent.MENU_SELECT, contextMenu_menuSelect);
}
private function contextMenu_menuSelect(evt:ContextMenuEvent):void {
dataGrid.selectedIndex = lastRollOverIndex;
}
private function contextMenuItem_menuItemSelect(evt:ContextMenuEvent):void {
var obj:Object = dataGrid.selectedItem;
alert = Alert.show("Property A: " + obj.#propertyA + "\\n" + "Property B: " + obj.#propertyB, obj.#label, Alert.OK);
}
]]>
</mx:Script>
<mx:XML id="itemsXML">
<items>
<item label="Item 1" data="i001" propertyA="Item 1.A" propertyB="Item 1.B" />
<item label="Item 2" data="i002" propertyA="Item 2.A" propertyB="Item 2.B" />
<item label="Item 3" data="i003" propertyA="Item 3.A" propertyB="Item 3.B" />
<item label="Item 4" data="i004" propertyA="Item 4.A" propertyB="Item 4.B" />
<item label="Item 5" data="i005" propertyA="Item 5.A" propertyB="Item 5.B" />
<item label="Item 6" data="i006" propertyA="Item 6.A" propertyB="Item 6.B" />
<item label="Item 7" data="i007" propertyA="Item 7.A" propertyB="Item 7.B" />
<item label="Item 8" data="i008" propertyA="Item 8.A" propertyB="Item 8.B" />
</items>
</mx:XML>
<mx:Number id="lastRollOverIndex" />
<mx:DataGrid id="dataGrid"
width="400"
dataProvider="{itemsXML.item}"
contextMenu="{cm}"
itemRollOver="lastRollOverIndex = event.rowIndex">
<mx:columns>
<mx:DataGridColumn id="labelCol"
dataField="#label"
headerText="Label:" />
<mx:DataGridColumn id="propACol"
dataField="#propertyA"
headerText="Property A:" />
<mx:DataGridColumn id="propBCol"
dataField="#propertyB"
headerText="Property B:" />
</mx:columns>
</mx:DataGrid>
<mx:Label text="{dataGrid.selectedItem.#label}" />
</mx:Application>
I hope to find an answer on customizing Datagrid from WPF toolkit 2010. I'd like to add a TITLE area to be above DataGridColumnHeaderPresenter of the datagrid. The problem is that I want it to be as a user control or data template where I can populate the title from XML. I want to have unique titles for multiple datagrids on one page getting data from one XML. I populate few datagrids in the same window. What will be the best solution to add customizable Tile area for a content populated from XML and bounded to each datagrid to avoid dublication?
Thank you in advance. I generate datagrid with columns this way:
<Custom:DataGrid Grid.Column="0" Grid.Row="1" x:Name="ServerList" ItemsSource="{Binding Source={StaticResource PagesData}, XPath=ListTiles/Tile1}">
<Custom:DataGrid.Columns>
<Custom:DataGridTextColumn Header="Name" Binding="{Binding XPath=#Name}" />
<Custom:DataGridTextColumn Header="Status" Binding="{Binding XPath=#Status}" />
<Custom:DataGridTextColumn Header="Events" Binding="{Binding XPath=#Events}" />
<Custom:DataGridTextColumn Header="Services" Binding="{Binding XPath=#Services}" />
</Custom:DataGrid.Columns>
<Custom:DataGrid x:Name="Events" Grid.Column="0" Grid.Row="2" ItemsSource="{Binding Source={StaticResource PagesData}, XPath=ListTiles/Tile2}" >
<Custom:DataGrid.Columns>
<Custom:DataGridTextColumn Header="Name" Binding="{Binding XPath=#Name}" />
<Custom:DataGridTextColumn Header="Level" Binding="{Binding XPath=#Level}" />
<Custom:DataGridTextColumn Header="Source" Binding="{Binding XPath=#Source}" />
<Custom:DataGridTextColumn Header="In last 24h" Binding="{Binding XPath=#TimeSpan}" />
</Custom:DataGrid.Columns>
<Custom:DataGrid x:Name="Services" Grid.Column="2" Grid.Row="2" ItemsSource="{Binding Source={StaticResource PagesData}, XPath=ListTiles/Tile3}">
<Custom:DataGrid.Columns>
<Custom:DataGridTextColumn Header="Name" Binding="{Binding XPath=#Name}" />
<Custom:DataGridTextColumn Header="Status" Binding="{Binding XPath=#Status}" />
<Custom:DataGridTextColumn Header="Start" Binding="{Binding XPath=#Start}" />
</Custom:DataGrid.Columns>
XML:
<?xml version="1.0" encoding="utf-8"?>
<ListTiles xmlns="">
<Tile1>
<Header Title="ROLES & GROUPS" />
<Server Name="Kim" Status="ready" Events="1" Services="1" />
<Server Name="Sherri" Status="past" Events="2" Services="1"/>
<Server Name="Mike" Status="future" Events="3" Services="1" />
</Tile1>
<Tile2>
<Header Title="EVENTS" />
<Server Name="Young" Level="average" Source="home" TimeSpan="5" />
<Server Name="Sarah" Level="Critical" Source="work" TimeSpan="6" />
<Server Name="Susan" Level="normal" Source="friend" TimeSpan="2" />
</Tile2>
<Tile3>
<Header Title="SERVICES" />
<Server Name="Josh" DisplayName="FF" Status="Running" Start="Auto" />
<Server Name="Amy" DisplayName="DD" Status="Rest" Start="Auto" />
<Server Name="Bill" DisplayName="AS" Status="Work" Start="Auto" />
</Tile3>
</ListTiles>
I have an ItemRenderer that is shared by several applications (inside a DataGrid), and I would like to add a context menu to it (rather than in each application). The renderer is derived from the Canvas class, and the code to create the context menu looks something like:
var menuItem:ContextMenuItem = new ContextMenuItem("Test");
menuItem.addEventListener(ContextMenuEvent.MENU_ITEM_SELECT, contextCallback);
var customContextMenu:ContextMenu = new ContextMenu();
customContextMenu.hideBuiltInItems(); //hide flash menu
customContextMenu.customItems.push(menuItem);
this.contextMenu = customContextMenu;
However, when I right click on the cell in the datagrid, I get the default Flash Context Menu. Is this not possible?
Edit: Here is a fully runnable example, which doesn't show the context menu's:
Application.mxml:
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
layout="vertical"
verticalAlign="middle"
backgroundColor="white">
<mx:Model id="items">
<items>
<item label="Item 1" data="i001" propertyA="Item 1.A" propertyB="Item 1.B" />
<item label="Item 2" data="i002" propertyA="Item 2.A" propertyB="Item 2.B" />
<item label="Item 3" data="i003" propertyA="Item 3.A" propertyB="Item 3.B" />
<item label="Item 4" data="i004" propertyA="Item 4.A" propertyB="Item 4.B" />
<item label="Item 5" data="i005" propertyA="Item 5.A" propertyB="Item 5.B" />
<item label="Item 6" data="i006" propertyA="Item 6.A" propertyB="Item 6.B" />
<item label="Item 7" data="i007" propertyA="Item 7.A" propertyB="Item 7.B" />
<item label="Item 8" data="i008" propertyA="Item 8.A" propertyB="Item 8.B" />
</items>
</mx:Model>
<mx:DataGrid id="dataGrid" width="400" dataProvider="{items.item}">
<mx:columns>
<mx:DataGridColumn headerText="No Menu" dataField="label" />
<mx:DataGridColumn headerText="Menu" dataField="propertyA" itemRenderer="canvasRenderer"/>
</mx:columns>
</mx:DataGrid>
canvasRenderer.mxml:
<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml" width="100%" verticalScrollPolicy="off" horizontalScrollPolicy="off" resize="this.setSize()" creationComplete="init()" implements="mx.controls.listClasses.IDropInListItemRenderer">
<mx:Script>
<![CDATA[
import mx.controls.listClasses.ListData;
import mx.controls.dataGridClasses.DataGridListData;
import mx.controls.listClasses.BaseListData;
import mx.events.FlexEvent;
private var _listData:DataGridListData;
private function init():void {
var menuItem:ContextMenuItem = new ContextMenuItem("Copy", true);
menuItem.addEventListener(ContextMenuEvent.MENU_ITEM_SELECT, function():void {
trace("selected");
});
var menu:ContextMenu = new ContextMenu();
menu.hideBuiltInItems(); //hide flash menu
menu.customItems.push(menuItem);
this.contextMenu = menu;
}
public override function set data(value:Object):void {
super.data = value;
if(_listData && myLabel) {
var text:String = _listData.label ? _listData.label : value[_listData.dataField];
myLabel.text = text;
myLabel.toolTip = text;
}
}
public function get listData():BaseListData { return _listData; }
public function set listData(value:BaseListData):void { _listData = DataGridListData(value); }
public function setSize():void { myLabel.width = this.width; }
]]>
</mx:Script>
<mx:Label id="myLabel" truncateToFit="true"/>
This works:
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
layout="vertical"
verticalAlign="middle"
backgroundColor="white"
creationComplete="init()">
<mx:Script>
<![CDATA[
import mx.controls.Alert;
[Bindable] public var cm1:ContextMenu;
[Bindable] public var cm2:ContextMenu;
private function init():void {
var cmi1:ContextMenuItem = new ContextMenuItem("View item in column 1...", true);
cmi1.addEventListener(ContextMenuEvent.MENU_ITEM_SELECT, contextMenuItem_menuItemSelect);
cm1 = new ContextMenu();
cm1.hideBuiltInItems();
cm1.customItems = [cmi1];
cm1.addEventListener(ContextMenuEvent.MENU_SELECT, contextMenu_menuSelect);
var cmi2:ContextMenuItem = new ContextMenuItem("View item in column 2...", true);
cmi2.addEventListener(ContextMenuEvent.MENU_ITEM_SELECT, contextMenuItem_menuItemSelect);
cm2 = new ContextMenu();
cm2.hideBuiltInItems();
cm2.customItems = [cmi2];
cm2.addEventListener(ContextMenuEvent.MENU_SELECT, contextMenu_menuSelect);
}
private function contextMenu_menuSelect(evt:ContextMenuEvent):void {
dataGrid.selectedIndex = lastRollOverIndex;
}
private function contextMenuItem_menuItemSelect(evt:ContextMenuEvent):void {
var obj:Object = dataGrid.selectedItem;
Alert.show("Property A: " + obj.propertyA + "\n" + "Property B: " + obj.propertyB, obj.label, Alert.OK);
}
]]>
</mx:Script>
<mx:Model id="items">
<items>
<item label="Item 1" data="i001" propertyA="Item 1.A" propertyB="Item 1.B" />
<item label="Item 2" data="i002" propertyA="Item 2.A" propertyB="Item 2.B" />
<item label="Item 3" data="i003" propertyA="Item 3.A" propertyB="Item 3.B" />
<item label="Item 4" data="i004" propertyA="Item 4.A" propertyB="Item 4.B" />
<item label="Item 5" data="i005" propertyA="Item 5.A" propertyB="Item 5.B" />
<item label="Item 6" data="i006" propertyA="Item 6.A" propertyB="Item 6.B" />
<item label="Item 7" data="i007" propertyA="Item 7.A" propertyB="Item 7.B" />
<item label="Item 8" data="i008" propertyA="Item 8.A" propertyB="Item 8.B" />
</items>
</mx:Model>
<mx:Number id="lastRollOverIndex" />
<mx:DataGrid id="dataGrid" width="400" dataProvider="{items.item}">
<mx:columns>
<mx:DataGridColumn headerText="Label">
<mx:itemRenderer>
<mx:Component>
<mx:Label text="{data.label}" contextMenu="{outerDocument.cm1}"/>
</mx:Component>
</mx:itemRenderer>
</mx:DataGridColumn>
<mx:DataGridColumn headerText="Property A">
<mx:itemRenderer>
<mx:Component>
<mx:Label text="{data.propertyA}" contextMenu="{outerDocument.cm2}"/>
</mx:Component>
</mx:itemRenderer>
</mx:DataGridColumn>
</mx:columns>
</mx:DataGrid>
<mx:Label text="{dataGrid.selectedItem.label}" />
</mx:Application>
I've added the context menu to an itemRenderer in a List with the Flextras DataSorter. However, I don't see any difference between what I did and what you're doing.
Source code here:
http://www.flextras.com/DataSorter/Samples/RightClick/srcview/index.html
and the running Sample
http://www.flextras.com/DataSorter/Samples/RightClick/
Can you share more code? What is the "this" that you're adding the context menu too? Is your temRenderer in-line or a separate component?
<mx:Script>
<![CDATA[
private function openAllNodes():void {
tree.openItems = dp..node;
}
private function closeAllNodes():void {
tree.openItems = [];
}
]]>
</mx:Script>
<mx:XML id="dp">
<root>
<node label="Parent 1">
<node label="Child 1" />
<node label="Child 2">
<node label="Grandchild 1" />
<node label="Grandchild 2" />
</node>
<node label="Child 3" />
<node label="Child 4" />
</node>
</root>
</mx:XML>
<mx:ApplicationControlBar dock="true">
<mx:Button label="Open all nodes" click="openAllNodes();" />
<mx:Button label="Close all nodes" click="closeAllNodes();" />
</mx:ApplicationControlBar>
<mx:Tree id="tree"
dataProvider="{dp}"
showRoot="false"
labelField="#label"
width="200" />
Unless or other wise i click my parent list, the child or the next list must be in a disabled state.
I click on Child 1, then only Child 2 Must be able to select.
Please Help Me.
It sounds like you might want to extend the tree class and override some of the methods to implement your special functionality. Look at overriding the drawItem, mouseClickHandler, and possibly the expandItem functions.