Animate a textblock from a point to another - animation

I want to move a TextBlock element from the rigth part of the screen to the left one (Like text at the news).
<Canvas>
<!-- Offset the text using a TranslateTransform. -->
<TextBlock Text="{Binding Picker}" VerticalAlignment="Bottom" Margin="0,0,0,0" TextWrapping="Wrap" FontSize="33" >
<TextBlock.RenderTransform>
<TranslateTransform X="2" Y="2" />
</TextBlock.RenderTransform>
</TextBlock>
<TextBlock Text="{Binding Picker}" VerticalAlignment="Bottom" Margin="0,0,0,0" TextWrapping="Wrap" FontSize="33" />
</Canvas>
I can't find a Property/Action to achieve that, I'm really newbie to UWP , and I know that the XAML I have, doesn't do anything like that.
It only put another TextBlock like a shadow effect.

Here is one of possible solutions - by usage of some VisualStates:
<Canvas>
<Canvas.Resources>
<local:InvertBooleanConverter x:Key="InvBoolConverter"/>
</Canvas.Resources>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="States">
<VisualState x:Name="Left">
<Storyboard>
<DoubleAnimation Storyboard.TargetName="myTextBlock" Storyboard.TargetProperty="(Canvas.Left)" To="0" Duration="0:0:1"/>
</Storyboard>
<VisualState.StateTriggers>
<StateTrigger IsActive="{Binding ElementName=myButton, Path=IsOn, Converter={StaticResource InvBoolConverter}}"/>
</VisualState.StateTriggers>
</VisualState>
<VisualState x:Name="Right">
<Storyboard>
<DoubleAnimation Storyboard.TargetName="myTextBlock" Storyboard.TargetProperty="(Canvas.Left)" To="200" Duration="0:0:1"/>
</Storyboard>
<VisualState.StateTriggers>
<StateTrigger IsActive="{Binding ElementName=myButton, Path=IsOn}"/>
</VisualState.StateTriggers>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<!-- Offset the text using a TranslateTransform. -->
<TextBlock x:Name="myTextBlock" Text="Test" VerticalAlignment="Bottom" Margin="0,0,0,0" TextWrapping="Wrap" FontSize="33" />
<ToggleSwitch x:Name="myButton" Margin="0,50,0,0" OffContent="Left" OnContent="Right"/>
</Canvas>
and the converter in the behind:
public class InvertBooleanConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language) => !(bool)value;
public object ConvertBack(object value, Type targetType, object parameter, string language) => throw new NotImplementedException();
}

I've create a Templated Control in one of my projects, where the text moves automatically when the Text is larger than the rectangle itself... maybe that will help you or gives you an idea
public enum MarqueeScrollingDirection
{
FromLeft,
FromRight,
FromTop,
FromBottom,
None,
}
public sealed class MarqueeUserControl : Control
{
public static readonly DependencyProperty MarqueeDirectionProperty = DependencyProperty.Register(nameof(MarqueeDirection), typeof(MarqueeScrollingDirection), typeof(MarqueeUserControl),new PropertyMetadata(MarqueeScrollingDirection.None));
public MarqueeScrollingDirection MarqueeDirection
{
get { return (MarqueeScrollingDirection)GetValue(MarqueeDirectionProperty); }
set { SetValue(MarqueeDirectionProperty, value); }
}
public static readonly DependencyProperty MarqueeTextProperty = DependencyProperty.Register(nameof(MarqueeText), typeof(string), typeof(MarqueeUserControl), new PropertyMetadata(string.Empty));
public string MarqueeText
{
get { return (string)GetValue(MarqueeTextProperty); }
set { SetValue(MarqueeTextProperty, value); }
}
public MarqueeUserControl()
{
this.DefaultStyleKey = typeof(MarqueeUserControl);
this.SizeChanged += MarqueeUserControl_SizeChanged;
}
private Canvas ContentCanvas;
private TextBlock MarqueeTextBlock;
private Storyboard storyboard;
private DoubleAnimation doubleAnimation;
protected override void OnApplyTemplate()
{
MarqueeTextBlock = (TextBlock)GetTemplateChild(nameof(MarqueeTextBlock));
ContentCanvas = (Canvas)GetTemplateChild(nameof(ContentCanvas));
if (MarqueeDirection != MarqueeScrollingDirection.None)
{
MarqueeTextBlock.SizeChanged += MarqueeUserControl_SizeChanged;
storyboard = new Storyboard();
doubleAnimation = new DoubleAnimation();
doubleAnimation.AutoReverse = true;
doubleAnimation.RepeatBehavior = RepeatBehavior.Forever;
if (MarqueeDirection == MarqueeScrollingDirection.FromLeft || MarqueeDirection == MarqueeScrollingDirection.FromRight)
{
Storyboard.SetTargetProperty(doubleAnimation, "(UIElement.RenderTransform).(TranslateTransform.X)");
}
if (MarqueeDirection == MarqueeScrollingDirection.FromTop || MarqueeDirection == MarqueeScrollingDirection.FromBottom)
{
Storyboard.SetTargetProperty(doubleAnimation, "(UIElement.RenderTransform).(TranslateTransform.Y)");
}
Storyboard.SetTarget(doubleAnimation, MarqueeTextBlock);
}
else
{
(MarqueeTextBlock.RenderTransform as TranslateTransform).X = (ContentCanvas.ActualWidth - MarqueeTextBlock.ActualWidth) / 2;
}
}
private void MarqueeUserControl_SizeChanged(object sender, SizeChangedEventArgs e)
{
if (MarqueeDirection != MarqueeScrollingDirection.None)
{
bool play = false;
RectangleGeometry rectangleGeometry = new RectangleGeometry()
{
Rect = new Rect(0, 0, ContentCanvas.ActualWidth, ContentCanvas.ActualHeight)
};
ContentCanvas.Clip = rectangleGeometry;
storyboard.Stop();
storyboard.Children.Clear();
switch (MarqueeDirection)
{
case MarqueeScrollingDirection.FromLeft:
doubleAnimation.From = MarqueeTextBlock.ActualWidth > ContentCanvas.ActualWidth ? ContentCanvas.ActualWidth - MarqueeTextBlock.ActualWidth : 0;
doubleAnimation.To = 0;
doubleAnimation.Duration = new Duration(TimeSpan.FromSeconds(MarqueeTextBlock.ActualWidth > ContentCanvas.ActualWidth ? ((MarqueeTextBlock.ActualWidth - ContentCanvas.ActualWidth) / 10) +1 : 0));
play = MarqueeTextBlock.ActualWidth > ContentCanvas.ActualWidth;
break;
case MarqueeScrollingDirection.FromRight:
doubleAnimation.From = 0;
doubleAnimation.To = MarqueeTextBlock.ActualWidth > ContentCanvas.ActualWidth ? ContentCanvas.ActualWidth - MarqueeTextBlock.ActualWidth : 0;
doubleAnimation.Duration = new Duration(TimeSpan.FromSeconds(MarqueeTextBlock.ActualWidth > ContentCanvas.ActualWidth ? ((MarqueeTextBlock.ActualWidth - ContentCanvas.ActualWidth) / 10) + 1 : 0));
play = MarqueeTextBlock.ActualWidth > ContentCanvas.ActualWidth;
break;
case MarqueeScrollingDirection.FromTop:
play = MarqueeTextBlock.ActualWidth > ContentCanvas.ActualWidth;
break;
case MarqueeScrollingDirection.FromBottom:
play = MarqueeTextBlock.ActualWidth > ContentCanvas.ActualWidth;
break;
case MarqueeScrollingDirection.None:
play = false;
break;
default:
break;
}
if (play)
{
storyboard.Children.Add(doubleAnimation);
storyboard.Begin();
}
else
{
(MarqueeTextBlock.RenderTransform as TranslateTransform).X = (ContentCanvas.ActualWidth - MarqueeTextBlock.ActualWidth) / 2;
}
}
}
}
And the Generic.xaml
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:uc="using:roomZone.UserControls">
<Style TargetType="uc:MarqueeUserControl" >
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="uc:MarqueeUserControl">
<RelativePanel x:Name="RootElement"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}" >
<Canvas x:Name="ContentCanvas" RelativePanel.AlignLeftWithPanel="True" RelativePanel.AlignRightWithPanel="True" RelativePanel.AlignTopWithPanel="True" RelativePanel.AlignBottomWithPanel="True"
MinWidth="100" MinHeight="16" >
<Border VerticalAlignment="Center" >
<TextBlock x:Name="MarqueeTextBlock"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Text="{TemplateBinding MarqueeText}"
Foreground="{TemplateBinding Foreground}"
FontFamily="{TemplateBinding FontFamily}"
FontSize="{TemplateBinding FontSize}"
FontStyle="{TemplateBinding FontStyle}"
FontStretch="{TemplateBinding FontStretch}"
FontWeight="{TemplateBinding FontWeight}" >
<TextBlock.RenderTransform>
<TranslateTransform />
</TextBlock.RenderTransform>
</TextBlock>
</Border>
</Canvas>
</RelativePanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>

Related

Visual state manager does not work on a button in a collection view

I'm trying to change the background color or text color of a button in a collection view when clicked, this is what I have so far, but it is not working. I even tried to have the button as the root but the state still does not change
<CollectionView
ItemsSource="{Binding Suburbs}"
SelectionMode="None"
VerticalScrollBarVisibility="Never"
HorizontalScrollBarVisibility="Never">
<CollectionView.ItemsLayout>
<LinearItemsLayout Orientation="Horizontal" ItemSpacing="5" />
</CollectionView.ItemsLayout>
<CollectionView.ItemTemplate>
<DataTemplate>
<StackLayout
VerticalOptions="Start">
<Button
Padding="15"
CornerRadius="10"
BorderColor="Black"
BorderWidth="1"
TextColor="Black"
CommandParameter="{Binding .}"
Command="{Binding Source={x:Reference browse}, Path=BindingContext.CitySelectedCommand}"
BackgroundColor="Transparent"
Text="{Binding name}"
HeightRequest="30"
VerticalOptions="Start"
HorizontalOptions="FillAndExpand">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="ColorStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Pressed">
<VisualState.Setters>
<Setter Property="TextColor" Value="Red"/>
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Button>
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</StackLayout>
``
Actually VisualStateGroup does work .
However the color only changes when you're pressing on the button , the color will change to origin color after you release the button .
Refer to Visual states in Xamarin.Forms.
If you want the button stays another color after clicking on it , you need to create a property in the model and bind it to the TextColor/BackgroundColor.
Xaml
TextColor="{Binding color}"
Command="{Binding command}"
Model
public class Model : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public string name { get; set; }
public Color _color;
public Color color {
get { return _color; }
set {
_color = value;
NotifyPropertyChanged();
}
}
public ICommand command { get; set; }
bool isClick = false;
public Model()
{
color = Color.Black;
command = new Command((obj)=> {
isClick = !isClick;
color = isClick ? Color.Red : Color.Black;
});
}
}

Can I set multiple properties on a template at the same time with one parameter?

I have this template:
<?xml version="1.0" encoding="utf-8"?>
<Frame xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
       xmlns:local="clr-namespace:Japanese;assembly=Japanese"
       x:Class="Japanese.Templates.ButtonTemplate"
       x:Name="this" CornerRadius="5"
       BackgroundColor="{Binding FrameBackgroundColor, Source={x:Reference this}}"
       BorderColor="{Binding FrameBorderColor, Source={x:Reference this}}"
       HorizontalOptions="FillAndExpand" HasShadow="false"
       HeightRequest="35" Padding="0">
<StackLayout Orientation="Horizontal" Padding="10,5" HorizontalOptions="FillAndExpand">
     <Label Text="{Binding Text,  Source={x:Reference this}}" FontSize="16"
         TextColor="{Binding LabelTextColor, Source={x:Reference this}}"
               x:Name="label1"
               HorizontalOptions="CenterAndExpand"
               VerticalOptions="Center" HorizontalTextAlignment="Center" />
       <Frame.GestureRecognizers>
         <TapGestureRecognizer Command="{Binding TapButtonPressed, Source={x:Reference this}}" CommandParameter="{Binding Param, Source={x:Reference this}}" NumberOfTapsRequired="1" />
        </Frame.GestureRecognizers>
    </StackLayout>
</Frame>
and this backing CS:
    
public partial class ButtonTemplate : Frame
{
public event EventHandler Action;
    public ButtonTemplate()
    {
     InitializeComponent();
    }
    public ICommand TapButtonPressed
    {
     get
        {
         return new Command((object componentIdentifier) =>
            {
             this.Action?.Invoke(this, new EventArgs());
            });
         }
     }
     public static readonly BindableProperty EnabledProperty =
            BindableProperty.Create(
                nameof(Enabled),
                typeof(bool),
                typeof(ButtonTemplate),
                default(bool));
                        
     public bool Enabled { get; set; }
     public static readonly BindableProperty FrameBackgroundColorProperty =
            BindableProperty.Create(
                nameof(FrameBackgroundColor),
                typeof(Color),
                typeof(ButtonTemplate),
                default(Color));
        
     public static readonly BindableProperty FrameBorderColorProperty =
            BindableProperty.Create(
                nameof(FrameBorderColor),
                typeof(Color),
                typeof(ButtonTemplate),
                default(Color));
        
     public static readonly BindableProperty ParamProperty =
            BindableProperty.Create(
                nameof(Param),
                typeof(string),
                typeof(ButtonTemplate),
                default(string));
        
     public static readonly BindableProperty LabelTextColorProperty =
            BindableProperty.Create(
                nameof(LabelTextColor),
                typeof(Color),
                typeof(ButtonTemplate),
                default(Color));
        
     public static readonly BindableProperty TextProperty =
            BindableProperty.Create(
                nameof(Text),
                typeof(string),
                typeof(ButtonTemplate),
                default(string));
        
     public Color FrameBackgroundColor
     {
      get { return (Color)GetValue(FrameBackgroundColorProperty); }
         set { SetValue(FrameBackgroundColorProperty, value); }
     }
     public Color FrameBorderColor
     {
         get { return (Color)GetValue(FrameBorderColorProperty); }
         set { SetValue(FrameBorderColorProperty, value); }
     }
     public Color LabelTextColor
     {
         get { return (Color)GetValue(LabelTextColorProperty); }
         set { SetValue(LabelTextColorProperty, value); }
     }
     public string Param
     {
         get { return (string)GetValue(ParamProperty); }
         set { SetValue(ParamProperty, value); }
     }
     public string Text
     {
         get { return (string)GetValue(TextProperty); }
         set { SetValue(TextProperty, value); }
     }
 }
Currently I use bindings to set TextColor, BorderColor and BackgroundColor. But all I need is two states enabled and disabled.  Is there a way I can set the three binding values all at the same time to one or other color set with just one binding parameter?
Edit:
So what I need is to just have one parameter so for example:
<template:button enabled="true">
BackgroundColor will be Blue
BorderColor will be Gray
TextColor will be White
Or:
<template:button enabled="false">
BackgroundColor will be White
BorderColor will be Black
TextColor will be Gray
So basically, you are trying to create a reusable control.
The easiest thing to do is just add an Enabled property on this in the code-behind. This also allows you to set it from XAML.
Just add: public bool Enabled { get; set; }.
You could then in the setter, reference the controls in your template by a name and set the properties like that. You would have to add an x:Key attribute to each of the controls.
Seeing you already have data-binding in place, you should be able to just update the properties that you are binding to from the setter.
If you also want to be able to bind to the new Enabled property, you will have to create it as a BindableProperty (docs). Add this:
public static readonly BindableProperty EnabledProperty =
BindableProperty.Create (nameof(Enabled), typeof(bool), typeof(ButtonTemplate), null, propertyChanged: OnEnabledChanged);
public bool Enabled { get; set; }
private static void OnEnabledChanged (BindableObject bindable, object oldValue, object newValue)
{
// Set the color properties here
}
The BindableProperty has an on property changed method where you can set the properties for the colors. By implementing it like this, you can also bind to the Enabled property: <template:button enabled="{Binding IsValid}">
Edit:
What I mean by setting the properties is this. But from your new code, I see you don't have data-binding in place here. You do have named your controls, so you can just refer to them and set their properties like this:
private static void OnEnabledChanged (BindableObject bindable, object oldValue, object newValue)
{
// Referencing controls
if ((bool)newValue)
{
BorderColor = Color.Red;
label1.BackgroundColor = Color.Red;
}
else
{
BorderColor = Color.Green;
label1.BackgroundColor = Color.Green;
}
// Using bindings
if ((bool)newValue)
{
FrameBackgroundColor = Color.Red;
FrameBorderColor = Color.Red;
}
else
{
FrameBackgroundColor = Color.Green;
FrameBorderColor = Color.Green;
}
}
I see that you have named your Frame this. That could cause problems since this is a reserved keyword in .NET. You might want to change that.
Would recommend using VisualStateManager for this particular use-case.
For e.g.
<Frame xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="SampleApp.ButtonView"
x:Name="this"
HorizontalOptions="FillAndExpand"
CornerRadius="5"
HasShadow="false"
HeightRequest="35" Padding="0">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal">
<VisualState.Setters>
<Setter Property="BackgroundColor" Value="Blue" />
<Setter Property="BorderColor" Value="Gray" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Focused" />
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Property="BackgroundColor" Value="White" />
<Setter Property="BorderColor" Value="Black" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<StackLayout Orientation="Horizontal" Padding="10,5" HorizontalOptions="FillAndExpand">
<Label Text="{Binding Text, Source={x:Reference this}}"
IsEnabled="{Binding IsEnabled, Source={x:Reference this}}"
FontSize="16"
HorizontalOptions="CenterAndExpand"
VerticalOptions="Center" HorizontalTextAlignment="Center">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal">
<VisualState.Setters>
<Setter Property="TextColor" Value="White" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Focused" />
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Property="TextColor" Value="Gray" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Label>
<Frame.GestureRecognizers>
<TapGestureRecognizer Command="{Binding TapButtonPressed,Source={x:Reference this}}"
CommandParameter="{Binding Param, Source={x:Reference this}}" NumberOfTapsRequired="1" />
</Frame.GestureRecognizers>
</StackLayout>
</Frame>
Code behind:
public partial class ButtonView : Frame
{
public ButtonView()
{
InitializeComponent();
VisualStateManager.GoToState(this, "Normal");
}
public static readonly BindableProperty TextProperty =
BindableProperty.Create(
"Text", typeof(string), typeof(ButtonView),
defaultValue: default(string));
public string Text
{
get { return (string)GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}
}

VisualStateManager.GoToState useTransitions Ignored in custom control UWP

I've created a custom control which inherits from contentControl . The control uses PlaneProjection.RotationX animation while changing from open to close and vice versa.
I want the control initial state to be in closed state. When the app launched the transition from open to close is shown even though I set changeVisualState(false).
What am I doing wrong?
My code:
public sealed class FlipPanel : ContentControl
{
private VisualState collapsedState;
private FrameworkElement contentElement;
public FlipPanel()
{
this.DefaultStyleKey = typeof(FlipPanel);
}
public bool IsOpen
{
get { return (bool)GetValue(IsOpenProperty); }
set { SetValue(IsOpenProperty, value); }
}
public static readonly DependencyProperty IsOpenProperty =
DependencyProperty.Register("IsOpen", typeof(bool), typeof(FlipPanel), new PropertyMetadata(false, onIsOpenChanged));
private static void onIsOpenChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
FlipPanel flipPanel = d as FlipPanel;
flipPanel.changeVisualState(true);
}
private void changeVisualState(bool useTransitions)
{
Debug.WriteLine(IsOpen.ToString());
if (IsOpen)
{
if (contentElement != null)
{
contentElement.Visibility = Visibility.Visible;
}
VisualStateManager.GoToState(this, "Opening", useTransitions);
}
else
{
VisualStateManager.GoToState(this, "Closing", useTransitions);
}
}
protected override void OnApplyTemplate()
{
base.OnApplyTemplate();
contentElement = (FrameworkElement)GetTemplateChild("Content");
if (contentElement != null)
{
collapsedState = (VisualState)GetTemplateChild("Closing");
if ((collapsedState != null) && (collapsedState.Storyboard != null))
{
collapsedState.Storyboard.Completed += (object sender, object e) =>
{
contentElement.Visibility = Visibility.Collapsed;
};
}
changeVisualState(false);
}
}
}
and my Style
<Style TargetType="local:FlipPanel" >
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:FlipPanel">
<Grid>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="ViewStates">
<VisualState x:Name="Opening">
<Storyboard>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Projection).(PlaneProjection.RotationX)" Storyboard.TargetName="Content">
<EasingDoubleKeyFrame KeyTime="0" Value="-90"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.2" Value="0"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Closing">
<Storyboard>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Projection).(PlaneProjection.RotationX)" Storyboard.TargetName="Content">
<EasingDoubleKeyFrame KeyTime="0" Value="0"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.2" Value="90"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Border BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Background="{TemplateBinding Background}">
<Grid>
<ContentPresenter Content="{TemplateBinding Content}" x:Name="Content">
<ContentPresenter.Projection>
<PlaneProjection CenterOfRotationX="0.5"/>
</ContentPresenter.Projection>
</ContentPresenter>
</Grid>
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
I think this is because you make the Content Collapsed in the Completed event of the storyboard and then you set changeVisualState(false);, it will do nothing since the "closing" storyboard is completed.
I modified your code of OnApplyTemplate like this and it works:
protected override void OnApplyTemplate()
{
base.OnApplyTemplate();
contentElement = (FrameworkElement)GetTemplateChild("Content");
if (contentElement != null)
{
if (!IsOpen)
contentElement.Visibility = Visibility.Collapsed;
else
changeVisualState(true);
}
}

WP7 UI controls like button and listbox events are not fired, in a user control class

I have a user control and in that user control there are ui controls like button and listbox, I have attached click and selection changed events of these controls from xaml and also tried by attaching them programmatically, but the events are not being fired.
any kind of help will be appreciated ,
Many thanks
here is the code .cs and xaml
<UserControl
x:Class="VisioLink.Views.MagazineListPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:views="clr-namespace:VisioLink.Views"
xmlns:toolkit="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls.Toolkit"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
mc:Ignorable="d" d:DesignHeight="768" d:DesignWidth="480"
shell:SystemTray.IsVisible="True"
Loaded="PhoneApplicationPage_Loaded"
xmlns:local="clr-namespace:VisioLink.Views">
<UserControl.Resources>
<local:BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
<Style x:Key="ListBoxItemStyle1" TargetType="ListBoxItem">
<Setter Property="Background" Value="Transparent"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="BorderBrush" Value="Transparent"/>
<Setter Property="Padding" Value="0"/>
<Setter Property="HorizontalContentAlignment" Value="Left"/>
<Setter Property="VerticalContentAlignment" Value="Top"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<Border x:Name="LayoutRoot" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" HorizontalAlignment="{TemplateBinding HorizontalAlignment}" VerticalAlignment="{TemplateBinding VerticalAlignment}">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal"/>
<VisualState x:Name="MouseOver"/>
<VisualState x:Name="Disabled">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="LayoutRoot">
<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource TransparentBrush}"/>
</ObjectAnimationUsingKeyFrames>
<DoubleAnimation Duration="0" To=".5" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="ContentContainer"/>
</Storyboard>
</VisualState>
</VisualStateGroup>
<VisualStateGroup x:Name="SelectionStates">
<VisualState x:Name="Unselected"/>
<VisualState x:Name="Selected">
<Storyboard>
<ObjectAnimationUsingKeyFrames
Storyboard.TargetName="ContentContainer"
Storyboard.TargetProperty="Foreground"
Duration="0">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<SolidColorBrush Color="White"/>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames
Storyboard.TargetName="border"
Storyboard.TargetProperty="Background"
Duration="0">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<SolidColorBrush Color="LightBlue"/>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<StackPanel x:Name="border" Orientation="Horizontal">
<!--<CheckBox x:Name="checkBox" IsChecked="{Binding RelativeSource={RelativeSource TemplatedParent},
Path=IsSelected, Mode=TwoWay}" DataContext="{TemplateBinding IsSelected}" Visibility="{Binding Converter={StaticResource BooleanToVisibilityConverter}}" HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"/>-->
<ContentControl x:Name="ContentContainer" ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" Foreground="{TemplateBinding Foreground}" HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"/>
</StackPanel>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</UserControl.Resources>
<!--LayoutRoot is the root grid where all page content is placed-->
<Grid x:Name="LayoutRoot" Background="White">
<toolkit:GestureService.GestureListener>
<toolkit:GestureListener Flick="GestureListener_Flick" />
</toolkit:GestureService.GestureListener>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition x:Name="firstCol" Width="40"></ColumnDefinition>
<ColumnDefinition x:Name="secondCol" Width="10"></ColumnDefinition>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<views:LeftMenuControl Visibility="Collapsed" x:Name="leftMenuControl" Grid.Column="0" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Grid.Row="1" ></views:LeftMenuControl>
<Button x:Name="flipBtn" Click="flip_click" Grid.Column="0" Height="70" Grid.Row="1" VerticalAlignment="Center">
<Button.Background>
<ImageBrush ImageSource="file:///C:/VisioLink/Resources/Images/next.png" />
</Button.Background>
</Button>
<Rectangle Fill="Black" Width="1" Grid.Column="1" Grid.Row="1" VerticalAlignment="Stretch" />
<!--TitlePanel contains the name of the application and page title-->
<StackPanel x:Name="TitlePanel" Grid.Row="0" Grid.Column="2" Margin="0,0,0,0">
<TextBlock x:Name="ApplicationTitle" Foreground="Black" Text="Nyhet" Style="{StaticResource PhoneTextNormalStyle}"/>
</StackPanel>
<!--ContentPanel - place additional content here-->
<StackPanel x:Name="ContentPanel" Grid.Row="1" Grid.Column="2" Margin="5,12,12,0">
<ListBox x:FieldModifier="public" x:Name="databoundListBoxMag" SelectionChanged="listBox1_SelectionChanged" ItemContainerStyle="{StaticResource ListBoxItemStyle1}" SelectionMode="Single">
<ListBox.ItemTemplate>
<DataTemplate>
<Border Margin="7"
BorderThickness="1"
BorderBrush="SteelBlue"
CornerRadius="3" x:Name="border1">
<StackPanel Width="450" x:Name="listItemPanel" Orientation="Vertical" Height="100" Margin="10,10,10,10">
<StackPanel x:Name="firstStack" Orientation="Horizontal">
<Image x:Name="magImage" Height="40" Width="40" Visibility="Collapsed" Source="Example4.PNG"></Image>
<TextBlock x:Name="itemone" FontWeight="Bold" TextAlignment="Left" Foreground="Black" Margin="0,0,0,0" HorizontalAlignment="Left" FontSize="22" Text="{Binding name}" Style="{StaticResource PhoneTextNormalStyle}"/>
</StackPanel>
<TextBlock x:Name="itemtwo" TextAlignment="Left" Foreground="Black" HorizontalAlignment="Left" Margin="0,0,0,0" FontSize="16" Text="{Binding content}" Style="{StaticResource PhoneTextNormalStyle}"/>
<!--<phone:WebBrowser Name="webBrowserContent" ScriptNotify="wb1_ScriptNotify" IsScriptEnabled="True" Source="http://www.bing.com" >
</phone:WebBrowser>-->
</StackPanel>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
<!--<ListBoxItem Style="{StaticResource ListBoxItemStyle1}">
<StackPanel x:Name="itemPanel" Grid.Row="0" Margin="0,0,0,28">
<TextBlock Height="72" HorizontalAlignment="Left" Name="nameBlock" Text="{Binding name}" VerticalAlignment="Top" Width="379" />
<TextBlock Height="72" HorizontalAlignment="Left" Name="detailBlock" Text="{Binding detail}" VerticalAlignment="Top" Width="379" />
</StackPanel>
</ListBoxItem>-->
</ListBox>
</StackPanel>
</Grid>
<!--Sample code showing usage of ApplicationBar-->
<!--<phone:PhoneApplicationPage.ApplicationBar>
<shell:ApplicationBar IsVisible="True" IsMenuEnabled="True">
<shell:ApplicationBarIconButton IconUri="/Images/appbar_button1.png" Text="Button 1"/>
<shell:ApplicationBarIconButton IconUri="/Images/appbar_button2.png" Text="Button 2"/>
<shell:ApplicationBar.MenuItems>
<shell:ApplicationBarMenuItem Text="MenuItem 1"/>
<shell:ApplicationBarMenuItem Text="MenuItem 2"/>
</shell:ApplicationBar.MenuItems>
</shell:ApplicationBar>
</phone:PhoneApplicationPage.ApplicationBar>-->
and here is its .cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Microsoft.Phone.Controls;
using System.Windows.Data;
using System.Globalization;
using System.Xml;
using System.Xml.Linq;
using System.IO;
using System.IO.IsolatedStorage;
using System.Windows.Resources;
using System.Text.RegularExpressions;
using VisioLink.DTO;
namespace VisioLink.Views
{
public partial class MagazineListPage : UserControl
{
public MagazineListPage()
{
InitializeComponent();
}
List<Article> articles = new List<Article>();
public int CatalogId { get; set; }
public string ContentToSee = string.Empty;
private void PhoneApplicationPage_Loaded(object sender, RoutedEventArgs e)
{
databoundListBoxMag.SelectionChanged += new SelectionChangedEventHandler(listBox1_SelectionChanged);
// List<Magazine> listMag = new List<Magazine>();
// listMag.Clear();
if(IsolatedStorageSettings.ApplicationSettings.Contains("magazineListPage"))
{
IsolatedStorageSettings.ApplicationSettings.TryGetValue("magazineListPage", out ContentToSee);
DoProcessingOnData();
}
else
{
WebClient client = new WebClient();
client.DownloadStringCompleted += new DownloadStringCompletedEventHandler(client_DownloadStringCompleted);
client.DownloadStringAsync(new Uri("http://device01.e-pages.dk/content/default4.php?customer=kaleva&catalog=" + CatalogId, UriKind.RelativeOrAbsolute));
}
}
void client_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
ContentToSee = e.Result;
IsolatedStorageSettings.ApplicationSettings.Add("magazineListPage", e.Result);
DoProcessingOnData();
}
private void DoProcessingOnData()
{
leftMenuControl.parent = this;
leftMenuControl.contentToSee = ContentToSee != "" ? ContentToSee : "";
XDocument doc = XDocument.Parse(ContentToSee);
XElement content = null;
foreach (XElement element in doc.Descendants("article"))
{
XElement refId = element.Element("refid");
XElement page = element.Element("page");
XElement title = element.Element("title");
XElement images = element.Element("images");
XElement image = null;
if (images != null)
{
foreach (XElement img in images.Descendants("image"))
{
image = img.Element("medium");
}
}
content = element.Element("content");
String detail = Regex.Replace(content.Value, #"<[^>]*>", String.Empty);
String cont = "";
if (detail.Length > 300)
{
cont = detail.Substring(0, 300) + ".....";
}
else
{
cont = detail;
}
Article art = new Article(title.Value, cont);
art.detail = detail;
art.page = Convert.ToInt32(page.Value);
art.refId = refId.Value;
if (image != null)
{
art.imageSrc = image.Value;
}
articles.Add(art);
}
this.databoundListBoxMag.ItemsSource = articles;
}
private void wb1_ScriptNotify(object sender, NotifyEventArgs e)
{
// The browser is zooming the text so we need to
// reduce the pixel size by the zoom level...
// Which is about 0.50
}
private void listBox1_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
Article art = databoundListBoxMag.SelectedItem as Article;
string id = art.refId;
MagazinePage page = new MagazinePage();
page._id = id;
page._content = art.detail;
page._title = art.name;
this.Content = page;
}
private void GestureListener_Flick(object sender, FlickGestureEventArgs e)
{
if (e.Angle > 90 && e.Angle < 270)
{
// MessageBox.Show("right");
GridLength len = new GridLength(50);
firstCol.Width = len;
flipBtn.Visibility = Visibility.Visible;
leftMenuControl.Visibility = Visibility.Collapsed;
}
else
{
// MessageBox.Show("left");
}
}
private void flip_click(object sender, RoutedEventArgs e)
{
GridLength len = new GridLength(200);
firstCol.Width = len;
flipBtn.Visibility = Visibility.Collapsed;
leftMenuControl.Visibility = Visibility.Visible;
}
private void SaveHTMLFile2()
{
string fileName = "TextFile2.htm";
IsolatedStorageFile isolatedStorageFile = IsolatedStorageFile.GetUserStoreForApplication();
if (isolatedStorageFile.FileExists(fileName) == true)
{
isolatedStorageFile.DeleteFile(fileName);
}
StreamResourceInfo streamResourceInfo = Application.GetResourceStream(new Uri(fileName, UriKind.Relative));
using (BinaryReader binaryReader = new BinaryReader(streamResourceInfo.Stream))
{
byte[] data = binaryReader.ReadBytes((int)streamResourceInfo.Stream.Length);
using (BinaryWriter bw = new BinaryWriter(isolatedStorageFile.CreateFile(fileName)))
{
bw.Write(data);
bw.Close();
}
}
}
}
public class BooleanToVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return System.Convert.ToBoolean(value) ? Visibility.Visible : Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return value.Equals(Visibility.Visible);
}
}
}
You need to bubble click events through UserControl. See my answer on this topic: Custom events in XAML on my UserControl

usage of observableCollection in longlistselector

I am using the _wordItems as the longlistselector's itemsource in order to dynamically delete items in longlistSelector
private ObservableCollection<Group<WordItem>> _wordItems = new ObservableCollection<Group<WordItem>>();
The Group class is defined as:
public class Group<T> : ObservableCollection<T>
{
public Group(string name, IEnumerable<T> items)
{
this.Key = name;
foreach (T item in items)
{
this.Add(item);
}
}
public override bool Equals(object obj)
{
Group<T> that = obj as Group<T>;
return (that != null) && (this.Key.Equals(that.Key));
}
public string Key
{
get;
set;
}
}
and the WordItem class is defined as:
[Table]
public class WordItem //:INotifyPropertyChanged,INotifyPropertyChanging
{
private int _wordItemId;
[Column(IsPrimaryKey = true, IsDbGenerated = true, DbType = "INT NOT NULL Identity", CanBeNull = false, AutoSync = AutoSync.OnInsert)]
public int WordItemId
{
get
{
return _wordItemId;
}
set
{
if (_wordItemId != value)
{
_wordItemId = value;
}
}
}
private string _word;
[Column(CanBeNull=false)]
public string Word
{
get
{
return _word;
}
set
{
if (_word != value)
{
_word = value;
}
}
}
private string _wordExplains;
[Column]
public string WordExplains
{
get
{
return _wordExplains;
}
set
{
if (_wordExplains != value)
{
_wordExplains = value;
}
}
}
}
when I use the code _wordItems[1].RemoveAt(1);, the _wordItems has been modified, and the longlistselector in the screen has also deleted certain item. But the problem is that when I call _wordItems[1].RemoveAt(1);, the longlistselector just deleted the _wordItems[1][0] item. When I call _wordItems[1].RemoveAt(0);, it just deleted the header of the second group and combined the items in _worditems[1] with the _wordItem[0].
The definition of longlistselector:
<toolkit:LongListSelector x:Name="WordsGroup" Background="Transparent"
Margin="12,0,12,73" ItemTemplate="{StaticResource WordItemTemplate}"
GroupHeaderTemplate="{StaticResource YoudaoGroupHeaderTemplate}"
GroupItemTemplate="{StaticResource YoudaoGroupItemTemplate}"
SelectionChanged="WordsGroup_SelectionChanged"
>
<toolkit:LongListSelector.GroupItemsPanel>
<ItemsPanelTemplate>
<toolkit:WrapPanel/>
</ItemsPanelTemplate>
</toolkit:LongListSelector.GroupItemsPanel>
</toolkit:LongListSelector>
The datatemplate is as:
<DataTemplate x:Key="WordItemTemplate">
<Border BorderBrush="Gray" BorderThickness="0,0,0,0" Margin="0,3,0,5">
<StackPanel >
<toolkit:ContextMenuService.ContextMenu>
<toolkit:ContextMenu Opened="ContextMenu_Opened" >
<toolkit:MenuItem Header="delete this word" Click="DelectWord_Click"/>
<toolkit:MenuItem Header="share this word" Click="SMSShare_Click"/>
</toolkit:ContextMenu>
</toolkit:ContextMenuService.ContextMenu>
<TextBlock Text="{Binding WordItemId}" Style="{StaticResource PhoneTextNormalStyle}" Visibility="Collapsed"/>
<TextBlock Text="{Binding Word}" Style="{StaticResource PhoneTextNormalStyle}" FontSize="25" Foreground="Black" FontWeight="Bold"/>
<TextBlock Text="{Binding WordExplains}" Style="{StaticResource PhoneTextNormalStyle}" Foreground="Black" TextWrapping="Wrap"/>
</StackPanel>
</Border>
</DataTemplate>
<DataTemplate x:Key="YoudaoGroupHeaderTemplate">
<Border Background="#1BA1E2" Margin="0">
<TextBlock Text="{Binding Key}" FontSize="30" Margin="12,0,0,0" Foreground="Black" />
</Border>
</DataTemplate>
<DataTemplate x:Key="YoudaoGroupItemTemplate" >
<Border Background="#1BA1E2" Width="99" Height="99" Margin="6">
<TextBlock Text="{Binding Key}" VerticalAlignment="Center" HorizontalAlignment="Center" FontSize="40" Foreground="{StaticResource PhoneForegroundBrush}"/>
</Border>
</DataTemplate>
Thx in advance.
ps. I am using the linq as
var wordBy4sLetter = from word in wordList
group word by word.Word.ToCharArray()[0].ToString() into s
orderby s.Key
select new Group<WordItem>(s.Key, s);
this._wordItems = wordBy4sLetter.ToObservableCollection();
this.WordsGroup.ItemsSource = this._wordItems;
I think you need another ObservableCollection. Take a look at the accepted answer for this question. Group Listbox for Windows Phone 7?
I have modified the code there and created new Add/Remove methods that will create a group if not there for an add, and remove the group if it's empty on a remove.

Resources