uwp: data binding programmatically issue - xaml

i'm developing with uwp and i've a problem with data binding. I have a listView that i fill with a custom panel elements called PlaylistLeftOption class. This class inherit Panel class attributes that inherit FrameworkElement class attribute and its methods so i have a SetBinding method avaible.
Now i'm trying to bind the height value (it's equal to other elements) so i created a static attribute, called PerformanceItemHeight, in other extern singleton class.
since i need to fill listview dinamically i'm trying to bind the value inside the constructor but it don't work.
This is the code inside constructor:
public PlaylistLeftOption()
{
mainGrid.Background = new SolidColorBrush(Colors.Red);
mainGrid.BorderBrush = new SolidColorBrush(Colors.Black);
mainGrid.BorderThickness = new Thickness(0.5,0.25,0.5,0.25);
WidthVal = 200;
HeightVal = 50;
var myBinding = new Binding();
myBinding.Source = PerformanceLayout.Instance.PerformanceItemHeight;
myBinding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
myBinding.Mode = BindingMode.TwoWay;
SetBinding(HeightValProperty, myBinding);
Children.Add(mainGrid);
}
And this is the property:
public static readonly DependencyProperty HeightValProperty = DependencyProperty.Register(
"HeightVal",
typeof(double),
typeof(PlaylistLeftOption),
new PropertyMetadata(50)
);
public double HeightVal
{
get => (double)GetValue(HeightValProperty);
set
{
SetValue(HeightValProperty, value);
Height = HeightVal;
mainGrid.Height = HeightVal;
globalSize.Height = HeightVal;
}
}
This is the code for PerformanceItemHeight:
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
// Raise the PropertyChanged event, passing the name of the property whose value has changed.
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
private double _performanceItemHeight = 50;
public double PerformanceItemHeight {
get => _performanceItemHeight;
set {
_performanceItemHeight = value;
this.OnPropertyChanged();
}
}
Why does via xaml it works?
i tryied to add PlaylistLeftOption item inside listview via xaml and it's ok!
thank you

By testing, the binding of HeightVal works in XAML and the binding of HeightVal does not work in code-behind. You could see the reason in the section Implementing the wrapper of the document Custom dependency properties which says that your wrapper implementations should perform only the GetValue and SetValue operations. Otherwise, you'll get different behavior when your property is set via XAML versus when it is set via code.
You could add a property-changed callback method to notify the changes of HeightVal actively.
For example:
public static readonly DependencyProperty HeightValProperty = DependencyProperty.Register(
"HeightVal",
typeof(double),
typeof(PlaylistLeftOption),
new PropertyMetadata(100, new PropertyChangedCallback(OnHeightValChanged))
);
private static void OnHeightValChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
PlaylistLeftOption playlistLeftOption = d as PlaylistLeftOption;
if(playlistLeftOption != null)
{
var height = (Double)e.NewValue;
playlistLeftOption.HeightVal = height;
}
}
And change the binging code like this:
var myBinding = new Binding();
myBinding.Source = PerformanceLayout.Instance;
myBinding.Path = new PropertyPath("PerformanceItemHeight");
myBinding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
myBinding.Mode = BindingMode.TwoWay;
SetBinding(HeightValProperty, myBinding);

Related

Windows Store Apps: animate control when visibility changes?

In my app I have A grid with visibility bound to a property in the view model.
What I want to do is when the visibility property changes at the view model, the grid fades in or out according to the visibility value: Visible/Collapsed.
how can I achieve this ?
Inspired by the answer of "HDW Production", here's the code for Windows Store and Windows Phone Store apps:
public class FadingVisibilityGrid : Grid
{
public static readonly DependencyProperty DeferredVisibilityProperty = DependencyProperty.Register(
"DeferredVisibility", typeof (Visibility), typeof (FadingVisibilityGrid), new PropertyMetadata(default(Visibility), DeferredVisibilityChanged));
private static void DeferredVisibilityChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
var newVisibility = (Visibility)e.NewValue;
var grid = (FadingVisibilityGrid)sender;
var animation = new DoubleAnimation
{
Duration = new Duration(TimeSpan.FromMilliseconds(200))
};
Storyboard.SetTarget(animation, grid);
Storyboard.SetTargetProperty(animation, "Grid.Opacity");
grid.FadeStoryBoard.Stop();
grid.FadeStoryBoard = new Storyboard();
grid.FadeStoryBoard.Children.Add(animation);
if (newVisibility == Visibility.Visible)
{
animation.From = 0;
animation.To = 1;
grid.Visibility = Visibility.Visible;
grid.FadeStoryBoard.Begin();
}
else
{
animation.From = 1;
animation.To = 0;
grid.FadeStoryBoard.Completed += (o, o1) =>
{
grid.Visibility = newVisibility;
};
grid.FadeStoryBoard.Begin();
}
}
public Visibility DeferredVisibility
{
get { return (Visibility) GetValue(DeferredVisibilityProperty); }
set { SetValue(DeferredVisibilityProperty, value); }
}
private Storyboard _fadeStoryBoard = new Storyboard();
public Storyboard FadeStoryBoard
{
get { return _fadeStoryBoard; }
set { _fadeStoryBoard = value; }
}
}
You need a new DependencyProperty, either by inheriting from Grid and adding one or by creating an attached property. Let's call it DeferredVisibility and let it be of type Visibility.
When DeferredVisibility is changed to Visible, set the Visibility to Visible and animate the opacity from 0 to 1.
When DeferredVisibility is changed to Collapsed, animate the opacity from 1 to 0 and THEN set the Visibility to Collapsed.

How to change the skeleton color in the KinectSkeletonViewer provided by the SDK v1.6

I want to change the KinectSkeletonViewer control provided in the Kinect examples.
I want to expose a property to change the color of the skeleton (tracked bones).
What i need to do?
You'll need to modify two files - KinectSkeleton.cs and KinectSkeletonViewer.xaml.cs. You're creating the binding on the KinectSkeleton but, because this class is not directly referenced and called from the viewer, you also need to create a passthrough binding in KinectSkeletonViewer.
KinectSkeleton.cs - create the DependencyProperties:
public static readonly DependencyProperty TrackedJointBrushProperty =
DependencyProperty.Register(
"TrackedJointBursh",
typeof(Brush),
typeof(KinectSkeleton),
new FrameworkPropertyMetadata(new SolidColorBrush(Color.FromArgb(255, 68, 192, 68)), FrameworkPropertyMetadataOptions.AffectsRender));
public static readonly DependencyProperty TrackedBonePenProperty =
DependencyProperty.Register(
"TrackedBonePen",
typeof(Pen),
typeof(KinectSkeleton),
new FrameworkPropertyMetadata(new Pen(Brushes.Green, TrackedBoneThickness), FrameworkPropertyMetadataOptions.AffectsRender));
KinectSkeletonViewer - create the DependencyProperties
public static readonly DependencyProperty TrackedJointBrushProperty =
DependencyProperty.Register(
"TrackedJointBursh",
typeof(Brush),
typeof(KinectSkeletonViewer),
new PropertyMetadata(new SolidColorBrush(Color.FromArgb(255, 68, 192, 68))));
public static readonly DependencyProperty TrackedBonePenProperty =
DependencyProperty.Register(
"TrackedBonePen",
typeof(Pen),
typeof(KinectSkeletonViewer),
new PropertyMetadata(new Pen(Brushes.Green, TrackedBoneThickness)));
In both files define the associated properties:
public Brush TrackedJointBursh
{
get { return (Brush)GetValue(TrackedJointBrushProperty); }
set { SetValue(TrackedJointBrushProperty, value); }
}
public Pen TrackedBonePen
{
get { return (Pen)GetValue(TrackedBonePenProperty); }
set { SetValue(TrackedBonePenProperty, value); }
}
Now you want to link the binding. In the OnLoad event of KinectSkeletonViewer -
var trackedJointBrush = new Binding("TrackedJointBrush");
trackedJointBrush.Source = this;
skeletonCanvas.SetBinding(KinectSkeleton.TrackedJointBrushProperty, trackedJointBrush);
var trackedBonePen = new Binding("TrackedBonePen");
trackedBonePen.Source = this;
skeletonCanvas.SetBinding(KinectSkeleton.TrackedBonePenProperty, trackedBonePen);
Finally, you need to look through KinectSkeleton.cs and replace reference of the hard coded colors with the new properties. trackedJointBrush and trackedBonePen in the case of the above examples - replaced with TrackedJointBrush and TrackedBonePen (note case). You can then comment out the hard coded variables.
You should now be able to bind those two properties in the KinectSkeletonViewer when you declare it in XAML.
There are a few other colors defined in the KinectSkeleton class. You can use the same concept as above to bind them as well.

Programatically create command button in Primefaces

I am trying to create a dynamic form with input text and command button. Everything works fine. But when I click on the command button, the action listener is never called. Please suggest what I am doing wrong or if this is a bug with PF or Mojarra. The code is below
panel = new Panel();
panel.setHeader("Test");
InputText text = new InputText();
final String binding = "#{roleCreateForm.role.name}";
text.setValueExpression("value",
createValueExpression(binding, String.class));
panel.getChildren().add(text);
CommandButton button = new CommandButton();
button.setValue("Save");
MethodExpression me = createMethodExpression("#{roleCreateForm.save}");
button.addActionListener(new MethodExpressionActionListener(me));
panel.getChildren().add(button);
Also the createXXXExpression are below
private MethodExpression createMethodExpression(String action) {
final Class<?>[] paramTypes = new Class<?>[0];
MethodExpression methodExpression = getExpressionFactory()
.createMethodExpression(getELContext(),action, null, paramTypes);
return methodExpression;
}
private ValueExpression createValueExpression(String binding,
Class<String> clazz) {
final ValueExpression ve = getExpressionFactory()
.createValueExpression(getELContext(), binding, String.class);
return ve;
}
public static ELContext getELContext() {
return FacesContext.getCurrentInstance().getELContext();
}
public static ExpressionFactory getExpressionFactory() {
return getApplication().getExpressionFactory();
}
public static Application getApplication() {
return FacesContext.getCurrentInstance().getApplication();
}
My form bean is below
public void save() {
logger.info("Saving role - {}" , role);
}
I am using
Primefaces 3.2, Mojarra 2.1.7, Tomcat 7, JDK 6 , Ubuntu 11
Here is my modified code
Yes I have seen that you have pointed out this as the common mistake. But here is my modified code. This does not work either.
public Panel getPanel() {
if (panel == null) {
panel = new Panel();
panel.setHeader("Test");
panel.setId("dynapanel");
InputText text = new InputText();
text.setId("dynatext");
final String binding = "#{roleCreateForm.role.name}";
text.setValueExpression("value", createValueExpression(binding, String.class));
panel.getChildren().add(text);
CommandButton button = new CommandButton();
button.setValue("Save");
MethodExpression me = getExpressionFactory().createMethodExpression(getELContext(), "#{roleCreateForm.save}", void.class, new Class[0]);
AjaxBehavior ajaxBehavior = new AjaxBehavior();
//ajaxBehavior.setListener( me );
ajaxBehavior.addAjaxBehaviorListener( new AjaxBehaviorListenerImpl( me ) );
button.addClientBehavior( "submit", ajaxBehavior);
panel.getChildren().add(button);
}
return panel;
}
As far as I remember, if you want to invoke a method in your backing bean, use a MethodExpression as a Listener of your AjaxBehaviour:
AjaxBehavior ab1 = new AjaxBehavior();
ExpressionFactory ef = ctx.getApplication().getExpressionFactory();
MethodExpression me1 = ef.createMethodExpression(ctx.getELContext(),
expression,//Your ELExpression #{roleCreateForm.save}
expectedReturnType, //In your case null
expectedParamTypes); //If you receive parameters put new Class[]{Object.class});
ab1.setListener(me1);
button.addClientBehavior( "submit", ab1);
CommandButton btn = ((CommandButton) FacesContext.getCurrentInstance().getViewRoot().findComponent("full id of button"));
try{
FacesContext context = FacesContextWrapper.getCurrentInstance();
MethodExpressionActionListener methodExpression = new MethodExpressionActionListener(context.getApplication().getExpressionFactory()
.createMethodExpression(context.getELContext(),"#{bean.method}", null, new Class[] {ActionEvent.class}));
btn.addActionListener(methodExpression);
}catch(Exception exc){
exc.printStackTrace();
}
and createMethodExpression :
public static MethodExpression createMethodExpression(String expression, Class<?> returnType, Class<?>... parameterTypes) {
FacesContext facesContext = FacesContext.getCurrentInstance();
return facesContext.getApplication().getExpressionFactory().createMethodExpression(
facesContext.getELContext(), expression, returnType, parameterTypes);
}
This works for me ;)

Binding to UserControl in WinRT

I created a simple Rating user control, the problem this control won't in WinRT work when I use binding, it works fine on windows phone, This is my Control:
public sealed partial class RatingControl : UserControl
{
public int Rate { get { return (int)GetValue(RateProperty); } set { SetValue(RateProperty, value); } }
public static readonly DependencyProperty RateProperty = DependencyProperty.Register("Rate",
typeof(int),
typeof(RatingControl), null);
public RatingControl()
{
this.InitializeComponent();
this.Loaded += RatingControl_Loaded;
}
void RatingControl_Loaded(object sender, RoutedEventArgs e)
{
List<Image> Images = new List<Image>();
for (int i = 0; i < 5; i++)
{
Image img = new Image { Width = 35, Height = 35, Margin = new Thickness(3) };
img.Source = new BitmapImage { UriSource = new System.Uri("ms-appx:Images/Stars/notFilled.png") };
Images.Add(img);
sp.Children.Add(img);
}
for (int i = 0; i < Rate; i++)
Images[i].Source = new BitmapImage { UriSource = new System.Uri("ms-appx:Images/Stars/Filled.png") };
}
}
When I hardcode the value, it works fine:
<local:RatingControl Rate="3" />
but when I use Binding, it just shows zero stars. I checked the value of Rate, it is always zero.
<local:RatingControl Rate="{Binding Decor, Mode=TwoWay}" />
UPDATE: I just found out that the binding happens before I get the value of the Rate, so its zero all the time. How can I fix that? I need the binding to happens after I get the value. Also I thought the Binding happens everytime I change the Rate value.
SOLUTION: I Didnt implement the DependencyObject right, I should've done this:
public static readonly DependencyProperty RateProperty = DependencyProperty.Register("Rate",
typeof(int),
typeof(RatingControl), new PropertyMetadata(0, new PropertyChangedCallback(BindRateControl)));
SOLUTION: I Didnt implement the DependencyObject right, I should've done this (adding a callback method):
public static readonly DependencyProperty RateProperty = DependencyProperty.Register("Rate",
typeof(int),
typeof(RatingControl),
new PropertyMetadata(0, new PropertyChangedCallback(BindRateControl)));
has you try adding the UserControl from code-behind. this help you to ensure that the UserControl is triggered after getting the value.

TextDecorationCollection serialization in WPF

Is there any xaml serialization attribute that I can specify for a dependency property which actually is a collection (TextDecorationCollection)?
I want to use serialization for cloning a very large and complex object. Here a sample of the code, simplified:
There is a MyVisualObject, that contains a lot of properties, including a custom font, which I want to clone
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public class Export : Attribute
{
}
public class MyVisualObject : DependencyObject
{
[Export]
public CustomFont Font
{
get { return (CustomFont)GetValue(FontProperty); }
set { SetValue(FontProperty, value); }
}
// Using a DependencyProperty as the backing store for Font. This enables animation, styling, binding, etc...
public static readonly DependencyProperty FontProperty =
DependencyProperty.Register("Font", typeof(CustomFont), typeof(MyVisualObject));
public MyVisualObject()
{
this.Font = new CustomFont();
}
}
And the custom font is defined like this:
public class CustomFont : DependencyObject
{
public TextDecorationCollection Decorations
{
get { return (TextDecorationCollection)GetValue(DecorationsProperty); }
set { SetValue(DecorationsProperty, value); }
}
// Using a DependencyProperty as the backing store for TextDecorations. This enables animation, styling, binding, etc...
public static readonly DependencyProperty DecorationsProperty =
DependencyProperty.Register("Decorations", typeof(TextDecorationCollection), typeof(CustomFont), new UIPropertyMetadata(new TextDecorationCollection()));
public CustomFont()
{
this.Decorations = System.Windows.TextDecorations.Underline;
}
}
THe deep clone method:
public static T DeepClone<T>(T from)
{
object clone = Activator.CreateInstance(from.GetType());
Type t = from.GetType();
System.Reflection.PropertyInfo[] pinf = t.GetProperties();
foreach (PropertyInfo p in pinf)
{
bool serialize = false;
foreach (object temp in p.GetCustomAttributes(true))
{
if (temp is Export)
{
serialize = true;
}
}
if (serialize)
{
string xaml = XamlWriter.Save(p.GetValue(from, null));
XmlReader rd = XmlReader.Create(new StringReader(xaml));
p.SetValue(clone, XamlReader.Load(rd), null);
}
}
return (T)clone;
}
The problem is that each time I initialize the Decorations as Underline
this.Decorations = System.Windows.TextDecorations.Underline;
the cloning process crashes with this error:'Add value to collection of type 'System.Windows.TextDecorationCollection' threw an exception.' Line number '1' and line position '213'.
As far as I found out, the serialization, which is this part
string xaml = XamlWriter.Save(p.GetValue(from, null));
returns an xaml which does not have the decorations set as a collection:
<CustomFont xmlns="clr-namespace:WpfApplication1;assembly=WpfApplication1" xmlns:av="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<CustomFont.Decorations>
<av:TextDecoration Location="Underline" />
</CustomFont.Decorations>
</CustomFont>
But the clone process would work if the xaml would be like this:
<CustomFont xmlns="clr-namespace:WpfApplication1;assembly=WpfApplication1" xmlns:av="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<CustomFont.Decorations>
<av:TextDecorationCollection>
<av:TextDecoration Location="Underline" />
</av:TextDecorationCollection>
</CustomFont.Decorations>
</CustomFont>
I found a workaround, something with string replacements:
xaml = xaml.Replace("<CustomFont.Decorations><av:TextDecoration Location=\"Underline\" /></CustomFont.Decorations>", "<CustomFont.Decorations><av:TextDecorationCollection><av:TextDecoration Location=\"Underline\" /></av:TextDecorationCollection></CustomFont.Decorations>");
but I think it's really dirty, and I would apreciate it if you could provide a more clean solution (specifying an attribute for the Decorations property for example)
Have you tried applying the following attribute to the Decorations property:
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]