【问题标题】:Changing Property in code behind does not update view在后面的代码中更改属性不会更新视图
【发布时间】:2021-04-18 16:28:19
【问题描述】:

当我更改作为模型对象的属性时,除非我重新分配绑定上下文,否则视图不会更新。我没有使用 mvvm,所以没有视图模型。

public partial class MainPage : ContentPage
{
    
    private MySource _myCurrentSource = new MySource("yolor");

    public MySource MyCurrentSource {
        get { return _myCurrentSource; }
        set  {_myCurrentSource = value; } 
    }
    public MainPage()
    {
        InitializeComponent();
        MyCurrentSource = _myCurrentSource;
        MainStack.BindingContext = MyCurrentSource;
        label.SetBinding(Label.TextProperty, new Binding("SourceString"));
    }

    private void Button_Clicked(object sender, EventArgs e)
    {
        MyCurrentSource = new MySource("new string");
        //property changed
        MainStack.BindingContext = MyCurrentSource;
    }
}

我想摆脱: MainStack.BindingContext = MyCurrentSource;

这就是我的 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"
             x:Class="DataBindingPlayGround.MainPage">

    <StackLayout Padding="10, 0" x:Name="MainStack" HorizontalOptions="Center"
               VerticalOptions="CenterAndExpand">
        <Label x:Name="label" Text="TEXT" FontSize="48" />
        <Button Text="Change" Clicked="Button_Clicked"/>
    </StackLayout>
</ContentPage>

模型类:

    public class MySource
{
    public MySource(string str)
    {
        SourceString = str;
    }
    public string SourceString { get; set; }
}

【问题讨论】:

标签: xamarin.forms data-binding


【解决方案1】:

修改MySource类如下试试:

public class MySource : INotifyPropertyChanged
{
    public MySource(string str)
    {
        sourceString = str;
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    private string sourceString;

    public double SourceString 
    {
        set
        {
            if (sourceString != value)
            {
                sourceString = value;
                OnPropertyChanged("SourceString");
            }
        }
        get
        {
            return sourceString;
        }
    }
}

==============================更新================= ================

虽然不了解你的应用程序的逻辑,但如果你想让MyCurrentSource 工作。您还需要使用INotifyPropertyChanged:

public partial class MainPage : ContentPage ,INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    
    protected virtual void OnPropertyChanged(string propertyName)
    {
         PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }    

    private MySource _myCurrentSource;
    
    public MySource MyCurrentSource
    {
        set
        {
            if (_myCurrentSource != value)
            {
                _myCurrentSource = value;
                OnPropertyChanged("MyCurrentSource");
            }
        }
        get
        {
            return _myCurrentSource;
        }
    } 

    public MainPage()
    {
        InitializeComponent();
        _myCurrentSource = new MySource("yolor");
        //MyCurrentSource = _myCurrentSource;
        MainStack.BindingContext = _myCurrentSource ;
        label.SetBinding(Label.TextProperty, new Binding("SourceString"));
    }

    private void Button_Clicked(object sender, EventArgs e)
    {
        _myCurrentSource = new MySource("new string");
        //property changed
        MainStack.BindingContext = _myCurrentSource;
    }
}

或者可以在BindingContext的时候直接设置新的Model。

public partial class MainPage : ContentPage
{
    
    public MainPage()
    {
        InitializeComponent();

        MainStack.BindingContext = new MySource("yolor");
        label.SetBinding(Label.TextProperty, new Binding("SourceString"));
    }

    private void Button_Clicked(object sender, EventArgs e)
    {
        //property changed
        MainStack.BindingContext = new MySource("new string");
    }
}

【讨论】:

  • 我现在添加了提到的更改,如果我这样做MyCurrentSource.SourceString = "string changed" 它可以工作。但我想要但仍然没有发生的是:MyCurrentSource= new MySource("new string") 注意:MyCurrentSource 是代码隐藏中的属性,它由:private MySource _myCurrentSource = new MySource("yolor");
  • 我对更改对象的属性不感兴趣,我想在后面的代码中为我的属性分配一个新对象,实际上我从具有许多字段的通信通道收到了两个对象。我需要相应地更新 UI。所以我想在代码隐藏中将这些新对象分配给我的两个属性。在 UI 中,两种不同的堆栈布局将这两个属性作为它们的绑定上下文。
  • 因为ContentPage有问题。您还没有理解我使用INotifyPropertyChanged 分享的回复。如果你可以将它用于MyCurrentSource,它也可以工作。
  • 这很有帮助。虽然它在代码隐藏 i.2(实现接口的主页面)中不起作用,但使用视图模型类尝试了同样的事情,并且效果非常好。我添加了生成的代码作为答案。谢谢。
  • @UmerMehmood 很高兴解决了它。记得尽可能标记答案。
【解决方案2】:

这终于对我有用,以防万一有人遇到类似情况: 下面的源类:

    public class FirstSource
{
    public string sourceString;
    public string SourceString { get; set; }
    public int SourceOneProp2 { get; set; }


    public FirstSource(string str, int num)
    {
        SourceString = str;
        SourceOneProp2 = num;
    }
   
}
    public class SecondSource
{
    public string ExampleField { get; set; }
    public int SourceTwoProp2 { get; set; }

    public SecondSource(string exampleField, int num)
    {
        ExampleField = exampleField;
        SourceTwoProp2 = num;
    }
}

ViewModel(决定用来简化任务)

    class MainPageViewModel : BaseViewModel
{
    private FirstSource _sourceOne;
    private SecondSource _sourceTwo;

    public FirstSource SourceOne
    {
        get { return _sourceOne; } 
        set { SetValue(ref _sourceOne, value); }
    }

    public SecondSource SourceTwo
    {
        get { return _sourceTwo; }
        set { SetValue(ref _sourceTwo, value); }
    }

}

代码背后:

 public partial class MainPage : ContentPage
{
    int counter = 0;

    private MainPageViewModel ViewModel
    {
        get { return BindingContext as MainPageViewModel; }
        set { BindingContext = value; }
    }

    public MainPage()
    {
        InitializeComponent();
        ViewModel = new MainPageViewModel();
        ViewModel.SourceOne = new FirstSource("init1", 10);
        ViewModel.SourceTwo = new SecondSource("init2", 20);
    }

    private void Button_Clicked(object sender, EventArgs e)
    {
        counter += 1;
        ViewModel.SourceOne = new FirstSource("Changed1", 100+counter);
    }

    private void Button_Clicked_1(object sender, EventArgs e)
    {
        counter += 1;
        ViewModel.SourceTwo = new SecondSource("Changed2", 200+counter);

    }
}

XAML/UI

    <StackLayout Padding="10, 0" x:Name="MainStack" HorizontalOptions="Center" VerticalOptions="Start">
    <Label x:Name="label" Text="{Binding Path=SourceOne.SourceString}" FontSize="48" />
    <Label Text="{Binding Path=SourceOne.SourceOneProp2}" />
    <Button Text="Change" Clicked="Button_Clicked"/>

    <StackLayout Padding="10, 0" x:Name="SecondStack">
        <Label x:Name="secondLabel" Text="{Binding Path=SourceTwo.ExampleField}" FontSize="48" />
        <Label  Text="{Binding Path=SourceTwo.SourceTwoProp2}"  />
        <Button Text="Change" Clicked="Button_Clicked_1"/>
    </StackLayout>
    
</StackLayout>

【讨论】:

    猜你喜欢
    • 2021-03-08
    • 2010-10-07
    • 2020-04-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多