【问题标题】:WPF: UI not being updated with INotifyPropertyChangedWPF:未使用 INotifyPropertyChanged 更新 UI
【发布时间】:2014-08-06 22:34:30
【问题描述】:

我目前正在学习 WPF、DataContexts 和 DataBinding。我的目标是有一个任务栏任务(使用 NotifyIconWpf),它有一个运行后台的连续线程来监控网络。

我已经设法将一个 UI 元素(如屏幕截图所示)绑定到 ProgramClock 类,但它不会在 ProgramClock 更改时更新,很可能是因为 INotifyPropertyChanged 参数中的某些内容有误。

我发现的最接近的类似问题是UI not being updated INotifyPropertyChanged,但是我无法弄清楚要更改 XAML 中的 DataPath 的内容,或者如何使 INotifyPropertyChanged 正常工作。

请注意,BackgroundWorker 线程成功更新了 App 的静态 ProgramClock(使用单独的 WinForm 检查)并且该时间最初加载到 WPF 中,因此可能是 PropertyChanged 没有被正确调用。 p>

程序时钟

public class ProgramClock : INotifyPropertyChanged
    {
        private DateTime _myTime;
        public event PropertyChangedEventHandler PropertyChanged;
        private ClockController clockController;

        public ProgramClock()
        {

            this._myTime = DateTime.Now;
            clockController = new ClockController();

            MessageBox.Show("created new clock");
        }

        public DateTime MyTime
        {
            get
            {
                return this._myTime;
            }

            set
            {
                if (_myTime == value) return;
                _myTime = value;

                //System.Windows.Forms.MessageBox.Show(PropertyChanged.ToString());
                if (PropertyChanged != null)
                    PropertyChanged(this, new PropertyChangedEventArgs(_myTime.ToString()));
            }
        }

        public string MyTimeString
        {
            get { return this._myTime.ToString(); }
        }

        public void UpdateTime()
        {
            this.MyTime = DateTime.Now;
        }
    }

泡泡CS

public partial class InfoBubble : System.Windows.Controls.UserControl
{

    public InfoBubble()
    {
        InitializeComponent();
        this.DataContext = App.ClockBindingContainer;
    }
}

冒泡 XAML

<UserControl x:Class="FileWatcher.Controls.InfoBubble"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008">
    <Border
        Background="White"
        BorderBrush="Orange"
        BorderThickness="2"
        CornerRadius="4"
        Opacity="1"
        Width="160"
        Height="40">
            <TextBlock
          Text="{Binding Path=MyTimeString}"
          HorizontalAlignment="Center"
          VerticalAlignment="Center" />
    </Border>
</UserControl>

主应用

public partial class App : System.Windows.Application
{

    private TaskbarIcon tb;
    private ResourceDictionary _myResourceDictionary;
    public static ProgramClock _programClock = new ProgramClock();

    private void Application_Startup(object sender, StartupEventArgs e)
    {
        NotifIconStarter();
    }

    public static ProgramClock ClockBindingContainer
    {
        get { return _programClock; }
    }
}

【问题讨论】:

    标签: c# wpf xaml datacontext


    【解决方案1】:

    一个问题在于您调用PropertyChanged 事件。您需要将更改为 PropertyChangedEventArgs 的属性的名称​​而不是传递新值。

    所以使用:

    if (PropertyChanged != null)
        PropertyChanged(this, new PropertyChangedEventArgs("MyTime"));
    

    代替:

    if (PropertyChanged != null)
        PropertyChanged(this, new PropertyChangedEventArgs(_myTime.ToString()));
    

    但是,您实际上是绑定到另一个属性 - MyTimeString

    最终,您要绑定的属性需要引发事件。

    【讨论】:

    • 感谢您的快速回复。然而,这并没有解决问题。 :( UI 的 DataBinding 仍然没有更新。
    • @SpaceSteak 每当您在 WPF 中遇到绑定问题时,请检查 VS 中的输出窗口(在视图菜单中查找)。如果有任何错误将在此处提及。有什么事吗?
    • @SpaceSteak 您是否已将 Text="{Binding Path=MyTimeString}" 更改为 Text="{Binding Path=MyTime}" ?没有调用 PropertyChanged(.."MyTimeString") 所以它显然不会更新。
    • 成功了,@Fex。谢谢! :D 因为我将 App 设置为数据上下文,所以我在 App 类中有 MyTimeString,但显然这不是正确的方法。我会将您的其他答案标记为已接受。
    • @SpaceSteak 为什么这不是答案? O_o
    【解决方案2】:
       if (PropertyChanged != null)
           PropertyChanged(this, new PropertyChangedEventArgs(_myTime.ToString()));
    

    你应该传递属性名称:

       if (PropertyChanged != null)
           PropertyChanged(this, new PropertyChangedEventArgs("MyTime");
    

    但是我建议你获取 PostSharp 库 - 它具有很好的功能,可以让你编写普通属性并通过自动提升 PropertyChanged 来“按属性装饰它”。如果您不想使用PostSharp,至少创建一些方法,例如:

    public void RaisePropertyChanged([CallerMemberName] string propertyName = null)
    {
         if (PropertyChanged != null)
             PropertyChanged(this, new PropertyChangedEventArgs(propertyName);
    }
    

    并在您的设置器中调用它。 ([CallerMemberName] 是 C# 5.0 的特性,它自动传递“调用者”名称(在 setter 中它将传递属性名称)

    【讨论】:

    • 感谢您的快速回复。我尝试将属性更改移动到它自己的函数并将其更改为“MyTime”,但它仍然无法正常工作。在 VS2010 上,所以没有 C#5.0。
    • @SpaceSteak 开始调试您的应用程序,点击查看、输出并检查是否有任何绑定错误 - 如果有,请将它们写在这里
    【解决方案3】:

    您没有通知您绑定到的属性的更改(即MyTimeString),所以 WPF 知道MyTime 的更改,但MyTimeString 是否也发生了更改?从未收到通知。

    尝试改变这一点:

                if (PropertyChanged != null)
                    PropertyChanged(this, new PropertyChangedEventArgs(_myTime.ToString()));
    

    到这里:

                if (PropertyChanged != null)
                    PropertyChanged(this, new PropertyChangedEventArgs("MyTimeString")); // Not MyTime!
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-06-02
      • 1970-01-01
      • 1970-01-01
      • 2019-04-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多