WPF 绑定不更新视图

问题描述 投票:0回答:9

我有一个文本块:

<TextBlock HorizontalAlignment="Left" Name="StatusText" Margin="0,20" TextWrapping="Wrap" Text="{Binding StatusText}">
            ... Status ...
</TextBlock>

隐藏代码:

public StatusPage()
{
    InitializeComponent();
    this.DataContext = new StatusPageViewModel(this);
}

在 viewModel 中:

private string _statusText;
/// <summary>
/// Status text
/// </summary>
public string StatusText
{
    get { return _statusText; }
    set { _statusText = value; }
}

并在 viewModel 中的函数中:

string statusText = Status.GetStatusText();
this.StatusText = statusText;

GetStatusText()
返回“工作完成”等字符串。该函数的值被分配给
this.StatusText
,但 TextBlock 的文本属性不会更改,并且仍显示占位符“... Status...”

我知道这样的问题 --> 点击<--- but after reading this I'm still not able to find solution

@更新

根据您的建议,我更新了我的代码,现在我有了这个:

public string StatusText
{
    get 
    {
        return _statusText;
    }
    set 
    {
        _statusText = value; 
        RaisePropertyChanged("StatusText");
    }
}

和viewModel的声明:

 public class StatusPageViewModel : ObservableObject, INavigable

地点:

ObservableObject 类是:

public abstract class ObservableObject : INotifyPropertyChanged
{
    #region INotifyPropertyChanged Members

    /// <summary>
    /// Raises the PropertyChange event for the property specified
    /// </summary>
    /// <param name="propertyName">Property name to update. Is case-sensitive.</param>
    public virtual void RaisePropertyChanged(string propertyName)
    {
        OnPropertyChanged(propertyName);
    }

    /// <summary>
    /// Raised when a property on this object has a new value.
    /// </summary>
    public event PropertyChangedEventHandler PropertyChanged;

    /// <summary>
    /// Raises this object's PropertyChanged event.
    /// </summary>
    /// <param name="propertyName">The property that has a new value.</param>
    protected virtual void OnPropertyChanged(string propertyName)
    {

        PropertyChangedEventHandler handler = this.PropertyChanged;
        if (handler != null)
        {
            var e = new PropertyChangedEventArgs(propertyName);
            handler(this, e);
        }
    }

    #endregion // INotifyPropertyChanged Members
}

但是还是不行

c# wpf xaml mvvm
9个回答
44
投票

您需要在 ViewModel 订单中实现

INotifyPropertyChanged
来通知 View 属性已更改。

这里是 MSDN 页面的链接:System.ComponentModel.INotifyPropertyChanged

最需要注意的是,您应该在属性设置器中引发

PropertyChanged
事件。


10
投票

添加两种方式的绑定模式,因为默认情况下Textblock的绑定模式是一种方式

<TextBlock HorizontalAlignment="Left" Name="StatusText" Margin="0,20" TextWrapping="Wrap" Text="{Binding StatusText, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
            ... Status ...
</TextBlock>

当然,您还需要实现 INotifyPropertyChanged 来实现此目的,请参阅 此链接 了解如何实现。


6
投票

使用数据模型时,您必须确保模型在初始加载时完整。因此,如果您这样做: this.DataContext = mainViewModel 并且 mainViewModel 的某些部分未加载(=null),那么您将无法绑定它们。例如,我有一个模型,该模型中有一个对象程序。我将 TextBlock 的文本绑定到 Model.Program.Name。程序对象在初始加载时未连接,因此您必须在之后重新绑定到加载的对象,否则无法发送通知。


3
投票

你的视图模型需要实现

INotifyPropertyChanged
,并且每次你的属性之一发生变化时(即在setter中),你都需要引发它。

没有它,WPF 就无法知道属性已更改。


2
投票

我遇到了这个问题,这就是我做错的事情......

注意:我的 INotifyPropertyChanged 编码正确。


在我看来,我有

<SomeView.DataContext>
    <SomeViewModel/>
<SomeView.DataContext/>

...这会调用 VM 的构造函数(创建一个指向/绑定的实例)。

在另一个类中(在我的程序主窗口的 ViewModel 代码中)我还实例化了 ViewModel,即:

private SomeAstractBaseViewModel someViewModel = new SomeViewModel();
private SomeAstractBaseViewModel someOtherViewModel = new SomeOtherViewModel(); 

它们都继承自超类,并且我在主窗口的一部分中显示不同视图的实例之间来回切换 - 按照我的意图。

如何连接所有这些是另一个问题,但是当我删除之前实例化 ViewModel 的另一个“未使用”实例的有问题的 xaml (在本答案的顶部)时,视图将按照 进行更新INotifyPropertyChanged机制。


2
投票

在我的情况下,

UserControl
嵌套在
View
中,当我尝试对
Binding
中的属性使用
UserControl
时,框架正在寻找
ViewModel
中不存在的属性。为了解决这个问题,我必须指定
ElementName

MyControl.xaml:

<UserControl
    ...
    x:Name="MyUserControl">
    ...
    <Label Content="{Binding MyProperty, ElementName=MyUserControl}"
    ...

MyControl.xaml.cs:

public partial class MyControl: UserControl, INotifyPropertyChanged
{
    ...
    private string _myProperty = "";

    public string MyProperty
    {
        get => _myProperty ;
        set
        {
            if (value == _myProperty ) return;
            _myProperty = value;
            OnPropertyChanged();
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
    ...

1
投票

当您调用 OnPropertyChanged 时,请确保包含属性名称。今天花了我几个小时,这个他妈的隐藏的绑定魔法太令人沮丧了。给我一条错误消息或其他信息,而不是只是默默地失败!

因此,不要只调用 OnPropertyChanged() 而不提供参数,而是在属性设置器中调用它(这样 CallerMemberName 会为您填写),或者自己提供它。

例如在 xaml 中的某处您有绑定:

... Value="{Binding Progress}" ...

然后在代码隐藏中,您拥有继承自 INotifyPropertyChanged 的 DataContext 对象,并在更新您调用的值后的某个方法中:

OnPropertyChanged("Progress");

0
投票

就我而言,问题是当我拨打

OnPropertyChanged
时。我输入的会员名不正确。例如:

不正确

        private Student std = new Student();
        public Student Std { 
            get { return std; } 
            set { std = value; OnPropertyChanged("Student"); } 
}

正确

        private Student std = new Student();
        public Student Std { 
            get { return std; } 
            set { std = value; OnPropertyChanged("Std"); } 
}

这里我必须传递属性名称而不是类名称


0
投票

我也有类似的情况。我有一个带有实现 IPropertyChanged 的 ViewModel 的 WPF UserControl,看起来我做的一切都是正确的,除了一件事:我的代码在主线程上运行,而我的长时间运行的操作正在阻止 UI 的更新。

所以就我而言,我将 WindowControl.Dispatcher 放入我的 ViewModel 中,所以我必须做的事情是:

dispatcher.Invoke(() =>   
{  
    Status = $"Processing task {number} of {total}.";
});

调度程序用于在 UI 线程上运行代码。

© www.soinside.com 2019 - 2024. All rights reserved.