VisualStateManager.GoToState useTransitions Ignored in custom control UWP - animation

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);
}
}

Related

Xamarin: Visual State Manager and custom properties

I am trying to set a custom property on a custom control using the Visual State Manager but I'm not having any luck so far. My custom control is just a label with an additional bindable property on it.
public class SelectableLabel : Label
{
public static readonly BindableProperty IsSelectedProperty = BindableProperty.Create("IsSelected", typeof(bool), typeof(SelectableLabel), false);
public bool IsSelected
{
get { return (bool)GetValue(IsSelectedProperty); }
set
{
Console.WriteLine($"MDO: {Text}.IsSelected_set={value}");
SetValue(IsSelectedProperty, value);
}
}
I use this control inside a CollectionView to toggle the IsSelected property when the control enters the Selected visual state.
<CollectionView
x:Name="cv"
ItemsSource="{Binding Names}"
SelectionMode="Multiple"
SelectedItems="{Binding SelectedNames, Mode=TwoWay}"
VerticalOptions="Fill">
<CollectionView.ItemTemplate>
<DataTemplate>
<local:SelectableLabel
x:Name="lblName"
Text="{Binding First}">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup
x:Name="CommonStates">
<VisualState
x:Name="Normal">
<VisualState.Setters>
<Setter
Property="IsSelected"
Value="False" />
</VisualState.Setters>
</VisualState>
<VisualState
x:Name="Selected">
<VisualState.Setters>
<Setter
Property="IsSelected"
Value="True" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</local:SelectableLabel>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
When I run this on an iOS simulator, I'm not seeing the setter being fired when the visual state changes to Selected. If I change the property in the setter to BackgroundColor or Text, I'm seeing the expected behavior. The problem seems specific to the custom property. I looked at the documentation for the Setter.Property and it states that the Setter can be applied to a BindableProperty which IsSelected is. Am I doing something wrong or does the VSM not support this functionality?
Edit: The CollectionView part of this example is irrelevant. The same issue happens with this code.
public class SelectableEntry : Entry
{
public static readonly BindableProperty IsSelectedProperty = BindableProperty.Create("IsSelected", typeof(bool), typeof(SelectableEntry), false);
public bool IsSelected
{
get { return (bool)GetValue(IsSelectedProperty); }
set
{
Console.WriteLine($"MDO: {Text}.IsSelected_set={value}");
var color = value ? Color.LightBlue : Color.LightPink;
SetValue(IsSelectedProperty, value);
SetValue(BackgroundColorProperty, color);
}
}
}
Here is the corresponding XAML. The background color changes when the first custom Entry control receives focus while the second does not. I also don't see my WriteLine statement in the console.
<local:SelectableEntry Text="First">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup
x:Name="CommonStates">
<VisualState
x:Name="Normal">
<VisualState.Setters>
<Setter
Property="BackgroundColor"
Value="LightBlue" />
</VisualState.Setters>
</VisualState>
<VisualState
x:Name="Focused">
<VisualState.Setters>
<Setter
Property="BackgroundColor"
Value="LightPink" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</local:SelectableEntry>
<local:SelectableEntry Text="Second">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup
x:Name="CommonStates">
<VisualState
x:Name="Normal">
<VisualState.Setters>
<Setter
Property="IsSelected"
Value="False" />
</VisualState.Setters>
</VisualState>
<VisualState
x:Name="Focused">
<VisualState.Setters>
<Setter
Property="IsSelected"
Value="True" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</local:SelectableEntry>
I have tried with Bindable Property to check whether property be invoked in VisualStateManager . That's regrettable, it can not be invoked even in propertyChanged method . I think maybe bindable property can not work in VisualStateManager.
Custom Entry Code as follow :
public class SelectableEntry : Entry
{
public static readonly BindableProperty IsSelectedProperty = BindableProperty.Create("IsSelected", typeof(bool), typeof(SelectableEntry), false ,propertyChanged:changedMethod);
private static void changedMethod(BindableObject bindable, object oldValue, object newValue)
{
Console.WriteLine($"MDO: {oldValue}.IsSelected_set={newValue}");
}
public bool IsSelected
{
get { return (bool)GetValue(IsSelectedProperty); }
set
{
Console.WriteLine($"MDO: {Text}.IsSelected_set={value}");
var color = value ? Color.LightBlue : Color.LightPink;
SetValue(IsSelectedProperty, value);
SetValue(BackgroundColorProperty, color);
}
}
}
Solution:
However , there is a Attached Properties that can be used in Style.Setters. Then you can also have a try with it in VisualState.Setters .It also will work .
Attached property class Code as follow :
public class SelectableEntryStyle
{
public static readonly BindableProperty IsSelectedProperty = BindableProperty.CreateAttached("IsSelected", typeof(bool), typeof(SelectableEntryStyle), false,propertyChanged:onChangedMethod);
private static void onChangedMethod(BindableObject bindable, object oldValue, object newValue)
{
Console.WriteLine($"MDO:IsSelected_set={newValue}");
var color = (bool)newValue ? Color.LightBlue : Color.LightPink;
var entry = bindable as Entry;
entry.SetValue(Entry.BackgroundColorProperty, color);
}
public static bool GetIsSelected(BindableObject view)
{
return (bool)view.GetValue(IsSelectedProperty);
}
public static void SetIsSelected(BindableObject view, bool value)
{
view.SetValue(IsSelectedProperty, value);
}
}
The code of Xaml as follow :
<local:SelectableEntry FontSize="18" Placeholder="Bindable Property">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal">
<VisualState.Setters>
<Setter Property="IsSelected"
Value="False" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Property="IsSelected"
Value="True" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</local:SelectableEntry>
<Entry Placeholder="Attached Property">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal">
<VisualState.Setters>
<Setter Property="local:SelectableEntryStyle.IsSelected"
Value="False" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Focused">
<VisualState.Setters>
<Setter Property="local:SelectableEntryStyle.IsSelected"
Value="True" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Entry>
Then console can print log when Entry is Normal or Focused .
02-18 14:26:27.360 I/mono-stdout(26014): MDO:IsSelected_set=True
02-18 14:26:28.675 I/mono-stdout(26014): MDO:IsSelected_set=False
The effects :

How to use VisualStateManager with content Dialogue control in uwp

Is there any way to use visualStateManager with content Dialogue control in uwp application.
Put all your popUp controls in the control as follow:
`<Grid Background="White">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup>
<VisualState>
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="1000" />
</VisualState.StateTriggers>
<VisualState.Setters>
</VisualState.Setters>
</VisualState>
<VisualState>
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="750" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="BlueRect.Visibility" Value="Visible" />
<Setter Target="RedRect.Visibility" Value="Collapsed" />
</VisualState.Setters>
</VisualState>
<VisualState>
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="500" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="BlueRect.Visibility" Value="Collapsed" />
<Setter Target="RedRect.Visibility" Value="Visible" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<StackPanel>
<Rectangle x:Name="BlueRect" Width="50" Height="50" Fill="Blue" />
<Rectangle x:Name="RedRect" Width="50" Height="50" Fill="Red" />
<Button Content="Change Style" Width="500" Height="30" HorizontalAlignment="Center" VerticalAlignment="Bottom" Click="Button_Click" />
</StackPanel>
</Grid>`
Transfer event of user controls to contentdialog if there is any:
`public sealed partial class MyUserControl1 : UserControl
{
public delegate void MyEventHandler(object source, EventArgs e);
public static event MyEventHandler OnNavigateParentReady;
public MyUserControl1()
{
this.InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
OnNavigateParentReady(sender,null);
}
}`
Create contentDialog control and use the created user control there as follow:
` <Grid >
<local:MyUserControl1 />
</Grid>`
Now Handle the transferred events of your user control on contentDialog code behind as follow:
`public sealed partial class ContentDialog1 : ContentDialog
{
public ContentDialog1()
{
this.InitializeComponent();
MyUserControl1.OnNavigateParentReady += test;
}
private void test(object source, EventArgs e)
{
Button bt = (Button)source;
if (bt.IsEnabled == true)
{
this.Hide();
}
}
}`
Now simply make a call to your popUp(contentDialog) from where you want to.I made a call on the button click event as shown:
` ContentDialog1 popup = new ContentDialog1() { };
public uc_test()
{
this.InitializeComponent();
}
private async void Button_Click_1(object sender, RoutedEventArgs e)
{
await popup.ShowAsync();
}`
Works fine for me and helped me to create a responsive popUp as it applies all the triggers that you applied on your user control when the main window shrink.
Thanks.

Animate a textblock from a point to another

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>

Set image for disabled button in windows phone 8

I'm using the below ControlTemplate for image button in my application.
Control Template in App.xaml is below.
<!--Below is the style for all ImageButtons in this project -->
<Style x:Key="ButtonStyleIB" TargetType="Button">
<Setter Property="Background" Value="Transparent"/>
<Setter Property="BorderBrush" Value="{StaticResource PhoneForegroundBrush}"/>
<Setter Property="Foreground" Value="{StaticResource PhoneForegroundBrush}"/>
<Setter Property="BorderThickness" Value="{StaticResource PhoneBorderThickness}"/>
<Setter Property="FontFamily" Value="{StaticResource PhoneFontFamilySemiBold}"/>
<Setter Property="FontSize" Value="{StaticResource PhoneFontSizeMediumLarge}"/>
<!--<Setter Property="Padding" Value="10,3,10,5"/>-->
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Grid x:Name="grid" Background="Transparent">
<Grid.Projection>
<PlaneProjection/>
</Grid.Projection>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal"/>
<VisualState x:Name="MouseOver"/>
<VisualState x:Name="Pressed">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground" Storyboard.TargetName="ContentContainer">
<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneBackgroundBrush}"/>
</ObjectAnimationUsingKeyFrames>
<DoubleAnimation Duration="0" To="-25" Storyboard.TargetProperty="(UIElement.Projection).(PlaneProjection.RotationY)" Storyboard.TargetName="grid" />
<!--d:IsOptimized="True"-->
<DoubleAnimation Duration="0" To="0" Storyboard.TargetProperty="(UIElement.Projection).(PlaneProjection.CenterOfRotationX)" Storyboard.TargetName="grid" />
<!--d:IsOptimized="True"-->
</Storyboard>
</VisualState>
<VisualState x:Name="Disabled">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground" Storyboard.TargetName="ContentContainer">
<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneDisabledBrush}"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<ContentControl x:Name="ContentContainer" ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" Foreground="{TemplateBinding Foreground}" HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" Padding="{TemplateBinding Padding}" VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}" Margin="0" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Now in my page i'm creating the button as below.
<Button x:Name="saveButton" Style ="{StaticResource ButtonStyleIB}" VerticalAlignment="Center" Click="save_button_clicked">
<Image Source="/STCDirectory;component/Images/save.png" Stretch="Fill" />
</Button>
Upto this it is fine. So when i run the application the button with image is displaying.
And it is working fine.
Now based on some internal condition i want to disable the image button.
So for disable the button i'm using the below code.
saveButton.IsEnabled = false;
So then image button is not clickable according to the above step.
But i want to change the image also whenever the button is disabled.
How could i achive this.
Dont give direct uri of the image in the buttons
you can bind it with a string property and on button click you can change the that string to another uri then it will change the image of the button to new image.
i hope this might help ...
you can do it using imagesource binding ..first define your button like this.
<Button Grid.Row="1" x:Name="saveButton" Style ="{StaticResource ButtonStyleIB}" VerticalAlignment="Center" Click="saveButton_Click_1" Width="300" Height="50">
<Image Source="{Binding ImageSource}" Stretch="Fill" />
</Button>
and in your page.xaml.cs create property ImageSource like this.
public partial class MainPage : PhoneApplicationPage , INotifyPropertyChanged
{
// Constructor
public MainPage()
{
InitializeComponent();
ImageSource = "/Assets/1.jpg";
this.DataContext = this;
}
private string _ImageSource;
public string ImageSource
{
get
{
return _ImageSource;
}
set
{
_ImageSource = value;
FirePropertyChanged("ImageSource");
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void FirePropertyChanged(string propertyName)
{
if (this.PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
private void saveButton_Click_1(object sender, RoutedEventArgs e)
{
ImageSource = "/Assets/2.jpg";
saveButton.IsEnabled = false;
}
}
here 1.jpg and 2.jpg are images i have toggled.

wp7: how to create image button and bind template to ImageSource dependency property

I am trying to create a silverlight imagebutton control. the xaml and code-behind will follow, but my problem is that I get an 'unspecified error' when i try a TemplateBinding to the image's source property. I'm hoping that someone can help me preserve my last shreds of sanity and last few scraps of hair on my head.
XAML:
<Grid x:Name="LayoutRoot">
<Button x:Name="btn" Click="Cancel_Click" Margin="0,0,10,10"
Width="{Binding ImageWidth}" Height="{Binding ImageHeight}" >
<Button.Template>
<ControlTemplate TargetType="Button">
<Grid Background="Transparent">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal"/>
<VisualState x:Name="MouseOver"/>
<VisualState x:Name="Pressed">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background"
Storyboard.TargetName="ButtonBackground">
<DiscreteObjectKeyFrame KeyTime="0"
Value="{StaticResource PhoneForegroundBrush}"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="BorderBrush"
Storyboard.TargetName="ButtonBackground">
<DiscreteObjectKeyFrame KeyTime="0"
Value="{StaticResource PhoneForegroundBrush}"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Disabled">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="BorderBrush"
Storyboard.TargetName="ButtonBackground">
<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneDisabledBrush}"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background"
Storyboard.TargetName="ButtonBackground">
<DiscreteObjectKeyFrame KeyTime="0" Value="Transparent"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Border x:Name="ButtonBackground"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Background="{TemplateBinding Background}"
CornerRadius="33"
Margin="{StaticResource PhoneTouchTargetOverhang}">
<Image x:Name="image" Source="{TemplateBinding IconSource}"
Width="{TemplateBinding Width}"
Height="{TemplateBinding Height}" />
</Border>
</Grid>
</ControlTemplate>
</Button.Template>
</Button>
</Grid>
</UserControl>
Code Behind:
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.Shapes;
namespace sltest.controls
{
public partial class ImageButtonControl : UserControl
{
public ImageButtonControl()
{
InitializeComponent();
}
private void Cancel_Click(object sender, RoutedEventArgs e)
{
}
public double ImageWidth { get; set; }
public double ImageHeight { get; set; }
public static readonly DependencyProperty IconSourceProperty =
DependencyProperty.Register("IconSource", typeof(ImageSource), typeof(ImageButtonControl), null);
public ImageSource IconSource
{
get { return base.GetValue(IconSourceProperty) as ImageSource; }
set { base.SetValue(IconSourceProperty, value); }
}
}
}
I'm using the following implementation which contains additional functionality to display text, but you can exclude it:
ImageTextButtonControl class
using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
namespace SecureBox.Controls
{
public class ImageTextButtonControl: Button
{
///
///
///
public static readonly DependencyProperty ImageHeightProperty =
DependencyProperty.Register("ImageHeight", typeof(double), typeof(ImageTextButtonControl), null);
public double ImageHeight
{
get { return (double)GetValue(ImageHeightProperty); }
set { SetValue(ImageHeightProperty, value); }
}
///
///
///
public static readonly DependencyProperty ImageWidthProperty =
DependencyProperty.Register("ImageWidth", typeof(double), typeof(ImageTextButtonControl), null);
public double ImageWidth
{
get { return (double)GetValue(ImageWidthProperty); }
set { SetValue(ImageWidthProperty, value); }
}
///
///
///
public static readonly DependencyProperty ImageSourceProperty =
DependencyProperty.Register("ImageSource", typeof(BitmapImage), typeof(ImageTextButtonControl), null);
public BitmapImage ImageSource
{
get { return (BitmapImage)GetValue(ImageSourceProperty); }
set { SetValue(ImageSourceProperty, value); }
}
///
///
///
public static readonly DependencyProperty TextMarginProperty =
DependencyProperty.Register("TextMargin", typeof(Thickness), typeof(ImageTextButtonControl), null);
public Thickness TextMargin
{
get { return (Thickness)GetValue(TextMarginProperty); }
set { SetValue(TextMarginProperty, value); }
}
///
///
///
public static readonly DependencyProperty TextProperty =
DependencyProperty.Register("Text", typeof(string), typeof(ImageTextButtonControl), null);
public string Text
{
get { return (string)GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}
public ImageTextButtonControl()
{
DefaultStyleKey = typeof(ImageTextButtonControl);
}
}
}
Themes\generic.xaml contains:
<Style TargetType="local:ImageTextButtonControl">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:ImageTextButtonControl">
<Grid Margin="{StaticResource PhoneTouchTargetOverhang}" toolkit:TiltEffect.IsTiltEnabled="True">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Border BorderBrush="White" BorderThickness="0" Opacity="0.9" >
<Image Grid.Column="0" Width="{TemplateBinding ImageWidth}" Height="{TemplateBinding ImageHeight}" Source="{TemplateBinding ImageSource}" VerticalAlignment="Top" />
</Border>
<TextBlock Grid.Column="1" Margin="{TemplateBinding TextMargin}" Text="{TemplateBinding Text}" HorizontalAlignment="Left" VerticalAlignment="Center" FontSize="{TemplateBinding FontSize}" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Example of usage:
<local:ImageTextButtonControl ImageSource="/ImagePath/YourImage.png" Text="YourText" FontSize="50" ImageHeight="128" ImageWidth="128" TextMargin="20,0,0,0">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<Command:EventToCommand
Command="{Binding GoTo}" CommandParameterValue="YourCommandParameter" />
</i:EventTrigger>
</i:Interaction.Triggers>
Note:
I've inherited the control from Button control. This allows me to
subscribe to Click event using MVVMLight framework
Xaml code is located in special place: Themes\generic.xaml file
I guess you can try to check whether these notes can fix your the issue in your code or use my one instead.

Resources