WPF: привязка свойств DoubleAnimation "To" - PullRequest
0 голосов
/ 26 ноября 2018

Я пытаюсь создать Button, который открывает / закрывает некоторую панель, используя анимацию в свойстве Height этой панели.

Подход заключается в привязке значения анимации "To" к viewmodelсвойство, которое изменяется в команде кнопки.

Я полагаю, что это должно работать следующим образом: *1001*

  1. Button нажато
  2. Viewmodel проверяет его "IsOpened "свойство
  3. Если это True, то vm устанавливает его в False и TargetHeight в 0;Если это False, то vm устанавливает его в True и TargetHeight в 128
  4. Анимация срабатывает и изменяет высоту на желаемое значение

Но в действительности это работает так:

  1. Button нажатие
  2. Анимация запускается и изменяет Height на ранее установленное значение
  3. Viewmodel проверяет свое свойство IsOpened и изменяет его значение

Из-за этого viewmodel устанавливает высоту цели не для текущего нажатия кнопки, а для следующего раза в будущем.

Что я должен изменить, чтобы сделать это правильно?Уже пытались установить свойство BeginTime для задержки анимации, к сожалению, это не помогло.

Код выглядит следующим образом:

XAML

<Button Command="{Binding SwitchBottomPanel}">
        <Button.Triggers>
            <EventTrigger RoutedEvent="Button.Click">
                <BeginStoryboard>
                    <Storyboard>
                        <DoubleAnimation Storyboard.TargetName="BottomPanel"
                                         Storyboard.TargetProperty="Height"
                                         To="{Binding TargetHeight}"
                                         Duration="0:0:0.3"
                                         BeginTime="0:0:0.3"/>
                    </Storyboard>
                </BeginStoryboard>
            </EventTrigger>
        </Button.Triggers>
    </Button>

Класс Viewmodel:

    class MainViewModel : ViewModelBase
{
    private double _targetHeight;
    private bool _isBottomOpened;
    private double _bottomHeightBig = 128;

    public double TargetHeight
    {
        get { return _targetHeight; }
        set
        {
            _targetHeight = value;
            RaisePropertyChanged(nameof(TargetHeight));
        }
    }

    public bool IsBottomOpened
    {
        get { return _isBottomOpened; }
        set
        {
            _isBottomOpened = value;

            if (value == true) TargetHeight = _bottomHeightBig;
            else TargetHeight = 0;

            RaisePropertyChanged(nameof(IsBottomOpened));
        }
    }

    public ICommand SwitchBottomPanel { get; set; }

    public MainViewModel()
    {
        SwitchBottomPanel = new DelegateCommand(() => IsBottomOpened = !IsBottomOpened);
        RaisePropertyChanged(nameof(SwitchBottomPanel));

        IsBottomOpened = false;
    }
}

1 Ответ

0 голосов
/ 26 ноября 2018

Вы можете обработать событие PropertyChanged для модели представления и запустить анимацию программно в представлении:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        DataContext = new MainViewModel();
        Loaded += OnLoaded;
        Unloaded += OnUnloaded;
    }

    private MainViewModel ViewModel => DataContext as MainViewModel;

    private void OnLoaded(object sender, RoutedEventArgs e) =>
        ViewModel.PropertyChanged += ViewModel_PropertyChanged;

    private void OnUnloaded(object sender, RoutedEventArgs e) =>
        ViewModel.PropertyChanged += ViewModel_PropertyChanged;

    private void ViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e) =>
        BottomPanel.BeginAnimation(HeightProperty, new DoubleAnimation()
        {
            To = ViewModel.TargetHeight,
            Duration = TimeSpan.FromSeconds(0.3)
        });
}

То, что вы можете реализовать такие вещи, как анимации, в чистом XAML, это не значит, чточто вы всегда должны.Это пример, в котором имеет смысл реализовать логику представления с использованием выразительного языка программирования, такого как C #, вместо использования языка разметки, например XAML.

Возможно, вы также захотите указать фактическую высоту в представлении.и привязать к свойству IsBottomOpened:

<Grid x:Name="BottomPanel" Background="Yellow" Height="0" Width="200">
    <Grid.Style>
        <Style TargetType="Grid">
            <Style.Triggers>
                <DataTrigger Binding="{Binding IsBottomOpened}">
                    <DataTrigger.EnterActions>
                        <BeginStoryboard>
                            <Storyboard>
                                <DoubleAnimation Storyboard.TargetProperty="Height"
                                         To="128"
                                         Duration="0:0:0.3" />
                            </Storyboard>
                        </BeginStoryboard>
                    </DataTrigger.EnterActions>
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </Grid.Style>
</Grid>

Если вы сделаете это, вы также можете заменить элемент Button на ToggleButton и привязать к его свойству IsChecked вместо использованияIsBottomOpened свойство источника.Нужны ли вам эти свойства в модели представления, зависит от ваших требований.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...