【问题标题】:Force a WPF control to refresh?强制 WPF 控件刷新?
【发布时间】:2010-10-23 13:34:14
【问题描述】:

我们有两个这样的文本块:(我们使用 .NET FW 3.0)

<TextBlock Grid.Column="0" Name="tabName" Style="{StaticResource textBlockBarStyle}" HorizontalAlignment="Left">
  <TextBlock.Margin>
      <Binding Converter="{StaticResource dpiConverter}">
          <Binding.ConverterParameter>
               <Thickness Left="3" Top="6" Right="0" Bottom="0"/>
          </Binding.ConverterParameter>
      </Binding>
  </TextBlock.Margin>
</TextBlock>

<TextBox  x:Name="txtBoxHelp" 
          IsReadOnly="True" Style="{DynamicResource txtBoxHelpStyle}" 
          IsTabStop="False" 
          Text="some text" MouseLeftButtonDown="txtBoxHelp_MouseLeftButtonDown">
     <TextBox.Margin>
        <Binding Converter="{StaticResource dpiConverter}">
            <Binding.ConverterParameter>
                 <Thickness Left="7" Top="0" Right="0" Bottom="0"/>
            </Binding.ConverterParameter>
        </Binding>
     </TextBox.Margin>
</TextBox>

这两个文本块在其他操作系统上运行良好,但有时在带有 SP3 的 Windows XP Home 版本上会丢失。我们尝试了很多方法来刷新这些,但都失败了。

我们试过了:

  1. 更新布局
  2. 视觉无效
  3. 将代码中的设置文本属性更改为绑定模式。

如何强制这些控件刷新?

【问题讨论】:

  • (x as UIElement).InvalidateMeasure()

标签: wpf controls refresh


【解决方案1】:

在 WPF 中使控件实时更新的方法是通过 TwoWay 数据绑定。因此,请确保您绑定到的所有 viewModel 属性都是依赖属性或实现 INotifyPropertyChanged(并正确处理)并且它们的 Binding.Mode = TwoWay。

查看Rudi Grobler关于 WPF 数据绑定我不知道的 10 件事

一些数据绑定文章:

  1. WPF Data Binding - Part 1乔尔·象牙·约翰逊
  2. Moving Toward WPF Data Binding One Step at a Time乔什·史密斯

【讨论】:

  • 我认为这不能解决问题,因为我们已经尝试过单向绑定。
【解决方案2】:

Thread thread = new Thread(new ThreadStart(delegate()
                {
                    Thread.Sleep(200); // this is important ...
                    try
                    {
                        this.Dispatcher.BeginInvoke(DispatcherPriority.Send,
                            new NoArgsHandle(delegate()
                            {
                               // do something, set .Text = "some text"
                            }));
                    }
                    catch { }
                }));
                thread.Name = "thread-UpdateText";
                thread.Start();

效果很好。

【讨论】:

  • Whats NoArgsHandle 我需要为它创建一个类吗?
  • new Action(()替换new NoArgsHandle(delegate()
【解决方案3】:

这对我们有用,无需创建新线程。它安排动作在所有绑定首先更新自己时开始。

           Application.Current.Dispatcher.BeginInvoke(
                DispatcherPriority.Background,
                new Action(() =>
                    {
                        // Do something here.
                    }));

【讨论】:

    【解决方案4】:

    我长期以来一直在努力解决这个特定问题,看起来 Cooper Wu 提出的建议非常接近最终解决方案,并结合了 Declan Taylor 的评论。在我的情况下它仍然没有完全解决,但它把我带到了这段代码:

    Thread thread = new Thread(new ThreadStart(delegate ()
    {
        Thread.Sleep(200); // this is important ...
        try
        {
            this.Dispatcher.BeginInvoke(DispatcherPriority.Send,
                new Action(delegate ()
                {
                    DoSomething();
                }));
        }
        catch { }
    }));
    thread.Name = "ThreadName";
    thread.Start();
    

    不同之处在于 NoArgsHandle 被 Action 取代,但委托仍然存在。 我对睡眠时间进行了一些调整,但这只会缩短几分之一秒。 我认为 thread.Name 是必要的,以避免获得多个具有相同名称的线程,但忽略它似乎不会导致任何问题。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-04-22
      • 2011-08-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-07-04
      • 1970-01-01
      相关资源
      最近更新 更多