我正在尝试制作一个 Button
,它使用该面板的 Height
属性上的动画打开/关闭该面板。
方法是将动画的“To”值绑定(bind)到 viewmodel 属性,该属性在按钮的命令中更改。
我想它应该像这样工作:
按钮
被点击- viewmodel 检查其“IsOpened”属性
- 如果为 True,则 vm 将其设置为 False 并将
TargetHeight
设置为 0;如果为 False,则 vm 将其设置为 True 并将TargetHeight
设置为 128 - 动画触发并将高度更改为所需值
但实际上它是这样工作的:
按钮
被点击- 动画触发并将
Height
更改为先前设置的值 - 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>
View 模型类:
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;
}
}
最佳答案
您可以处理 View 模型的 PropertyChanged
事件并在 View 中以编程方式启动动画:
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 等标记语言来实现 View 逻辑非常有意义。
您可能还想考虑在 View 中指定实际高度,并绑定(bind)到 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
并绑定(bind)到其 IsChecked
属性,而不是使用 IsBottomOpened
源属性。您是否真的需要 View 模型中的这些属性取决于您的要求。
关于c# - WPF:DoubleAnimation "To"属性绑定(bind)计时,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53476802/