OnPropertyChanged 不会与标签文本一起触发

Posted

技术标签:

【中文标题】OnPropertyChanged 不会与标签文本一起触发【英文标题】:OnPropertyChanged not fire with label text 【发布时间】:2021-12-11 13:46:20 【问题描述】:

我在一个 Xamarin 应用程序中,我必须制作一个待办事项列表。我正在使用列表视图。每次添加新的待办事项时,我都必须动态设置标签文本,如下所示:任务数 2/4,其中 2 是已完成的任务,4 是总任务。一切正常,但是当我必须更新标签文本时发现了一些问题。我正在使用 MVVM 模式。在 XAML 中,我将文本值绑定到 SetInfoDoneText。在 MainPage 中,我将 bindigContext 设置为 VM(TodoListViewModel)。我将 INotifyPropertyChanged 与 OnPropertyChanged 一起使用。我做了一个改变 setInfoDoneText 值的方法。问题是 set 和 get 仅被调用一次,并且当 setInfoDoneText 由 OnPropertyChanged 方法更新时不会再次触发。这是代码。 问题是当我尝试更新 lblDoneInfo 文本( ) 类 TodoListViewModel: INotifyPropertyChanged

    public ObservableCollection<TodoItem> todoItems  get; set; 
    public event PropertyChangedEventHandler PropertyChanged;
    public String setInfoDoneText;
    public String SetInfoDoneText
    
        get => setInfoDoneText;
        set
        

            setInfoDoneText = value;
            OnPropertyChanged("SetInfoDoneText");
        

    
    protected void OnPropertyChanged(string propertyName = null)
    
        if (PropertyChanged != null)
        
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        

    
   
    int doneTask = 0;
    int totalTask = 0;
    public TodoListViewModel()
    
       
        this.todoItems = new ObservableCollection<TodoItem>();
        setInfoDoneText = "Number of tasks: " + doneTask + "/" + totalTask;
       
        

    

    public ICommand AddTodoCommand => new Command(AddTodoItem);

    public String newTodoInputValue  get; set; 
    public String selectedItem  get; set; 
    public  bool highPriority  get; set; 
    public  bool midPriority  get; set; 
    public  bool lowPriority  get; set; 
   



    Color newColor = new Color();
    public void AddTodoItem()
    
       
        if (highPriority)
        
            newColor = Color.Red;
            AddNewItem(newColor);
            highPriority = false;


        
        if (midPriority)
        
            newColor = Color.Orange;
            AddNewItem(newColor);
            midPriority = false;

        
        if (lowPriority) 
        
            newColor = Color.Yellow;
            AddNewItem(newColor);
            lowPriority = false;
        
       
        

    

        
    
    public TodoItem AddNewItem(Color newColor)
    
        
        TodoItem newItem = new TodoItem(newTodoInputValue,
           false,
           highPriority,
           midPriority,
           lowPriority,
           newColor);

        
        todoItems.Add(newItem);
        UpdateDoneInfo();

        return newItem;
    

    public ICommand RemoveTodoCommand => new Command(RemoveTodoItem);

    public void RemoveTodoItem(object o)
    
        TodoItem todoItemBeingRemoved = o as TodoItem;
       
        todoItems.Remove(todoItemBeingRemoved);
    

    public ICommand EditTodoCommand => new Command(EditTodoItem);
    public void EditTodoItem(object o)
    


        TodoItem todoItemBeingEdited = o as TodoItem;
        int newIndex = todoItems.IndexOf(todoItemBeingEdited);
        todoItems.Remove(todoItemBeingEdited);

        TodoItem updatedTodo = AddNewItem(newColor);
        //todoItems.Add(updatedTodo);

        int oldIndex = todoItems.IndexOf(updatedTodo);
        todoItems.Move(oldIndex, newIndex);

    

    public String UpdateDoneInfo()
    



        totalTask = todoItems.Count;

        foreach (TodoItem item in todoItems)
        
            if (item.complete) doneTask++;
        


        return setInfoDoneText = "Number of tasks: " + doneTask + "/" + totalTask;
    



<ContentPage.BindingContext>
    <local:TodoListViewModel/>
</ContentPage.BindingContext>


<StackLayout>
   
  
    <Entry 
        x:Name="inputField"
        Text="Binding newTodoInputValue" 
        Placeholder="Enter a todo..."
        

    />


    <Label x:Name="lblDoneInfo" Text="Binding SetInfoDoneText, Mode=TwoWay ">
        
    </Label>

    <FlexLayout AlignItems="Center" JustifyContent="SpaceBetween">
        <input:CheckBox x:Name="highP" 
                        IsChecked="Binding highPriority" 
                        CheckChangedCommand="Binding AddTodoCommand" 
                        Margin="0,0,20,0" />
        <Label Text="High Priority" FontSize="Medium"/>

        <input:CheckBox x:Name="midP" 
                       IsChecked="Binding midPriority"
                       CheckChangedCommand="Binding AddTodoCommand"  
                       Margin="0,0,20,0" />
        <Label Text="Medium Priority" FontSize="Medium"/>

        <input:CheckBox x:Name="lowP"  
                        IsChecked="Binding lowPriority"  
                        CheckChangedCommand="Binding AddTodoCommand"  
                        Margin="0,0,20,0" />
        <Label Text="Low Priority" FontSize="Medium"/>
    </FlexLayout>
     


    
    <ListView x:Name="todoList" ItemsSource="Binding todoItems" SelectedItem="Binding selectedItem">
        
        <ListView.ItemTemplate>
            <DataTemplate>
                <ViewCell Height="20">
                    
                    <FlexLayout JustifyContent="SpaceBetween"  AlignItems="Center" Padding="20,0">
                        <ContentView>
                            <FlexLayout AlignItems="Center">
                                <input:CheckBox IsChecked="Binding complete" Margin="5" />
                                <Label x:Name="todoText" TextColor="Binding color" Text="Binding todoText" FontSize="Large"/>
                            </FlexLayout>
                            

                        </ContentView>

                        <ImageButton 
                            Source="editar_24.png"
                            BackgroundColor="Transparent"
                            WidthRequest="100"
                            HeightRequest="100"
                            Margin="0,0,20,0"
                            Command="Binding Path=BindingContext.EditTodoCommand,
                                        Source=x:Reference todoList"
                            CommandParameter="Binding ."/>

                        
                        <ImageButton 
                        
                            Source="basura_24.png"
                            BackgroundColor="Transparent"
                            WidthRequest="100"
                            HeightRequest="100"
                           
                            Command="Binding Path=BindingContext.RemoveTodoCommand, 
                                        Source=x:Reference todoList"
                            CommandParameter="Binding ."/>
  
                    </FlexLayout>

                </ViewCell>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>
</StackLayout>

【问题讨论】:

【参考方案1】:

PropertyChanged 仅在您设置 公共属性 SetInfoDoneText 的值时触发。您的代码正在设置字段 setInfoDoneText(小写)的值。

通常最好的做法是设置字段private 来防止这种情况

private String setInfoDoneText;

【讨论】:

非常感谢您的帮助!但是我尝试用大写 S 更改 setInfoDoneText,现在应用程序运行但立即关闭...不知道为什么...我认为这属于无限循环或类似的东西。 您只需要在UpdateDoneInfo 和VM 构造函数中更改它。如果您在属性设置器中更改它,您将创建一个无限循环,导致应用程序崩溃 这就是重点!!!非常感谢您的宝贵时间!来自西班牙的最美好的祝愿! 如果您不介意回答,还有一个问题!我如何将列表视图中的 checkbos 绑定到视图模型中的命令。我想要实现的是更改与以前相同的标签,但现在根据列表视图中检查的待办事项。问题是,如果我尝试在 listview 中正常绑定到 viewmodel,它不会触发命令功能。 请使用相关代码发布一个新问题

以上是关于OnPropertyChanged 不会与标签文本一起触发的主要内容,如果未能解决你的问题,请参考以下文章

WPF:多重绑定不使用 OnPropertyChanged 更新?

Xamarin Forms App Shell OnPropertyChanged 未更新 FlyoutHeader 视图

在不触发 OnPropertyChanged 的​​情况下更新 WPF DataGrid

OnPropertyChanged在WPF中的作用,越详细越好。谢谢了!!

在 WPF 中找出 OnPropertyChanged 事件的接收者

我们应该在UI线程中调用OnPropertyChanged吗?