xamarin 如何通过ViewModel属性更改在Template中运行控件动画

bq8i3lrv  于 2022-12-07  发布在  其他
关注(0)|答案(3)|浏览(158)

.Net Maui页面,其中包含CarouselView和通过将数据绑定到ViewModel中的项集合而创建的卡片列表(VM)。我正在寻找方法来动画控制内CarouselView的一些属性在VM设置为一个特定的值。动画应该在c#代码中完成(代码隐藏、触发操作、行为等),而不是通过xaml。不确定如何正确实现。这是我认为可能的解决方案:

  • 在VM中声明事件并在代码隐藏中订阅它。对于非模板控件非常有效,但对于CarouselView,它由DataTemplate中描述的Card控件集合组成,我只需要找到特定的活动控件,比如说我想动画化的Label。不知道如何找到它,VM集合中的每个项都有它的一个示例,但即使我这样做,它看起来也不是一个很好的面向MVVM的设计。
  • 我最大的希望是TriggerAction<Label>(假设我想制作Label动画),但问题是TriggerAction似乎只能在EventTrigger中工作,它只捕获xaml控件事件,而不是VM事件。但另一方面,它不允许在内部声明TriggerAction<T>。不知道为什么在.Net毛伊岛有这样的限制,我希望我有两者的一些混合。
  • 行为,-与触发器一样,不确定如何通过VM中声明任何属性更改或事件来运行它们

第一个

cqoc49vn

cqoc49vn1#

正如您所说,datatemplate中的控件很难访问,所以我做了一个示例来测试Label的TranslateX属性,发现label.TranslateTo(60, 0, 100);label.TranslateX = 60的效果是一样的。
据此,可以在Item中创建一个变量,绑定到DataTemplate中的label,在page.cs中修改item的值,也可以使用DataTrigger设置label.TranslateX的值。

k0pti3hp

k0pti3hp2#

好的,我已经找到了一种方法,通过行为中的可绑定属性来实现它。虽然比我预期的要复杂一些,但它确实有效。不幸的是,. NET Maui没有提供更好更直观的方法来实现它,我想这是需要改进的地方。
代码如下:

namespace View.Behaviors;

public class AnimateWrongAnswerBehavior : BaseBehavior<VisualElement>
{
    public static readonly BindableProperty ShouldAnimateProperty =
        BindableProperty.CreateAttached(
            "ShouldAnimate",
            typeof(bool),
            typeof(AnimateWrongAnswerBehavior),
            false,
            propertyChanged: OnShouldAnimateChanged);

    public static void SetShouldAnimate(BindableObject view, VisualElement value) =>
        view.SetValue(ShouldAnimateProperty, value);

    static async void OnShouldAnimateChanged(BindableObject bindable, object oldValue, object newValue)
    {
        if ((bool)newValue)
        {
            await Animate((VisualElement)bindable);
        }
    }

    /// <summary>
    /// Implemenation of Animation logic
    /// </summary>  
    static private async Task Animate(VisualElement elementToAnimate)
    {
        await elementToAnimate.TranslateTo(-30, 0, 100);
        await elementToAnimate.TranslateTo(60, 0, 100);
        await elementToAnimate.TranslateTo(-30, 0, 100);
    }
}

然后,您可以将动画绑定到任何可视元素,如Frame

<ContentPage 
   xmlns:bh="clr-namespace:View.Behaviors" ...>

    <Frame bh:AnimateWrongAnswerBehavior.ShouldAnimate="{Binding IsInvalid}">

</ContentPage>
6ioyuze2

6ioyuze23#

请注意,TranslateTo是可等待的,并且可能需要async/await模式来使元素具有动画效果,尤其是在调用了多个TranslateTo时。
添加了async/awaitTriggerAction

public class TriggerActionTranslateTo : TriggerAction<VisualElement>
{
  protected override async void Invoke(VisualElement sender)
  {
      await sender.TranslateTo(0, 0, 250);
      await sender.TranslateTo(30, 0, 250);
      await sender.TranslateTo(0, 0, 250);
  }

由于某种原因,仅使用一个TranslateTo时不需要async/await,这将设置以下动画:

protected override void Invoke(VisualElement sender)
{
    sender.TranslateTo(30, 0, 250);
}

XAML文件:

<Label.Triggers>
  <DataTrigger
    TargetType="Label"
    Binding="{Binding Property}" 
    Value="True">
  <DataTrigger.EnterActions>
    <ns:TriggerActionTranslateTo/>
  </DataTrigger.EnterActions>
  <DataTrigger.ExitActions>
  ...

相关问题