【问题标题】:Xamarin Android MvvmCross - How to Force Repaint of Custom View within an MvxList Item?Xamarin Android MvvmCross - 如何在 MvxList 项中强制重绘自定义视图?
【发布时间】:2014-11-06 21:23:48
【问题描述】:

为了帮助进行讨论,我在 GitHub 上发布了所有相关的源代码... https://github.com/WindSpirit/DroidCustomView

基本上,我编写了一个 Android Custom-View (Asgl.Android.Views.RatingView),它继承自 TableLayout 并包含几个由公共 get/set 属性更改的 ImageView(通过 MvvmCross 绑定和/或 AXML 属性)。

这个Custom-View在一个MvxList、MvxItemTemplate中使用。

这是 MvxItemTemplate AXML 代码的样子...

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:local="http://schemas.android.com/apk/res-auto"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical">
    <TextView
        android:id="@+id/task_description"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        local:MvxBind="Text RatingValue" />
    <TextView
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        local:MvxBind="Text ScaleValue" />
    <Asgl.Android.Views.RatingView
        android:id="@+id/rating"
        android:layout_margin="20dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        local:MvxBind="Rating RatingValue; Scale ScaleValue" />
</LinearLayout>

TextView 控件按预期通过 MvvmCross 绑定显示数据,但 Custom-View 控件显示不正确。

基于“N-28-CustomBinding”,当在 View 对象上调用 Public Property setter 方法时,我自定义了 Custom-View 的外观。另见http://slodge.blogspot.ca/2013/06/n28-custom-bindings-n1-days-of-mvvmcross.html

一切正常,除了所有初始 MvxItemTemplate 项目的显示完全相同,即使它们应该以不同的方式显示。就好像 Custom-View 的缓存图像用于每个列表项,即使列表项属性的值不同。

Custom-View 中,this.Parent() 永远不可用,并调用 Custom-View 方法,如 this.Invalidate() 或 this.InvalidateDrawable(this.Invalidate() 或 this.InvalidateDrawable()。 myDrawable.Drawable ),似乎没有任何效果。

也就是说,简单的执行下面的代码,在MvxList的构建过程中不一定会导致视觉列表项的变化……

public int? Rating
{
  get { return _rating; }

  set {

    if ((value != null) && (value < -2 || value > 5))
      throw new ArgumentOutOfRangeException();

    if (_rating != value)
    {
      _rating = value;
      _isUpdating = true;
      try
      {
        var testValue = Scale ?? 0;

        Rating0.Visibility = (testValue > 0) ?
          ViewStates.Visible : ViewStates.Gone;

        Rating1.Visibility = (testValue > 0) ?
          ViewStates.Visible : ViewStates.Gone;
        Rating2.Visibility = (testValue > 2) ?
          ViewStates.Visible : ViewStates.Gone;
        Rating3.Visibility = (testValue > 3) ?
          ViewStates.Visible : ViewStates.Gone;

        Rating4.Visibility = (testValue > 4) ?
          ViewStates.Visible : ViewStates.Gone;

        ActnGood.SetColorFilter((Rating > 0) ?
          ColourGood : ColourDisabled, PorterDuff.Mode.SrcIn);

        Rating0.SetImageDrawable(ActnGood);

        ActnBad.SetColorFilter((Rating > 0) ?
          ColourDisabled : ColourBad, PorterDuff.Mode.SrcIn);

        Rating1.SetImageDrawable(ActnBad);

        this.Invalidate();
        // etc...

        if (RatingChanged != null)
          RatingChanged(this, EventArgs.Empty);
      } finally {
        _isUpdating = false;
      }
    }
  }
}
public event EventHandler RatingChanged;

问题:当列表项属性值由于 MvvmCross 绑定而发生更改时,我需要做什么才能让 MvxList 重绘其中一个列表项?

【问题讨论】:

    标签: android xamarin xamarin.android mvvmcross


    【解决方案1】:

    哇!我终于有了一个解决方案,并将其作为我的 GitHub 项目的修订版发布在该线程的不同第一行中。

    我通过检查 DrawChild View 句柄的 GroupView 句柄得出了这个解决方案,然后考虑...“如果我对 DrawChild View 参数执行与对 GroupView 执行相同的操作会怎样”?它会在屏幕上绘制正确的信息吗?

    解决方案草案看起来或多或少是这样的......

        protected override bool DrawChild(Canvas canvas, View child, long drawingTime)
        {
            System.Diagnostics.Debug.Print(string.Format("this.Handle = {0} Scale = {1} Rating = {2}", Handle, Scale, Rating));
    
            InitControls(child);
            Refresh();
    
            return base.DrawChild(canvas, child, drawingTime);
        }
    

    是的!更新传递给 DrawChild 的 GroupView(子)就可以了!

    【讨论】:

      【解决方案2】:

      我打开了你的示例项目

      尝试先更新到最新的 MvvmCross。

      使用低版本没有意义

      【讨论】:

      • 感谢您提醒我更新 MvvmCross 的需要。我已经做到了。但是,我应该提到 MvvmCross 绑定似乎正在工作。问题似乎是画布的更新。也就是说(ViewModel 看起来还可以)=>(View 看起来还可以)=>(Android Canvas 好像在使用缓存的图片)
      • 这与 MvvMcross 绑定无关。您遇到的问题与更新这些 ImageView 的方式有关
      • 绑定似乎工作正常,正如你所说,值不同
      • 我建议您更改显示该控件的方式。您可以使用转换器等 MVVM 技术,而不是使用代码隐藏来更改 ImageViews。在我看来,您将 UI 代码与逻辑混合在一起
      • 你应该只有一个用于好\坏的 ImageView,它的可绘制值绑定到好\坏枚举(使用转换器)。此外,您还应该为具有 Rating 属性值的 rating 单独创建一个控件并绑定到该值。
      【解决方案3】:

      重写 DrawChild 方法并将其视觉设置与事件处理程序的实例设置同步是迄今为止唯一能显示自身的解决方案。

      这个自定义视图(Android 视图组)似乎是正确的方法,尽管监听器注册在错误的位置(它们应该在 OnAttachedToWindows() 中注册并在 OnDetachedFromWindow() 中删除)。

      这段 YouTube.com 视频重申了我对所采取方法的信念

      Google I/O 2013 - 为 Android 编写自定义视图 https://www.youtube.com/watch?v=NYtB6mlu7vA#t=1286

      但是,我真诚地认为我遗漏了一些可以使 DrawChild 逻辑更加高效的东西。

      【讨论】:

        猜你喜欢
        • 2016-06-12
        • 1970-01-01
        • 1970-01-01
        • 2011-10-19
        • 2019-05-16
        • 1970-01-01
        • 1970-01-01
        • 2014-09-27
        • 2023-03-19
        相关资源
        最近更新 更多