【问题标题】:How to refresh TableView data after tapping ViewCell in Xamarin Forms?在 Xamarin Forms 中点击 ViewCell 后如何刷新 TableView 数据?
【发布时间】:2017-05-07 17:27:36
【问题描述】:

所以我有以下代码为我的TableView 动态创建 ViewCells:

XAML:

<StackLayout>
   <TableView Intent="Settings">
      <TableView.Root>
         <TableSection x:Name="tableSection"></TableSection>
      </TableView.Root>
   </TableView>
</StackLayout>

C#:

categories = getCategories();
foreach (var category in categories)
{
   var viewCell = new ViewCell 
   { 
      View = new StackLayout()
      {
         Padding = new Thickness(20, 0, 20, 0),
         HorizontalOptions = LayoutOptions.FillAndExpand,
         Children = { 
            new StackLayout() {
               Orientation = StackOrientation.Horizontal,
               VerticalOptions = LayoutOptions.CenterAndExpand,
               Children = {
                  new StackLayout() {
                     HorizontalOptions = LayoutOptions.StartAndExpand,
                     Children = {
                        new Label { Text = category.Name}
                      },
                  new StackLayout() {
                     HorizontalOptions = LayoutOptions.EndAndExpand,
                     Orientation = StackOrientation.Horizontal,
                     Children = {
                        new Label { Text = category.Count},
                        new Image { Source = "right1.png",
                                    IsVisible = category.Selected }
                     }
                  }
               }
            }
         }
       }
    };
    viewCell.Tapped += (sender, e) =>
    {
       if (category.Selected == false)
       {
          App.DB.UpdateSelected(true);
       }
       else
       {
          App.DB.UpdateSelected(false);
       }
       categories = getCategories();
       totalPhraseCount = getTotalPhraseCount();
       Title = totalPhraseCount.ToString() + " phrases";
     };
    tableSection.Add(viewCell);
}

我想要做的是,每当我点击视图单元格以更新所选属性时,表格视图中的数据也会更新。在 ListView 中,我可以调用 ItemSelected 事件并使用更新的类别再次调用 ItemSource。 TableView 可以吗?

【问题讨论】:

  • 为什么要使用TableView?回答这个问题对于实施适当的解决方案很重要。如果您在 TableView 中可能有很多行,您将不得不对您的解决方案进行创意。我想提供帮助,但需要更多关于您尝试使用此 TableView 在应用程序中实现的目标的指导(例如它是设置页面,还是向用户显示动态行等)。

标签: c# .net xaml xamarin xamarin.forms


【解决方案1】:

尝试关注

categories = getCategories();
foreach (var category in categories)
{
   var viewCell = new ViewCell 
   { 
      View = new StackLayout()
      {
         Padding = new Thickness(20, 0, 20, 0),
         HorizontalOptions = LayoutOptions.FillAndExpand,
         Children = { 
            new StackLayout() {
               Orientation = StackOrientation.Horizontal,
               VerticalOptions = LayoutOptions.CenterAndExpand,
               Children = {
                  new StackLayout() {
                     HorizontalOptions = LayoutOptions.StartAndExpand,
                     Children = {
                        new Label { Text = category.Name}
                      },
                  new StackLayout() {
                     HorizontalOptions = LayoutOptions.EndAndExpand,
                     Orientation = StackOrientation.Horizontal,
                     Children = {
                        new Label { Text = category.Count},
                        new Image { Source = "right1.png",
                                    IsVisible = category.Selected }
                     }
                  }
               }
            }
         }
       }
    };
    viewCell.Tapped += (sender, e) =>
    {
       if (category.Selected == false)
       {
          App.DB.UpdateSelected(true);
       }
       else
       {
          App.DB.UpdateSelected(false);
       }
       categories = getCategories();
       totalPhraseCount = getTotalPhraseCount();
       Title = totalPhraseCount.ToString() + " phrases";
     };

}
tableSection.Add(viewCell);
tableSection.ForceLayout();
// Or try tableview.Forcelayout();
// Or try parent_stacklayout.ForceLayout();

【讨论】:

  • 谢谢@Atul。但这仍然行不通。我的 TableView 仍然没有更新。
  • 你能把小样本项目发给我吗?
  • 你可以吗?
  • 也尝试将我的最后三个语句置于循环之外。
  • 使用此解决方案的性能在 Android 手机上会很差。应始终避免调用ForceLayout(),因为它会使布局无效并导致所有布局计算再次运行。您还在循环中调用它,这在 Xamarin.Forms 中不应执行。
【解决方案2】:

您应该使用绑定到您的视图模型而不是手动设置值,以下文章应该可以帮助您:https://developer.xamarin.com/guides/xamarin-forms/xaml/xaml-basics/data_bindings_to_mvvm/ 为了使示例更容易编写,我使用了一个列表视图,因为您基本上在做的是创建一个列表。

XAML:

<StackLayout>

        <ListView x:Name="CategoriesList" ItemsSource="{Binding Categories}">

            <ListView.ItemTemplate>

                <DataTemplate>

                    <ViewCell>

                        <StackLayout HorizontalOptions="FillAndExpand"
                                     Padding="20,0,20,0"
                                     VerticalOptions="CenterAndExpand">

                            <StackLayout HorizontalOptions="StartAndExpand">

                                <Label Text="{Binding Name}" />

                            </StackLayout>

                            <StackLayout HorizontalOptions="StartAndExpand">

                                <Label Text="{Binding Count" />

                                <Image IsVisible="{Binding Selected}" Source="right1.png" />

                            </StackLayout>


                        </StackLayout>

                    </ViewCell>

                </DataTemplate>

            </ListView.ItemTemplate>

        </ListView>

    </StackLayout>

C#: 在页面的构造函数上添加对此方法的调用: 还要确保将绑定上下文设置为您的视图模型!

public PageConstructor(PageViewModel viewModel)
        {
            this.BindingContext = viewModel;
            Listeners();
        }

private void Listeners()
        {
            CategoriesList.ItemTapped += (sender, e) =>
            {
                if (category.Selected == false)
                {
                    App.DB.UpdateSelected(true);
                }
                else
                {
                    App.DB.UpdateSelected(false);
                }
                categories = getCategories();
                totalPhraseCount = getTotalPhraseCount();
                Title = totalPhraseCount.ToString() + " phrases";
            };
        }

您的 ViewModel 应该有一个 Categories 属性并实现 INotifyPropertyChanged 接口:

ViewModel C#:

class PageViewModel : INotifyPropertyChanged
    {
        List<Category> Categories;
    public event PropertyChangedEventHandler PropertyChanged;

    public PageViewModel()
    {
        this.Categories = //API call to retrieve the categories
    }

    public List<Category> Categories
    {
        set
        {
            if (Categories != value)
            {
                Categories = value;

                if (PropertyChanged != null)
                {
                    PropertyChanged(this,
                        new PropertyChangedEventArgs("Categories"));
                }
            }
        }
        get
        {
            return Categories;
        }
    }
}

为了更好地实现 MVVM 模型,您可以尝试以下解决方案:

【讨论】:

  • 感谢@Lucas 的建议。我确实知道如何在 ListView 中执行此操作,但我被特别告知要使用 TableView 因此我的问题。
  • 我并不是要烦人,但我不确定 TableView 是否适合您。如果您查看文档,它指出 TableView 应该用于静态数据,这就是它没有 ItemTemplate 属性的原因。此外,它被设计用于在每一行中呈现不同的数据,这也不是你的情况。可以在developer.xamarin.com/guides/xamarin-forms/user-interface/… 找到该文档
【解决方案3】:

试试这个:

XAML:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:App54"
             x:Class="App54.MainPage">

 <ContentPage.Content>
        <TableView Intent="Settings">
            <TableRoot>
                <TableSection x:Name="tableSection" Title="Section Title">
                </TableSection>
            </TableRoot>
        </TableView>
    </ContentPage.Content>
</ContentPage>

主页:

public partial class MainPage : ContentPage
{
    MyViewModel vm;

    public MainPage()
    {
        InitializeComponent();

        vm = new MyViewModel();

        foreach (MyDataModel dm in vm.Data)
        {
            Image img = new Image();
            img.SetBinding(Image.SourceProperty, "MyImage", BindingMode.TwoWay, null, null);
            img.BindingContext = dm;

            Label label1 = new Label();
            label1.SetBinding(Label.TextProperty, "MyLabel", BindingMode.TwoWay, null, null);
            label1.BindingContext = dm;

            Label label2 = new Label();
            label2.SetBinding(Label.TextProperty, "Selected", BindingMode.TwoWay, null, null);
            label2.BindingContext = dm;

            StackLayout sl = new StackLayout();
            sl.Orientation = StackOrientation.Horizontal;
            sl.Children.Add(img);
            sl.Children.Add(label1);
            sl.Children.Add(label2);

            ViewCell vc = new ViewCell();
            vc.BindingContext = dm;
            vc.View = sl;
            vc.Tapped += Vc_Tapped;

            tableSection.Add(vc);
        }
    }

    private void Vc_Tapped(object sender, EventArgs e)
    {
        ViewCell vc = (ViewCell)sender;
        MyDataModel dm = (MyDataModel)vc.BindingContext;

        MyDataModel currSel = vm.Data.FirstOrDefault(d => d.Selected == true);

        if (currSel != null)
            currSel.Selected = false;

        dm.Selected = true;
    }
}

视图模型:

public class MyViewModel
{
    public ObservableCollection<MyDataModel> Data { get; set; }

    public MyViewModel()
    {
        Data = new ObservableCollection<MyDataModel>
        {
            new MyDataModel {MyLabel = "Label 1", MyImage = "image.png", Selected = false },
            new MyDataModel {MyLabel = "Label 2", MyImage = "image.png", Selected = false },
            new MyDataModel {MyLabel = "Label 3", MyImage = "image.png", Selected = false },
            new MyDataModel {MyLabel = "Label 4", MyImage = "image.png", Selected = false },
            new MyDataModel {MyLabel = "Label 5", MyImage = "image.png", Selected = false }
        };
    }
}

型号:

public class MyDataModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged = delegate { };

    private string myLabel;
    public string MyLabel
    {
        get { return myLabel; }
        set
        {
            if (value != myLabel)
            {
                myLabel = value;
                PropertyChanged(this, new PropertyChangedEventArgs("MyLabel"));
            }
        }
    }
    private string myImage;
    public string MyImage
    {
        get { return myImage; }
        set
        {
            if (value != myImage)
            {
                myImage = value;
                PropertyChanged(this, new PropertyChangedEventArgs("MyImage"));
            }
        }
    }
    private bool selected;
    public bool Selected
    {
        get { return selected; }
        set
        {
            if (value != selected)
            {
                selected = value;
                PropertyChanged(this, new PropertyChangedEventArgs("Selected"));
            }
        }
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-14
    • 1970-01-01
    相关资源
    最近更新 更多