【问题标题】:C# WPF - How to auto refresh the UI after run itC# WPF - 如何在运行后自动刷新 UI
【发布时间】:2014-08-04 07:00:42
【问题描述】:

我在 XAML 中创建了一个名为 TbTimer 的简单 Label

我做了以下代码:

class Level2 
{
    public Level2()
    {
        timer = new DispatcherTimer();
        timer.Interval = TimeSpan.FromSeconds(1);
        timer.Tick += timer_Tick;
    }
    public int counter;
    public void timer_Tick(object sender, EventArgs e)
    {
        counter++;
    }

    public DispatcherTimer timer;
}

public partial class MainWindow : Window
{

    public MainWindow()
    {
        InitializeComponent();

        lvl2 = new Level2();
    }

    private void MenuItemMedium_Click(object sender, RoutedEventArgs e)
    {
        lvl2.timer.Start();
        TbTimer.Content = lvl2.counter.ToString();
    }
}

然后我有另一个按钮,当单击该按钮时我调用TimerUpdater

当我运行程序并单击按钮时,我可以看到TextBlock 的内容显示数字 1...并且它不会继续运行数字 - 当我在 5 后再次单击按钮时秒显示数字 6。

所以我猜计时器在幕后运行良好,但TextBlock 的内容只有在我单击按钮时才会更新。

我应该怎么做才能使TextBlock 内容在不单击按钮的情况下更新秒数?希望我的解释和问题是清楚的。

【问题讨论】:

  • 您必须更新计时器上的标签,而不仅仅是增加一个不相关的变量。 ps:方法中有方法。
  • 谢谢 Jeroen,但是...我如何更新计时器上的文本块?我在这方面很新,希望你能指导我
  • 我不完全确定,但Dispatcher.Invoke(() => TbTimer.Text = counter); 应该是关于它的(在你的Timer_Tick 方法中)。
  • 我认为在这种情况下 Dispatcher.Invoke 是不必要的,因为正在使用 DispatcherTimer,所以回调应该在 UI 线程中触发(我相信)。
  • 我编写了 dispatcher.invoke 但系统要求我提供我不熟悉的“委托方法”...有什么建议吗?

标签: c# wpf refresh


【解决方案1】:

使用修改后的代码,答案会完全改变。对于内容的巨大变化,我深表歉意。完成此操作的“最简单”方法是添加一个事件以更新计数器并让您的 UI 订阅它。比如:

class Level2
{
    public event Action<int> CounterUpdated;

    ...
    public void timer_Tick(object sender, EventArgs e)
    {
        counter++;
        if (CounterUpdated != null)
           CounterUpdated(counter);
    }
}

public class MainWindow
{
    public MainWindow()
    {
       InitializeComponent();

       lvl2 = new Level2();
       lvl2.CounterUpdated += UpdateCounterText;
    }

    private void MenuItemMedium_Click(object sender, RoutedEventArgs e)
    {
       lvl2.timer.Start();
    }

    private void UpdateCounterText(int newCounterValue)
    {
        TbTimer.Content = newCounterValue.ToString();
    }
}

顺便说一句,这最终类似于绑定系统的设置方式。如果你只是将你的文本框绑定到counter 变量,它会更干净,更容易使用。为此,您需要将 XAML 更改为:

<TextBox Name="TbTimer" Text="{Binding Counter}"/>

并分配 DataContext:

public class MainWindow
{
    public MainWindow()
    {
       InitializeComponent();

       lvl2 = new Level2();
       DataContext = lvl2;
    }

    private void MenuItemMedium_Click(object sender, RoutedEventArgs e)
    {
        lvl2.timer.Start();
    }
}

Level2 现在需要实现 INotifyPropertyChanged,并且你必须让 counter 成为一个属性(这样才能绑定到):

class Level2 : INotifyPropertyChanged
{
    //Notify Property Changed Implementation from MSDN:
    public event PropertyChangedEventHandler PropertyChanged;

    private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
    {
        if (PropertyChanged != null)
        {
           PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    private int counter = 0;
    public int Counter
    {
       get { return counter; }
       set
       {
           counter = value;
           NotifyPropertyChanged();
       }
    }

    ...
    public void timer_Tick(object sender, EventArgs e)
    {
        Counter++;
    }
}

绑定系统现在将在计时器计时时自动更新文本框(并增加 Counter 属性。这是它应该在 WPF 中完成的方式,所以请随时询问任何实施时出现的问题。

供参考,这是我使用的INofityPropertyChanged的实现:http://msdn.microsoft.com/en-us/library/system.componentmodel.inotifypropertychanged.aspx

【讨论】:

  • TimerUpdater 在不同的类中,他不在 MainWindow 中,所以我不能在计数器下添加“TbTimer.Text = counter.ToString();”,因为该类无法识别新课程中的用户界面...也尝试添加您给我的“IF”,但仍然无法正常工作
  • @user3396397 那么您的代码最初是如何工作的呢?根据您所显示的,我的代码将编译。我愿意更改它,但您必须显示更多代码/详细信息。
  • 我刚刚编辑了我上面的代码...请看一下,希望你能提供帮助。当然,MAIN 中有更多代码,但与 TIMER 问题无关。我也将文本块更改为标签(只是认为它会更容易处理......但事实并非如此)
  • @user3396397,谢谢,我过会儿再回复你。
  • 感谢您的宝贵时间,等待您的反馈:)
猜你喜欢
  • 1970-01-01
  • 2019-04-27
  • 2012-09-23
  • 1970-01-01
  • 2013-09-16
  • 2023-01-30
  • 2014-10-04
  • 2013-03-19
  • 2012-12-09
相关资源
最近更新 更多