WPF: How to prevent data triggered animation at program start? - wpf

I am using a datatrigger to start an animation whenever a property TargetValue in my viewmodel is set to a specific value Value1.
But I don't want this animation to happen during program startup. What is the best way to prevent the animation to run at program start?
Part of the view model:
public enum TargetValue
{
Value1,
Value2,
}
public class MainWindowViewModel : INotifyPropertyChanged, IDisposable
{
public TargetValue _targetValue = TargetValue.Value1;
public TargetValue TargetValue
{
get => _targetValue;
set => SetProperty(ref _targetValue, value);
}
Part of the xaml:
<Border Background="Green" >
<Border.Style>
<Style TargetType="{x:Type Border}">
<Style.Triggers>
<DataTrigger Binding="{Binding TargetValue}" Value="Value1">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetProperty="(UIElement.Opacity)">
<LinearDoubleKeyFrame KeyTime="00:00:0" Value="0.5"/>
<LinearDoubleKeyFrame KeyTime="00:00:3" Value="1"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
</DataTrigger>
</Style.Triggers>
</Style>
</Border.Style>
</Border>
Part of the MainWindow.cs:
public partial class MainWindow : Window
{
MainWindowViewModel myViewModel = new MainWindowViewModel();
public MainWindow()
{
InitializeComponent();
DataContext = myViewModel;
}

Add another property to your viewmodel. For example a bool DoAnimation.
Make that false by default.
Use this to drive your animation instead of TargetValue and compare it to a value of true.
In the setter of Value1 you can call a method encapsulating your logic. Which is presumably to check if the value changes to "Value1" and to set DoAnimation to True when that happens.
When you translate your data from your model into the viewmodel, set DoAnimation to false. Do this before you present it to the ui.
You could just put that logic in the constructor.
myViewModel.DoAnimation=false;
DataContext = myViewModel;

Related

WPF Change button style at runtime

I am trying to turn on or off a style at runtime using a Toggle Switch.
I have added the style to a resource dictionary but im not sure how to make some C# code to load or unload the resource. All of my buttons are using a dynamic resource of "PassiveGlowButton" and when i use a toggle switch i would like it to remove the "PassiveGlowButton" so its using the style of "GlowButton"
The code behind "GlowButton" This is the code i want to apply when the toggle is on. This is in App.Xaml under Application.resources, resourceDictionary:
<ResourceDictionary>
<Style x:Key="GlowButton" TargetType="{x:Type Button}"
BasedOn="{StaticResource AccentedSquareButtonStyle}">
<Setter Property="BorderThickness" Value="0" />
<Setter Property="Effect">
<Setter.Value>
<DropShadowEffect ShadowDepth="5" Color="WhiteSmoke" BlurRadius="18"/>
</Setter.Value>
</Setter>
<Style.Triggers>
<EventTrigger RoutedEvent="Button.Loaded">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetProperty="Effect.ShadowDepth"
From="3.0" To="0.0" Duration="0:0:1"
AutoReverse="True" RepeatBehavior="Forever"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<!-- Mouse over glow -->
<Trigger Property="IsMouseOver" Value="True">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetProperty="Effect.BlurRadius"
From="45.0" To="17.0" Duration="0:0:1"
AutoReverse="True" RepeatBehavior="Forever"/>
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetProperty="Effect.BlurRadius"
From="15.0" To="15.0" Duration="0:0:1"
AutoReverse="True" RepeatBehavior="Forever"/>
</Storyboard>
</BeginStoryboard>
</Trigger.ExitActions>
</Trigger>
</Style.Triggers>
</Style>
</ResourceDictionary>
Update
I have been able to set the style using a button but it will only apply to a button called Testbttn. Is there a way to change it to apply to Button.Style? If i use this method it also looses the storyboard of the button for some reason
Style style = this.FindResource("PassiveGlowButton") as Style;
TestBttn.Style = style;
Update 2: The solution was to create 3 styles, one the button uses from load and then 2 others, one with a blank button and one with the style i wanted.
I have attached the code i used to swap between the styles.
private void ButtonStyle_Checked(object sender, RoutedEventArgs e)
{
Application.Current.Resources["PassiveGlowButton"] = Application.Current.Resources["PassiveGlowButtonOn"];
}
private void ButtonStyle_UnChecked(object sender, RoutedEventArgs e)
{
Application.Current.Resources["PassiveGlowButton"] = Application.Current.Resources["PassiveGlowButtonOff"];
}
There are several ways of doing this.
What you're asking may be best redesigned to use VisualStateManager.
Another option is redesigning the styles into a StyleViewModel. (I recommend using a enum and typing your styles so that the VM can live / reference separate from the styles themselves) If you do this properly you can change the style type and the styles binding will update.
Finally you can use DynamicResource as the style and make a default style resource that's set else where. Styles, when used as a resource, can have the same key in separate dictionaries. The names overlapped so the last one in (or closest to the control requesting it in the hierarchy) will be the one to get used. You can re-arrange the style order or add / remove them but the controls won't update until the next time they are loaded.
Each is a little tricky to implement and although I like VisualStateManager I'm a fan of the binding fix (option 2) myself. There's a difference between the two; so I don't want this to confuse you or start a debate. I'm just illustrating options.
Here's a quick example of binding styles if you do prefer to go that route which will fix your problem IMO.
Example:
Styles
<Application x:Class="Question_Answer_WPF_App.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="MainWindow.xaml">
<Application.Resources>
<Style x:Key="StyleA"
TargetType="Button">
<Setter Property="Background"
Value="Green" />
<Setter Property="Height"
Value="40" />
<Setter Property="Margin"
Value="4" />
</Style>
<Style x:Key="StyleB"
TargetType="Button">
<Setter Property="Background"
Value="Blue" />
<Setter Property="Height"
Value="30" />
</Style>
</Application.Resources>
</Application>
Enum
namespace Question_Answer_WPF_App.ViewModels
{
public enum Styles
{
StyleA,
StyleB
}
}
ViewModel
using System.Windows.Input;
namespace Question_Answer_WPF_App.ViewModels
{
public class StylesViewModel : NotifyModel
{
private Styles selectedStyle;
public StylesViewModel()
{
SelectStyleCommand = new RelayCommand(SelectStyle);
}
public Styles SelectedStyle
{
get { return selectedStyle; }
set
{
selectedStyle = value;
Notify();
}
}
public ICommand SelectStyleCommand { get; }
private void SelectStyle(object obj)
{
if (obj is Styles style) SelectedStyle = style;
}
}
}
Converter
using Question_Answer_WPF_App.ViewModels;
using System;
using System.Globalization;
using System.Windows;
using System.Windows.Data;
namespace Question_Answer_WPF_App.Views
{
public class StyleTypeConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var result = Application.Current.Resources["StyleA"];
if (value is Styles style)
{
switch (style)
{
case Styles.StyleB:
result = Application.Current.Resources["StyleB"];
break;
case Styles.StyleA:
default:
result = Application.Current.Resources["StyleA"];
break;
}
}
return result;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
=> DependencyProperty.UnsetValue;
}
}
View
<UserControl x:Class="Question_Answer_WPF_App.Views.StylesTestView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ViewModels="clr-namespace:Question_Answer_WPF_App.ViewModels"
xmlns:local="clr-namespace:Question_Answer_WPF_App.Views">
<UserControl.Resources>
<ViewModels:StylesViewModel x:Key="StylesViewModel" />
<local:StyleTypeConverter x:Key="StyleTypeConverter" />
</UserControl.Resources>
<StackPanel>
<Button Style="{Binding SelectedStyle, Source={StaticResource StylesViewModel}, Converter={StaticResource StyleTypeConverter}}"
Command="{Binding SelectStyleCommand, Source={StaticResource StylesViewModel}}"
CommandParameter="{x:Static ViewModels:Styles.StyleA}"
Content="Select Style A" />
<Button Style="{Binding SelectedStyle, Source={StaticResource StylesViewModel}, Converter={StaticResource StyleTypeConverter}}"
Command="{Binding SelectStyleCommand, Source={StaticResource StylesViewModel}}"
CommandParameter="{x:Static ViewModels:Styles.StyleB}"
Content="Select Style B" />
</StackPanel>
</UserControl>
Results

DataContext binding in Page's Resources

I have a page that gets a datacontext objet in the behind code.
I would like to set an empty value to the TextList[11] when the Trigger variable loses the 1 value. The Trigger "int" and the TextList "ObservableCollection" are booth situated in the Datacontext object. The TextList is initialized 20pcs element before set the page datacontext. I have to solve it in wpf code, code behind excluded. My English is pretty poor, sorry!
<Page x:Class="LayerTemplates.Templates.example"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:LayerTemplates.Templates"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"
Title=""
xmlns:System="clr-namespace:System;assembly=mscorlib">
<Page.Resources>
<DataTemplate x:Key="myDataTemplate" DataType="{x:Type System:String}">
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding Path=Trigger}" Value="1">
<DataTrigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<StringAnimationUsingKeyFrames Storyboard.TargetName="Page.DataContext" Storyboard.TargetProperty="TextList[11]" Duration="1">
<DiscreteStringKeyFrame KeyTime="0" Value=""></DiscreteStringKeyFrame>
</StringAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</DataTrigger.ExitActions>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</Page.Resources>
<Grid>
...
</Grid>
If you just want to hide a text box or label try to use style triggers instead. As you are setting the value of a string to an empty value I think you might be able to use Visibility="Hidden".
In this example I hide the the label by default but whenever the MyIntProperty becomes 1 I change visibility to Visible.
My xaml code looks like this:
<Window x:Class="TestBinding.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid>
<Label Content="{Binding MyTextProperty}">
<Label.Style>
<Style TargetType="Label">
<Setter Property="Visibility" Value="Hidden"/>
<Style.Triggers>
<DataTrigger Binding="{Binding MyIntProperty}" Value="1">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Label.Style>
</Label>
</Grid>
Data binding class and codebehind looks like this:
public class MyViewModel
{
public int MyIntProperty { get; set; } = 1;
public string MyTextProperty { get; set; } = "This is my text";
}
public partial class MainWindow : Window
{
MyViewModel model;
public MainWindow()
{
InitializeComponent();
model = new MyViewModel();
this.DataContext = model;
}
}
Note that in order to get the visibility to update automatically you have let the view model class implement INotifyPropertyChanged for the MyIntProperty.

WPF MVVM - Trigger storyboard on property change only happens once

In my view model, I have a timer that needs to make a border background blink every 5 minutes.
The border in my view:
<Border Name="btnBorder" Grid.Row="0" Grid.Column="0" Opacity="1" CornerRadius="10,10,0,0">
<Border.Style>
<Style TargetType="Border">
<Style.Setters>
<Setter Property="Background" Value="#e2e2e2"></Setter>
</Style.Setters>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=ViewEventTrigger}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<ColorAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)">
<EasingColorKeyFrame KeyTime="00:00:00.000" Value="#e2e2e2"/>
<EasingColorKeyFrame KeyTime="00:00:00.500" Value="#163f6b"/>
<EasingColorKeyFrame KeyTime="00:00:01.000" Value="#e2e2e2"/>
<EasingColorKeyFrame KeyTime="00:00:01.500" Value="#163f6b"/>
<EasingColorKeyFrame KeyTime="00:00:02.000" Value="#e2e2e2"/>
<EasingColorKeyFrame KeyTime="00:00:02.500" Value="#163f6b"/>
<EasingColorKeyFrame KeyTime="00:00:03.000" Value="#e2e2e2"/>
<EasingColorKeyFrame KeyTime="00:00:03.500" Value="#163f6b"/>
<EasingColorKeyFrame KeyTime="00:00:04.000" Value="#e2e2e2"/>
</ColorAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
</DataTrigger>
</Style.Triggers>
</Style>
</Border.Style>
</Border>
Property from view model:
private string _viewEventTrigger = "";
public string ViewEventTrigger
{
get => _viewEventTrigger ?? (_viewEventTrigger = "");
private set
{
if (_viewEventTrigger == value)
return;
_viewEventTrigger = value;
OnPropertyChanged();
}
}
And the method that needs to trigger the... well, trigger:
private void ShowInfocenterIfAnyItinirary(object sender, ElapsedEventArgs e)
{
ViewEventTrigger = "";
ViewEventTrigger = "True";
}
I testet the Storyboard by triggering it with MouseEnter. But I am not able to make it work by binding it to my property.
EDIT:
I set the datacontext like this:
d:DataContext="{d:DesignInstance local:ItineraryViewModel}"
Also, I have lots og other databindings that work fine, like data to show and commands for buttons. But I just can't make the trigger execute the storybord.
The method ShowInfocenterIfAnyItinirary() is executed by a timer, started in the viewmodel.
Timer code:
private readonly Timer _timer = new Timer();
public ItineraryViewModel()
{
_timer.Interval = 5000;
_timer.Elapsed += ShowInfocenterIfAnyItinirary;
_timer.Start();
}
EDIT 2:
I have delayed when the animation should start when the program runs. I have discovered that the animation DOES run, but only once. I did not see it before, because the window starts minimized.
Why does it only run once, no matter how many times the trigger event happens?
This only sets the design time data context:
d:DataContext="{d:DesignInstance local:ItineraryViewModel}"
This won't have any effect when you actualy run the application.
You should set the DataContext property of the view to an instance of your view model:
<Window ...>
<Window.DataContext>
<local:ItineraryViewModel />
</Window.DataContext>
I ended up solving the problem like this:
private void ShowInfocenterIfAnyItinirary(object sender, ElapsedEventArgs e)
{
if (Items.Count <= 0) return;
GlobalEvents.TriggerShowMainWindowEvent();
ViewEventTrigger = "True";
Task.Run(async () =>
{
Thread.Sleep(4000);
ViewEventTrigger = "False";
});
}
This stops the animation, instead of leaving it paused at the end point.

Updating a wpf style having infinite possible conditions

I have a DataGrid with rows representing a host I'm doing pings to and a column called Lost which represents lost ICMP packets which over time increases in value. I have the whole INotifyPropertyChanged thing down and I'm seeing value increase. What I want to do is write a Style that'll change a row's background color from white to dark red progressively relative to the Lost column's value.
I would like, if it were possible, to write a Trigger or DataTrigger with a setter value set to a ValueConverter which would calculate the color needed, but so far I've been unsuccessful in writing a style that will update every time a Lost cell's value changes. I only see a difference in color when I load a new data context and switch back (just for testing).
Here's what I've tried:
<Style x:Key="DownStyle" TargetType="{x:Type DataGridRow}">
<Setter Property="Background" Value="{Binding Converter={StaticResource BackgroundConverter}}" />
</Style>
I can't see this working with a DataTrigger since you have to specify a value anyways and the values are infinite (or Int32.MaxValue I guess), really. Although I also tried specifying a ValueConverter for the value property and that didn't work either.
Btw, I want to try to avoid code-behind if possible.
Edit:
Rick: I had tried doing something like:
<Style x:Key="DownStyle" TargetType="{x:Type DataGridRow}">
<Style.Triggers>
<DataTrigger Binding="{Binding Converter={StaticResource LostColumnValueConverter}}" Value="Somenumber">
<Setter Property="Background" Value="{Binding Converter={StaticResource BackgroundConverter}}" />
</DataTrigger>
</Style.Triggers>
</Style>
I think I understand the need to have the Trigger actually bind to something that's going to be changing (in this case I feel I'm forced to also use a ValueConverter to get the column's value, is there a more direct way?), but even if I do this, what do I specify as the DataTrigger's value?
Edit:
So in my case I went ahead and did the following (currently this would only modify the TextBlock's background):
<DataGridTemplateColumn Header="Lost" Width="Auto">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Lost, NotifyOnTargetUpdated=True}">
<TextBlock.Triggers>
<EventTrigger RoutedEvent="Binding.TargetUpdated">
<BeginStoryboard>
<Storyboard>
<ObjectAnimationUsingKeyFrames Duration="0" Storyboard.TargetProperty="Background">
<DiscreteObjectKeyFrame KeyTime="0" Value="{Binding Converter={StaticResource BackgroundConverter}}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</TextBlock.Triggers>
</TextBlock>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
Which to me seems right, but only works once for some reason. I added a seperate TargetUpdated event handler right on the TextBlock definition to see if the event was indeed being called on every change and it is.
Something must be missing on my EventTrigger. Probably something to do with the Storyboard.
Anyways, this all seems incredibly verbose for something so simple, so I went ahead and went with the code-behind route.
I suppose Triggers and DataTriggers can't help in this case because datagrigger's value is unstable. And worse, it's not dependency property and you can't bind to it. It seems to me the better way is to use EventTrigger.
<Window.Resources>
<BeginStoryboard x:Key="bsbPing">
<Storyboard>
<DoubleAnimation Duration="0:0:0.2" Storyboard.TargetProperty="FontSize" To="{Binding Path=PingValue}" />
</Storyboard>
</BeginStoryboard>
</Window.Resources>
<Grid>
<StackPanel>
<TextBox Name="txbPingValue" Text="{Binding Path=PingValue}">
<TextBox.Triggers>
<EventTrigger RoutedEvent="TextBox.TextChanged">
<EventTrigger.Actions>
<StaticResource ResourceKey="bsbPing" />
</EventTrigger.Actions>
</EventTrigger>
</TextBox.Triggers>
</TextBox>
<Button Name="btnPing" Click="btnPing_Click">Ping</Button>
</StackPanel>
</Grid>
and code:
public partial class Window7 : Window
{
public Ping MyPing { get; set; }
public Window7()
{
InitializeComponent();
MyPing = new Ping { PingValue = 20.0 };
this.DataContext = MyPing;
}
private void btnPing_Click(object sender, RoutedEventArgs e)
{
MyPing.PingValue += 10;
}
}
public class Ping : INotifyPropertyChanged
{
private double pingValue;
public double PingValue
{
get
{
return pingValue;
}
set
{
pingValue = value;
NotifyPropertyChanged("PingValue");
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
}
You are on the right track with the converter. The technique you are using is sometimes called "binning" which maps a large set of integers to a fixed small set of values. It is also used to create histograms.
As far as not updating, your binding expression has to be more specific to retrieve the Lost property, otherwise it won't be re-evaluated when Lost changes. Once you change it you'll also need to update your converter.

WPF Frame in separate thread?

I have an application where when a person types or selects a listbox there's a portion of the screen that dynamically updates to a new view.
The problem is since WPF runs everything in a single thread the displaying of the view can interfer with typing or navigating making the app less responsive. What i'd like to do is run the view portion in a different thread.
My first thought was to use a window running on a different thread, but more than being something of a hack there's the problem of the window losing focus and being placed behind the mainwindow when the mainwindow is clicked. I could make it topmost but I also need to place other windows in front of it.
So what's the best way to achieve this, can I place the view in a frame and run it in a different thread?
You can load / generate the data in a backround thread and then update the UI using Dispatcher.BeginInvoke.
I would propose you use the Visibility property of this piece of the screen that you want to make appear and use a trigger to set it from Invisible or Collapsed to Visible whenever the user types or selecs. Or you can animate the Opacity property to produce a cool fading effect ;-) I will add some code to illustrate the point.
EDIT: a time consuming backgroundtask, like File operations, can be accomplished using a BackgroundWorker
<Window x:Class="VisibleOnTypingSpike.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<StackPanel>
<StackPanel Orientation="Horizontal">
<Label Name="TypingSnooper"
Visibility="{Binding TypingSnooperVisibility}">
You are typing!</Label>
<Label>
<Label.Style>
<Style>
<Setter Property="Label.Opacity" Value="0"/>
<Style.Triggers>
<DataTrigger Binding="{Binding HasListBoxNewSelection}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard >
<Storyboard>
<DoubleAnimation From="0" To="1"
Duration="0:0:1"
Storyboard.TargetProperty="Opacity"/>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<BeginStoryboard >
<Storyboard>
<DoubleAnimation From="1" To="0"
Duration="0:0:1"
Storyboard.TargetProperty="Opacity"/>
</Storyboard>
</BeginStoryboard>
</DataTrigger.ExitActions>
</DataTrigger>
</Style.Triggers>
</Style>
</Label.Style>
You selected!
</Label>
</StackPanel>
<TextBox TextChanged="TextBox_TextChanged"></TextBox>
<ListBox Name="SimpleListBox"
SelectionChanged="SimpleListBox_SelectionChanged">
<ListBoxItem>1</ListBoxItem>
<ListBoxItem>2</ListBoxItem>
</ListBox>
</StackPanel>
using System.Windows;
using System.Windows.Controls;
namespace VisibleOnTypingSpike
{
public partial class Window1 : Window
{
public Visibility TypingSnooperVisibility
{
get { return (Visibility)GetValue(TypingSnooperVisibilityProperty); }
set { SetValue(TypingSnooperVisibilityProperty, value); }
}
public static readonly DependencyProperty TypingSnooperVisibilityProperty =
DependencyProperty.Register("TypingSnooperVisibility",
typeof(Visibility),
typeof(Window1),
new UIPropertyMetadata(System.Windows.Visibility.Collapsed));
public bool HasListBoxNewSelection
{
get { return (bool)GetValue(HasListBoxNewSelectionProperty); }
set { SetValue(HasListBoxNewSelectionProperty, value); }
}
public static readonly DependencyProperty HasListBoxNewSelectionProperty =
DependencyProperty.Register("HasListBoxNewSelection",
typeof(bool),
typeof(Window1),
new UIPropertyMetadata(false));
public Window1()
{
InitializeComponent();
DataContext = this;
}
private void TextBox_TextChanged(object sender, TextChangedEventArgs e)
{
var textbox = (TextBox) sender;
if (textbox.Text.Length > 0) TypingSnooperVisibility = Visibility.Visible;
else TypingSnooperVisibility = Visibility.Hidden;
}
private void SimpleListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
HasListBoxNewSelection = true;
HasListBoxNewSelection = false;
}
}
}

Resources