#wpf #animation #fade #textblock
#wpf #Анимация #исчезать #textblock
Вопрос:
Я использую текстовый блок в datatemplate для ячейки в datagrid. У меня есть требование, в котором говорится, что при изменении значения ячейки текст должен:
- исчезать перед изменением
- значение должно измениться
- снова ввести текст
На данный момент я использую TargetUpdated RoutedEvent для запуска анимации, чтобы текст исчез, а затем вернулся. Но исчезновение происходит после того, как текст уже изменил значение на экране.
<DataTemplate>
<Border>
<TextBlock Name="templateTextBlock" Text="{Binding Path=FirstName, NotifyOnTargetUpdated=True}" />
</Border>
<DataTemplate.Triggers>
<EventTrigger RoutedEvent="Binding.TargetUpdated">
<BeginStoryboard>
<Storyboard AutoReverse="True">
<DoubleAnimation Storyboard.TargetName="templateTextBlock" Storyboard.TargetProperty="Opacity" To=".1" Duration="0:0:.5" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</DataTemplate.Triggers>
</DataTemplate>
Мой вопрос в том, как мне добиться требуемого эффекта — убрать, изменить текст, ввести?
Большое спасибо.
Комментарии:
1. Глупые требования к win.
Ответ №1:
Написал интерактивное поведение, которое должно это делать:
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
<TextBlock Text="{Binding Name, NotifyOnTargetUpdated=True}">
<i:Interaction.Behaviors>
<b:AnimatedTextChangeBehavior AnimationDuration="0:0:0.1" />
</i:Interaction.Behaviors>
</TextBlock>
class AnimatedTextChangeBehavior : Behavior<TextBlock>
{
public Duration AnimationDuration { get; set; }
private string OldValue = null;
private string NewValue = null;
DoubleAnimation AnimationOut;
DoubleAnimation AnimationIn;
protected override void OnAttached()
{
base.OnAttached();
AnimationOut = new DoubleAnimation(1, 0, AnimationDuration, FillBehavior.HoldEnd);
AnimationIn = new DoubleAnimation(0, 1, AnimationDuration, FillBehavior.HoldEnd);
AnimationOut.Completed = (sOut, eOut) =>
{
AssociatedObject.SetCurrentValue(TextBlock.TextProperty, NewValue);
OldValue = NewValue;
AssociatedObject.BeginAnimation(TextBlock.OpacityProperty, AnimationIn);
};
Binding.AddTargetUpdatedHandler(AssociatedObject, new EventHandler<DataTransferEventArgs>(Updated));
}
private void Updated(object sender, DataTransferEventArgs e)
{
string value = AssociatedObject.GetValue(TextBlock.TextProperty) as string;
AssociatedObject.BeginAnimation(TextBlock.OpacityProperty, AnimationOut);
NewValue = value;
if (OldValue == null)
{
OldValue = value;
}
AssociatedObject.SetCurrentValue(TextBlock.TextProperty, OldValue);
}
}
Если вы не хотите использовать для этого интерактивность Blend SDK, вы можете просто взять код и преобразовать его в отдельный класс и использовать Loaded
событие TextBlock для выполнения настройки.
Комментарии:
1. Я действительно рад, что нашел этот пост. Для этого я использовал 2 текстовых блока и анимацию. Это намного чище.
2. @H.B. Могу я узнать, какая ссылка на пространство имен для <b: ?
3. @abccba: это ссылается на пространство имен класса, которое я определяю во фрагменте ниже. Итак, что-то вроде
clr-namespace:YourProject.YourNamespace
, зависит от того, куда вы его поместили.4. стоит отметить, что
NotifyOnSourceUpdated=True
должна присутствовать текстовая привязка, иначе такое поведение не сработает (в любом случае, это меня зацепило!).