【问题标题】:Xamarin Forms User Control Binding inside ListViewListView 内的 Xamarin 表单用户控件绑定
【发布时间】:2018-10-17 01:58:33
【问题描述】:

场景 - ListView 绑定到字符串的 ObservableCollection。 Listview 有一个标签和一个 UserControl(只包含一个标签)。两者都绑定到同一个集合。

另外,还有一个按钮可以为集合生成一些随机数据。

问题是当我运行应用程序并单击“生成数据”按钮时,标签会更新,但 UserControl 不会更新。

下面是示例代码。

MainPage.xaml

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
         xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
         xmlns:local="clr-namespace:TestSample"
         xmlns:controls="clr-namespace:TestSample.Controls"
         x:Class="TestSample.MainPage">

<StackLayout>
    <Button Text="Generate Data" Clicked="Button_Clicked"/>

    <ListView Grid.Row="1" HorizontalOptions="Center" ItemsSource="{Binding Collection}" SeparatorVisibility="None">
        <ListView.ItemTemplate>
            <DataTemplate>
                <ViewCell>
                    <StackLayout Orientation="Horizontal" HorizontalOptions="Center">
                        <Label Text="{Binding}"/>
                        <Label Text=" - "/>
                        <controls:MagicBox Text="{Binding}"/>
                    </StackLayout>
                </ViewCell>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>
</StackLayout>

MainPage.xaml.cs

 public partial class MainPage : ContentPage
{
    public ObservableCollection<string> Collection { get; set; }

    public MainPage()
    {
        InitializeComponent();
        Collection = new ObservableCollection<string>
        {
            "XX",
            "XX",
            "XX"
        };

        this.BindingContext = this;
    }

    public void Button_Clicked(object sender, EventArgs e)
    {
        var rand = new Random();
        for (int i = 0; i < 3; i++)
        {
            Collection[i] = rand.Next(10, 100).ToString();
        }
    }
}

用户控制

  <ContentView.Content>
  <Grid>
      <Label Text="{Binding Text}" />
  </Grid>

public partial class MagicBox : ContentView
{

    public static readonly BindableProperty TextProperty =
      BindableProperty.Create("Text", typeof(string), typeof(MagicBox), "XX");

    public string Text
    {
        get { return (string)GetValue(TextProperty); }
        set { SetValue(TextProperty, value); }
    }

    public MagicBox ()
    {
        InitializeComponent ();
        this.BindingContext = this;
    }
}

在实现 INotifyPropertyChanged 后,我还尝试使用 POCO 类的 ObservableCollection 而不是字符串,但没有奏效。 如果我将 MagicBox Text 直接绑定到字符串,它可以工作,但如果我将它绑定到某个属性,则不会。

【问题讨论】:

  • 谁能帮我解决这个问题?

标签: c# xaml xamarin xamarin.forms


【解决方案1】:

在做

this.BindingContext = this;

在 MagicBox.xaml.cs 中强制 BindingContext 到当前对象。这也意味着不再继承父级的 BindingContext。

为了使其正常工作,请将您的代码更改为

[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class MagicBox : ContentView
{

    public static readonly BindableProperty TextProperty =
        BindableProperty.Create("Text", typeof(string), typeof(MagicBox), default(string));

    public string Text
    {
        get { return (string)GetValue(TextProperty); }
        set { SetValue(TextProperty, value); }
    }

    public MagicBox ()
    {
        InitializeComponent ();
    }
}

和你的 xaml 到

<?xml version="1.0" encoding="UTF-8"?>
<ContentView xmlns="http://xamarin.com/schemas/2014/forms" 
         xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
         x:Class="TestSample.Controls.MagicBox"
         x:Name="box">
  <ContentView.Content>
    <Grid>
        <Label Text="{Binding Text, Source={x:Reference box}}" />
    </Grid>
  </ContentView.Content>
</ContentView>

我测试过了。它有效。

【讨论】:

    【解决方案2】:

    我认为问题在于“this.BindingContext = this;”这一行在您的自定义控件中。

    你应该像这样绑定: Text="{Binding Path=BindingContext, Source={x:Reference ListViewName}}"

    确保将 x:Name 添加到您的列表视图。未测试,但希望对您有所帮助。

    【讨论】:

      【解决方案3】:

      首先,更新您的自定义控件:

      • 更改您的“Text”依赖属性定义 => 将绑定模式设置为“OneWay”并添加 propertyChanged 事件处理程序,如下所示:

        public partial class MagicBox : ContentView
        {
        
        public static readonly BindableProperty TextProperty =
          BindableProperty.Create("Text", typeof(TextVM), typeof(MagicBox), "XX", BindingMode.OneWay, null, new BindableProperty.BindingPropertyChangedDelegate(TextPropertyChanged));
        
        public TextVM Text
        {
            get { return (TextVM)GetValue(TextProperty); }
            set { SetValue(TextProperty, value); }
        }
        
      • 然后将'Text' propertyChanged 方法添加到您的自定义控件中,如下所示:

        private static void TextPropertyChanged(BindableObject sender, object oldValue, object newValue )
        {
            Label updatedLabel = sender as Label;
            if(updatedLabel == null) return;
        
            updatedLabel.Text = (newValue as TextVM)?.MyText;
        }
        

      制作一个嵌入文本属性的 Observable 对象,以便抛出 'PropertyChanged' 事件:

      public class TextVM : INotifyPropertyChanged
      {
          public event PropertyChangedEventHandler PropertyChanged;
      
          private string _myText;
          public string MyText
          {
              get => _myText;
              set
              {
                  _myText = value;
                  PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("MyText"));
              }
          }
      }
      

      然后在您的 XAML 中,更新文本绑定:

      <controls:MagicBox Text="{Binding MyText}"/>
      

      不要忘记更新您的集合类型和随机数生成过程...

      应该不错吧!

      【讨论】:

      • 没用。如果我删除 this.BindingContext = this; 什么都没有显示在添加它时输出没有改变。
      • Property Changed 事件处理程序根本没有被调用。
      • 你是对的对不起,让'BindingContext = this'在构造函数中。为什么不调用“TextPropertyChanged”?我认为这是因为您的数据源是字符串对象列表。字符串类型不实现 INotifyPropertyChanged...所以尝试制作一个包含 Text 属性(get;set;)并使用 NotifyPropertyChanged 的​​“ViewModel”对象,我更新答案...
      • 其实这是我原来的问题,这个不行。我用字符串替换了 TextVM 类,以便在 SF 上发布它:)
      • 我相信我在 UserControl 中遗漏了一些东西,一些非常基本的东西。如果标签可以更新,则绑定肯定有效。是 UserControl 无法选择更改的值。更新问题。
      猜你喜欢
      • 2016-10-10
      • 1970-01-01
      • 2017-04-16
      • 2016-09-08
      • 2017-07-15
      • 2021-10-20
      • 2017-04-05
      • 1970-01-01
      • 2017-07-22
      相关资源
      最近更新 更多