3

i want Storyboard automatically begin if something is changed :- E.g I have text block which can contain text "On" or "Off"

<TextBlock Name="BindedTextBlock" />

for checking text block text is on or off i created DispatcherTimer (Suggest me anyother way if which can check Text block text)

if textblock text is ON then NextStoryBoardIn.Begin(); should begin, if textblock text is OFF then PrevStoryBoardOut.Begin(); should begin. so i done this way:

DispatcherTimer timer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(0) };
timer.Tick += delegate (object sender, object e)
{                
    if(BindedTextBlock.Text.Equals("On"))
    {
        PrevStoryBoardIn.Begin();
    }
    else if(BindedTextBlock.Text.Equals("Off"))
    {
        PrevStoryBoardOut.Begin();
    }
};
timer.Start();

it works fine but storyboard triggers continuously, it should begin once. and if i write

if(BindedTextBlock.Text.Equals("On"))
{
    PrevStoryBoardIn.Begin();
}
else if(BindedTextBlock.Text.Equals("Off"))
{
    PrevStoryBoardOut.Begin();
}
timer.Stop();

then it will never check text block text again even if text block text if updated.

Update

if any one intrested in view Xaml codes for testing purpose , so i shared some sample of my xaml

<Page.Resources>
    <Storyboard x:Name="PrevStoryBoardIn">
        <DoubleAnimation Storyboard.TargetName="AppearStackPanel" Storyboard.TargetProperty="Opacity"
                         From="0" To="1" Duration="0:0:1"/>
    </Storyboard>

    <Storyboard x:Name="PrevStoryBoardOut">
        <DoubleAnimation Storyboard.TargetName="AppearStackPanel" Storyboard.TargetProperty="Opacity"
                         From="1" To="0" Duration="0:0:1"/>
    </Storyboard>
</Page.Resources>

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <TextBlock x:Name="DogWatcherTextBlock"
                   Height="50" Width="100" VerticalAlignment="Top"/>
    <StackPanel x:Name="AppearStackPanel" BorderThickness="1" BorderBrush="Crimson" Height="150" Width="150" Opacity="0" HorizontalAlignment="Center" VerticalAlignment="Center">
        <!-- My Items -->            
    </StackPanel>
</Grid>
Arpit Jain
  • 107
  • 11

3 Answers3

3

Using DispatcherTimer is not a good idea.

There is no TextChanged event for TextBlock. So we can create one and perform your task in it.

public MainPage()
{
    this.InitializeComponent();

    //Register PropertyChangedCallback
    MyTextBlock.RegisterPropertyChangedCallback(TextBlock.TextProperty, OnTextChanged);
}

private void OnTextChanged(DependencyObject sender, DependencyProperty dp)
{
    if(((TextBlock)sender).Text == "On")
        PrevStoryBoardIn.Begin();
    else if(((TextBlock)sender).Text == "Off")
        PrevStoryBoardOut.Begin();
}
Vijay Nirmal
  • 5,239
  • 4
  • 26
  • 59
3

If you are playing with animations, consider doing it in XAML itself. There are plenty of options, not mentioning Behaviors. Take a look at this sample:

<Page.Resources>
    <local:EqualParamConverter x:Key="EqualParamConverter"/>
</Page.Resources>

<StackPanel Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <VisualStateManager.VisualStateGroups>
        <VisualStateGroup x:Name="TextStates">
            <VisualState x:Name="Normal"/>
            <VisualState x:Name="OnState">
                <Storyboard>
                    <DoubleAnimation Duration="0:0:1" Storyboard.TargetName="myRectangle" Storyboard.TargetProperty="Opacity" To="1.0"/>
                </Storyboard>
                <VisualState.StateTriggers>
                    <StateTrigger IsActive="{Binding ElementName=myTextBlck, Path=Text, Converter={StaticResource EqualParamConverter}, ConverterParameter='On'}"/>
                </VisualState.StateTriggers>
            </VisualState>
            <VisualState x:Name="OffState">
                <Storyboard>
                    <DoubleAnimation Duration="0:0:1" Storyboard.TargetName="myRectangle" Storyboard.TargetProperty="Opacity" To="0.5"/>
                </Storyboard>
                <VisualState.StateTriggers>
                    <StateTrigger IsActive="{Binding ElementName=myTextBlck, Path=Text, Converter={StaticResource EqualParamConverter}, ConverterParameter='Off'}"/>
                </VisualState.StateTriggers>
            </VisualState>
        </VisualStateGroup>
    </VisualStateManager.VisualStateGroups>
    <TextBlock x:Name="myTextBlck" Text="Something"/>
    <Rectangle x:Name="myRectangle" Width="300" Height="100" Fill="Green" Opacity="0.75"/>
    <ToggleButton Content="Switcher" Click="ToggleButton_Click"/>
</StackPanel>

Code behind:

public class EqualParamConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, string language) => value.ToString() == parameter.ToString();
    public object ConvertBack(object value, Type targetType, object parameter, string language) => throw new NotImplementedException();
}

public sealed partial class MainPage : Page
{
    public MainPage() { this.InitializeComponent(); }

    private void ToggleButton_Click(object sender, RoutedEventArgs e) => myTextBlck.Text = (bool)(sender as ToggleButton).IsChecked ? "On" : "Off";
}
Romasz
  • 29,662
  • 13
  • 79
  • 154
  • okay but i have a text block which will get text automatically either "On" or "Off" so app should aware of this text so story board begin accordingly as dispatcher time aware of this activity but it triggers storyboard continuously – Arpit Jain Oct 22 '17 at 15:27
  • in your example you are done this through toggle switch which can be easily done but i want it automatically trigger ,and i am ready to use either textblock or textbox which will help me to do this – Arpit Jain Oct 22 '17 at 15:31
  • @ArpitJain ToggleButton has nothing to do here, it only changes the value of TextBlock, which technically should be done via Binding. This is only short sample which shows how it can be done different way. Details of course depend on your needs. – Romasz Oct 22 '17 at 15:36
  • okay okay let me check, but app will aware of this change not from that switch only from that textblock or textbox. okay wait checking – Arpit Jain Oct 22 '17 at 15:40
  • @ArpitJain Everything depends on implementation. – Romasz Oct 22 '17 at 19:16
2

You initialize your timer with TimeSpan.FromSeconds(0). So your Tick-callback will be called permanently.

One possible solution would be to have a viewmodel

First the ViewModel itself:

public class ViewModel : INotifyPropertyChanged
    {
    private bool _someVariable;

    public bool SomeVariable
    {
        get { return _someVariable; }
        set
        {
            //// simplified code
            _someVariable = value;
            PropertyChanged(this, new PropertyChangedEventArgs(nameof(SomeVariable)));
            SomeVariableChanged(this, EventArgs.Empty);
        }
    }

    public event EventHandler SomeVariableChanged = delegate { };

    /// <summary>
    /// Needed for updating the binding
    /// </summary>
    public event PropertyChangedEventHandler PropertyChanged = delegate { };
}

And here the logic part. As you can see, you don't need a timer, which checks every x seconds if something changes.

var viewModel = new ViewModel();
_textBlock.DataContext = viewModel; //// Here you bind your viewmodel to the TextBlock
viewModel.SomeVariableChanged += (s, e) =>
{
     if(viewModel.SomeVariable == true)
     {
         PrevStoryBoardIn.Begin();
     }
     else
     {
         PrevStoryBoardOut.Begin();
     }
}

Now you can define a trigger or a converter to display "ON" or "OFF" depending on the value of your ViewModel.

If you want to read some more:

MVVC-Pattern from MSDN

Data-Bindings in UWP

Link
  • 1,307
  • 1
  • 11
  • 23
  • Although this solves the problem, it does clutter the viewmodel, imagine there're lots of properties to track. Doesn't play well with separation of concerns. – Funk Oct 22 '17 at 07:51
  • 2
    This is a simplified example. Normally you have a presenter and the View just executes the action. – Link Oct 22 '17 at 08:02