How to access silverlight3 DataGrid cell control - silverlight-3.0

how to access silverlight3 DataGrid cell value programatically?
I know that I can use DataContext to access the data, but I need to access control contained in a specific cell.
If column template is like this:
<data:DataGridTemplateColumn Header="Header text">
<data:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBox TextAlignment="Right" x:Name="myTxt" Text="{Binding Path=Val1, Mode=TwoWay}" TextWrapping="Wrap" Width="50" HorizontalAlignment="Left"/>
</DataTemplate>
</data:DataGridTemplateColumn.CellTemplate>
</data:DataGridTemplateColumn>
how can I get a reference to myTxt control?
Thank you

You can use this to examine the visual tree:
private void GetVisualTreeChildren(DependencyObject element, int depth)
{
string spacer = new string(' ', depth * 2);
System.Diagnostics.Debug.WriteLine(spacer + element.GetType().ToString());
TextBox txt = element as TextBox;
if (txt != null)
{
...
}
int childCount = VisualTreeHelper.GetChildrenCount(element);
for (int i = 0; i < childCount; i++)
{
DependencyObject child = VisualTreeHelper.GetChild(element, i);
GetVisualTreeChildren(child, depth + 1);
}
}
Maybe you can adapt it to what you need?

Related

Dependency Property stops updating after target property changes due to edit in UI

I have a custom dependency property on my control like so (boilerplate to implement the control left out):
public static readonly DependencyProperty ValueProperty = DependencyProperty.Register(
"Value",
typeof(String),
typeof(BindingTestControl),
new PropertyMetadata(null));
public static void SetValue(UIElement element, string value)
{
element.SetValue(ValueProperty, value);
}
public static string GetValue(UIElement element)
{
return (string)element.GetValue(ValueProperty);
}
I created a page with code-behind to bind to with relevant xaml like so (with x:Name="root" on the page):
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<local:BindingTestControl Value="{Binding ElementName=root, Path=StringItem}"/>
<Button Width="200" Height="100" Tapped="Button_Tapped" FlowDirection="RightToLeft"/>
</Grid>
With code-behind like so (again, only relevant parts shown):
private string stringItem = "";
public string StringItem
{
get
{
return stringItem;
}
set
{
this.stringItem = value;
OnPropertyChanged("StringItem");
}
}
int i = 0;
private void Button_Tapped(object sender, TappedRoutedEventArgs e)
{
//i++;
this.StringItem = "Test" + i;
}
This works fine the first time, but if I update the value in the Textbox, the binding won't overwrite the new value. If I uncomment the i++; then the binding overwrites every time. I'm assuming this happens this way because the value that is being sent with INotifyPropertyChanged is the same as the previous one despite the value in the Textbox no longer being the same.
Is there a way to force the value through the binding even if it hasn't changed?
You could change your setter to something like -
set
{
this.stringItem = null;
this.stringItem = value;
OnPropertyChanged("StringItem");
}
Which should force the PropertyChanged event to fire as a change in value has occurred.

MvxRadioGroupSelectedIndexBinding

i created a RadioGroupSelectedIndexBinding from the source of MvxRadioGroupSelectedItemBinding.
It works ok, but not at viewmodel startup: the binding from viewmodel to view is called but at this time the RadioGroup has no child views. It seems they haven't been inflated yet.
This is a "bug" (or feature :p) in Mvvmcross custom inflater/binding ? Or is there something to overload in MvxAndroidTargetBinding ?
Edit: code of MvxRadioGroupSelectedIndexBinding (Index, not Item: different from MvxRadioGroupSelectedItemBinding).
public class MvxRadioGroupSelectedIndexBinding : MvxAndroidTargetBinding
{
bool stopListeningCheckChanged = false;
private int selectedIndex = -2;
public int SelectedIndex
{
get { return selectedIndex; }
set { if(value != selectedIndex) { selectedIndex = value; FireValueChanged(SelectedIndex); } }
}
public static void Register(IMvxTargetBindingFactoryRegistry registry)
{
registry.RegisterCustomBindingFactory<RadioGroup>("SelectedIndex", radioGroup => new MvxRadioGroupSelectedIndexBinding(radioGroup));
}
public MvxRadioGroupSelectedIndexBinding(RadioGroup radioGroup) : base(radioGroup)
{
if (radioGroup == null)
{
Mvx.Trace(MvxTraceLevel.Error, "RadioGroup SelectedIndex: radioGroup is null");
return;
}
radioGroup.CheckedChange += CheckedChange;
radioGroup.ChildViewAdded += RadioGroupOnChildViewAdded;
}
private void RadioGroupOnChildViewAdded(object sender, ViewGroup.ChildViewAddedEventArgs childViewAddedEventArgs)
{
var radioGroup = Target as RadioGroup;
if (selectedIndex == radioGroup.ChildCount-1)
{
stopListeningCheckChanged = true;
radioGroup.Check(radioGroup.GetChildAt(selectedIndex).Id);
stopListeningCheckChanged = false;
}
}
private void CheckedChange(object sender, RadioGroup.CheckedChangeEventArgs e)
{
if (stopListeningCheckChanged)
return;
var radioGroup = Target as RadioGroup;
var checkedId = e.CheckedId;
if (checkedId == View.NoId)
{
SelectedIndex = -1;
return;
}
for (var i = radioGroup.ChildCount - 1; i >= 0; i--)
{
if (checkedId == radioGroup.GetChildAt(i).Id)
{
SelectedIndex = i;
return;
}
}
SelectedIndex = -1;
Mvx.Trace(MvxTraceLevel.Error, "RadioGroup id not found: {0}", checkedId);
}
public override void SetValue(object index)
{
var radioGroup = Target as RadioGroup;
if (radioGroup == null)
return;
stopListeningCheckChanged = true;
selectedIndex = (int)index;
if (selectedIndex < 0 || selectedIndex >= radioGroup.ChildCount)
{
radioGroup.ClearCheck();
}
else
{
radioGroup.Check(radioGroup.GetChildAt(selectedIndex).Id);
}
stopListeningCheckChanged = false;
}
public override Type TargetType
{
get { return typeof(object); }
}
protected override void SetValueImpl(object target, object value)
{
}
public override MvxBindingMode DefaultMode
{
get { return MvxBindingMode.TwoWay; }
}
protected override void Dispose(bool isDisposing)
{
if (isDisposing)
{
var radioGroup = Target as RadioGroup;
if (radioGroup != null)
{
radioGroup.CheckedChange -= CheckedChange;
radioGroup.ChildViewAdded -= RadioGroupOnChildViewAdded;
}
}
base.Dispose(isDisposing);
}
}
And usage
<RadioGroup
android:orientation="horizontal"
local:MvxBind="SelectedIndex SelectedChoiceIndex">
<RadioButton
android:text="choice 1"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<RadioButton
android:text="choice 2"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</RadioGroup>
The "bug" is that when SetValue is called, the RadioGroup has no childs. I suppose the custom inflater create and binds views at the same time. In fact it should bind views only when their childs are inflated. I may be wrong though, i've not checked the source code. And it could have other bad side effects.
This is a "bug" (or feature :p) in Mvvmcross custom inflater/binding ?
Neither - I think this is simply out of scope of what the MvxRadioGroup was designed to target.
MvxRadioGroupSelectedItemBinding was a user contribution and I believe it was designed to be used exactly as shown in https://github.com/MvvmCross/MvvmCross-Tutorials/pull/8:
<MvxRadioGroup
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textSize="40dp"
local:MvxItemTemplate="#layout/item_radio"
local:MvxBind="ItemsSource Items;SelectedItem SelectedItem"
/>
=> so it is designed to work for lists of items where the ItemsSource is first set, and then the SelectedItem is also set.
I don't believe the author of that MvxRadioGroup had any intention of supporting AXML based lists of radio choices.
With that said, if anyone wants to author a more extensive RadioGroup solution - e.g. one that can cope with AXML defined lists or that can cope with ItemsSource changes after SelectedItem has been set, then I think this should be perfectly possible to do - and it looks like you've already gone a long way towards this :) To "perfectly" handle all combinations of dynamic and static list changes, would probably require using some kind of technique which rechecks the SelectedItem property each and every time the ItemsSource and/or static items have been added. For practical reasons I think this recheck would need to be performed within some custom RadioGroup and/or binding based code - I don't think there's any way to do this within the XML inflation handlers as Android simply doesn't present any suitable childrenInflatedAndAdded type callbacks during inflation.
It may also be interesting to note that XAML presents similar challenges in this area - e.g. see Silverlight XAML Attribute Definition Order Matters for a XAML ComboBox scenario where the items must be set before the selected item.

Rerender/update a JSF 2.0 custom component using a primefaces command button does not work

Thanks in advance for your attention.
I've created a JSF 2.0 custom component to render Google GeoCharts. So, the renderer just writes some javascript and a div at the end.
The component works fine doing that. But my requirement is that the GeoChart should change its values using an ajax request. To do that, i'm using a primefaces command button putting in its attribute "update" the id of the geoChart.
The problem is that the GeoChart is not being updated when the comand button is clicked.
I'm using a maven archetype (myfaces-archetype-jsfcomponents20) allowing the automatic generation of some configuration files. So, I just need to write to classes and annotations. Those classes are the UIComponent and the Renderer.
I'm running this code in GlassFish 3.1 and Mojarra 2.1.6
The code of those classes:
UIComponent:
#JSFComponent(
name = "processum:geochart",
clazz = "org.processum.component.gchart.GoogleChart",
tagClass = "org.processum.component.gchart.GoogleChartTag")
abstract class AbstractGoogleChart extends UIComponentBase {
public static final String COMPONENT_TYPE = "org.processum.GoogleChart";
public static final String DEFAULT_RENDERER_TYPE = "org.processum.GoogleChartRenderer";
public static final String COMPONENT_FAMILY = "javax.faces.Output";
/**
*
* GoogleChartModel
*/
#JSFProperty
public abstract GoogleGeoChartModel getModel();
}
Renderer:
#JSFRenderer(
renderKitId = "HTML_BASIC",
family = "javax.faces.Output",
type = "org.processum.GoogleChartRenderer")
public class GoogleChartRenderer extends Renderer {
#Override
public void encodeEnd(FacesContext context, UIComponent component) throws IOException {
GoogleChart chart = (GoogleChart) component;
String divId = (String) component.getClientId() + "chartDiv";
GoogleGeoChartModel model = chart.getModel();
ResponseWriter writer = context.getResponseWriter();
writer.write("<script type='text/javascript'>"
+ "google.load('visualization', '1', {'packages': ['geochart']});"
+ "google.setOnLoadCallback(initGeoMap);"
+ "function initGeoMap() {"
+ "var data = google.visualization.arrayToDataTable(["
+ "[");
StringBuilder data = new StringBuilder();
for (String header : model.getHeaders()) {
data.append("\'").append(header).append("\'").append(",");
}
data.deleteCharAt(data.length() - 1).append("],");
for (String[] value : model.getValues()) {
data.append("[");
for (int i = 0; i < value.length; i++) {
if (i == 0) {
data.append("\'").append(value[i]).append("\'");
} else {
data.append(value[i]);
}
data.append(",");
}
data.deleteCharAt(data.length() - 1).append("],");
}
data.deleteCharAt(data.length() - 1);
writer.write(data.toString());
writer.write("]);");
writer.write("var options = {"
+ "region: 'CO',"
+ "displayMode: 'markers'"
+ "};"
+ "var chart = new google.visualization.GeoChart(document.getElementById(\'" + divId + "\'));"
+ "chart.draw(data, options);"
+ "};"
+ "</script>"
+ "<div id=\"" + divId + "\"/>");
}
}
XHTML:
<h:form>
<div id="anotherContent" style="width: 900px; height: 500px;">
<h:panelGroup id="chartCont" layout="block">
<processum:geochart id="chart" model="#{chartBackBean.model}"/>
</h:panelGroup>
</div>
<p:commandButton id="change" value="Cambio" actionListener="#{chartBackBean.change}" update="chart"/>
</h:form>
Some debugging:
The ajax request is triggered adequately. The managed bean updates the GoogleGeoChartModel with new values.
Next, the control flow goes to the Renderer which "encodes" the new values of the chart (that means that the encondeEnd is called again). But, this new "enconding" is not painted in the browser.
The html has two JSF components. My custom component and a h:panelGroup. If in the "update" attribute on primefaces button I put the id of the chart's div and then I trigger the ajax request, the chart does not change. But instead I put the id of the h:panelGroup, the div of the chart disappears.

How can I add WaterMark property to PasswordBox in Winrt?

I need WatermarkPasswordBox control but there is not in Winrt. Maybe we can add Watermark property to PasswordBox. Are there anyone who can do it?
Thanks
The purpose of a watermark is to convey a message behind the control. In the case of this demonstration, the watermark also dissappear after you start typing text, so they are more like a field "hint" telling you what is expected.
To achieve this, we turn to a regular WPF solution provider, the AttachedProperty. AttachedProperties allow you to add extra properties to any control. You can also extend it into an Attachedbehaviour, where you are making the control react to changes to the property.
In this example, we use two attached properties. The first "WaterrmarkProperty" to take the watermark value and initialise the control:
public static string GetWatermark(DependencyObject obj)
{
return (string)obj.GetValue(WatermarkProperty);
}
public static void SetWatermark(DependencyObject obj, string value)
{
obj.SetValue(WatermarkProperty, value);
}
public static readonly DependencyProperty WatermarkProperty =
DependencyProperty.RegisterAttached("Watermark", typeof(string), typeof(TextBoxHelper), new UIPropertyMetadata(null, WatermarkChanged));
The second attached property is to notify whether there is a value in the box, which the template binds to and hides or shows the watermark.
public static bool GetShowWatermark(DependencyObject obj)
{
return (bool)obj.GetValue(ShowWatermarkProperty);
}
public static void SetShowWatermark(DependencyObject obj, bool value)
{
obj.SetValue(ShowWatermarkProperty, value);
}
public static readonly DependencyProperty ShowWatermarkProperty =
DependencyProperty.RegisterAttached("ShowWatermark", typeof(bool), typeof(TextBoxHelper), new UIPropertyMetadata(false));
For the TextBoxHelper, whenever the text is changed, the watermark is shown or hidden as follows:
private static void CheckShowWatermark(TextBox box)
{
box.SetValue(TextBoxHelper.ShowWatermarkProperty, box.Text == string.Empty);
}
This is controlled by the ControlTemplate:
<ControlTemplate x:Key="WatermarkedTextBoxTemplate" TargetType="{x:Type TextBox}">
<Microsoft_Windows_Themes:ListBoxChrome x:Name="Bd" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" RenderMouseOver="{TemplateBinding IsMouseOver}" RenderFocused="{TemplateBinding IsKeyboardFocusWithin}" SnapsToDevicePixels="true">
<Grid>
<TextBlock Text="{Binding Path=(local:TextBoxHelper.Watermark), RelativeSource={RelativeSource TemplatedParent}}" Opacity=".5" FontWeight="Bold" Visibility="{Binding (local:TextBoxHelper.ShowWatermark), Converter={StaticResource BooleanToVisibilityConverter}, RelativeSource={RelativeSource TemplatedParent}}" />
<ScrollViewer x:Name="PART_ContentHost" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</Grid>
</Microsoft_Windows_Themes:ListBoxChrome>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Background" TargetName="Bd" Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"/>
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
Source: http://code.msdn.microsoft.com/windowsdesktop/Watermarked-TextBox-and-444ebdec
In Windows 8.0 you can use the WatermarkPasswordBox from WinRT XAML Toolkit, which you can get from here. It gives you a Watermark property to set any UI element (Shape, Image, etc.) as a watermark or WatermarkText property that takes a text and WatermarkTextStyle that takes a TextBlock Style to style the text.
In Windows 8.1 you can use the same or use the new PlaceholderText property.
Feel free to rip out and modify the WatermarkPasswordBox control's code from the library and use it in your app. It's MIT licensed. No credits required. Just take the .cs and .xaml files and include the .xaml resource dictionary in your Themes/Generic.xaml like so:
<ResourceDictionary
Source="ms-appx:///YourControlsLibraryNamefNotInMainApp/RelativeDirectoryPathOfTheFile/WatermarkPasswordBox.xaml" />
UPDATE 1
If you don't want to use 3rd party DLL, add these two methods in PasswordBoxBehavior.cs file.
using System.Reflection;
public static T FindVisualChildByName<T>(this DependencyObject fe, string name) where T : DependencyObject
{
if (string.IsNullOrEmpty(name))
{
throw new ArgumentNullException("name");
}
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(fe); i++)
{
DependencyObject child = VisualTreeHelper.GetChild(fe, i);
string a = child.GetValue(FrameworkElement.NameProperty) as string;
if (a == name)
{
return child as T;
}
T t = FindVisualChildByName<T>(child, name);
if (t != null)
{
return t;
}
}
return default(T);
}
public static T FindVisualParent<T>(this DependencyObject fe) where T : DependencyObject
{
for (fe = VisualTreeHelper.GetParent(fe); fe != null; fe = VisualTreeHelper.GetParent(fe))
{
T t = fe as T;
if (t != null)
{
return t;
}
}
return default(T);
}
Here's extensive blog from JulMar
Adding a watermark to a PasswordBox in a Windows Store app
Here’s the code if you’d like to use it yourself.

Why is my WPF binding not working in state change?

I have some items in a WrapPanel. I want to be able to click on an item and have it expand to the full width of the wrap panel. I tried doing this by creating two states, Expanded and Colapsed, in the control that is used for each item. For the Expanded state, I bound the Width of the control to be equal to the ActualWidth of the WrapPanel.
When I didn't get the result I expected, I tried setting Expanded value to a specific number (instead of the the binding). That is working. The items toggle between the two Colapsed and Exapanded widths. I still want to have the Expanded state be equal to the width of the WrapPanel though, not an arbitrary fixed width. I know my binding works because if I just bind the Width property directly (not via visual states), the items in the WrapPanel match its width.
Expanded state with Binding - Doesn't work:
<VisualState x:Name="Expanded">
<Storyboard>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(FrameworkElement.Width)" Storyboard.TargetName="JobMaster">
<EasingDoubleKeyFrame KeyTime="0">
<EasingDoubleKeyFrame.Value>
<Binding
Path="ActualWidth"
RelativeSource="{RelativeSource FindAncestor, AncestorType={x:Type WrapPanel}}" />
</EasingDoubleKeyFrame.Value>
</EasingDoubleKeyFrame>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
Expanded State with hard coded value - Works
<VisualState x:Name="Expanded">
<Storyboard>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(FrameworkElement.Width)" Storyboard.TargetName="JobMaster">
<EasingDoubleKeyFrame KeyTime="0" Value="800" />
</DoubleAnimationUsingKeyFrames>
</Storyboard>
Bind the control Width property directly works
<UserControl.Width>
<Binding
Path="ActualWidth"
RelativeSource="{RelativeSource AncestorType={x:Type WrapPanel}}" />
</UserControl.Width>
So why doesn't the Binding in the state work or is there another way to do this?
I was never able to get this working using visual states. Instead I wrote a behavoir.
public class TileExpandColapseBehavoir : Behavior<Control>
{
private ITile _data;
#region Properties
public static readonly DependencyProperty TileControlProperty = DependencyProperty.Register("TileControl", typeof(object), typeof(TileExpandColapseBehavoir), new PropertyMetadata(null));
public static readonly DependencyProperty DefaultWidthProperty = DependencyProperty.Register("DefaultWidth", typeof(Double), typeof(TileExpandColapseBehavoir), new PropertyMetadata(null));
public object TileControl
{
get { return (object)this.GetValue(TileControlProperty); }
set { this.SetValue(TileControlProperty, value); }
}
public double DefaultWidth
{
get { return (double)this.GetValue(DefaultWidthProperty); }
set { this.SetValue(DefaultWidthProperty, value); }
}
#endregion
public TileExpandColapseBehavoir()
{
}
protected override void OnAttached()
{
this.AssociatedObject.PreviewMouseDown +=new MouseButtonEventHandler(AssociatedObject_MouseUp);
}
private void AssociatedObject_MouseUp(object sender, MouseButtonEventArgs e)
{
UIElement child = (UIElement)sender;
WrapPanel parentWrap = FindAncestorUtil.TryFindAcestor<WrapPanel>(child);
if (parentWrap != null && TileControl is UserControl)
{
GetData();
if (_data.IsExpanded == false)
{
Binding newBinding = new Binding();
newBinding.Source = parentWrap;
newBinding.Path = new PropertyPath("ActualWidth");
UserControl thisTile = (UserControl)TileControl;
BindingOperations.SetBinding(thisTile, UserControl.WidthProperty, newBinding);
_data.IsExpanded = true;
}
else
{
UserControl thisTile = (UserControl)TileControl;
BindingOperations.ClearBinding(thisTile, UserControl.WidthProperty);
thisTile.Width = DefaultWidth;
_data.IsExpanded = false;
}
}
}
private void GetData()
{
if (_data == null && AssociatedObject.DataContext is ITile)
{
_data = (ITile)AssociatedObject.DataContext;
}
}
}
Your RelativeSource binding is looking for an ancestor of the animation, not the target of the animation. Try giving your WrapPanel a name and use Element binding instead.
<Binding Path="ActualWidth" ElementName="MyWrapPanel"/>

Resources