1

我正在用 C# 构建一个小型 wpf 应用程序。当单击按钮时,第三方 dll 函数会构造一个树状对象。此对象绑定到树视图。这工作正常,但需要一些时间来加载。当 dll 函数构造对象时,它将进度信息打印到控制台。我想将此重定向到 TextBlock 以便用户看到进度消息。

我的窗口 ctor 看起来像这样:

初始化组件();
StringRedir s = new StringRedir(ref ProgressTextBlock);
Console.SetOut(s);
Console.SetError(s);
this.DataContext = s;

xml:

<TextBlock 文本="{绑定路径=文本}" 宽度="244"
x:Name="ProgressTextBlock" TextWrapping="Wrap" />
<树视图 >... </树视图 > 

StringRedir 类如下所示。问题是 TextBlock 出于某种原因在加载 TreeView 之前不会更新消息。单步执行我看到 Text 属性正在更新,但 TextBlock 没有得到刷新。我在 Text 被更新的地方添加了一个 MessageBox.Show () ,这似乎导致窗口每次都刷新并且我能够看到每条消息。所以我想我需要一些方法来显式刷新屏幕......但这没有意义我认为当属性更改时数据绑定会导致视觉刷新。我在这里想念什么?如何让它刷新?任何建议表示赞赏!

public class StringRedir : StringWriter , INotifyPropertyChanged 
{ 
    private string text; 
    private TextBlock local; 


    public string Text { 
        get{ return text;} 
        set{ 
            text = text + value; 
            OnPropertyChanged("Text"); 
        } 
    } 


    public event PropertyChangedEventHandler PropertyChanged; 
    protected void OnPropertyChanged(string name) 
    { 
        PropertyChangedEventHandler handler = PropertyChanged; 
        if (handler != null) 
        { 
            handler(this, new PropertyChangedEventArgs(name)); 
        } 
    } 


    public StringRedir(ref TextBlock t) 
    { 
        local = t; 
        Text = ""; 
    } 


    public override void WriteLine(string x) 
    { 
        Text = x +"\n"; 
        //MessageBox.Show("hello"); 
    } 


} 
4

3 回答 3

1

您没有包含为 加载数据的代码TreeView,但我猜它是在 UI 线程上完成的。如果是这样,这将阻止任何 UI 更新(包括对 的更改TextBlock),直到它完成。

于 2008-12-19T09:27:34.393 回答
1

因此,在阅读了 WPF 线程模型 ( http://msdn.microsoft.com/en-us/library/ms741870.aspx ) 之后,我终于通过调用 Dispatcher Invoke() 并将 Dispatch 优先级设置为 Render 来刷新它。正如上面 Kent 建议的那样,调度程序队列中的 UI 更新可能是低优先级的。我最终做了这样的事情。

XAML

<TextBox VerticalScrollBarVisibility="Auto"  
         Text="{Binding Path=Text, NotifyOnTargetUpdated=True}"
         x:Name="test" TextWrapping="Wrap" AcceptsReturn="True" 
         TargetUpdated="test_TargetUpdated"/>

C# 目标更新的处理程序代码

private void test_TargetUpdated(对象发送者,DataTransferEventArgs e)
{
    文本框 t = 作为文本框的发件人;
    t.ScrollToEnd();
    t.Dispatcher.Invoke(new EmptyDelegate(() => { }), System.Windows.Threading.DispatcherPriority.Render);
}

注意:之前我使用的是 TextBlock,但我更改为 TextBox,因为它带有滚动功能

不过,我仍然对整个流程感到不安。有一个更好的方法吗?感谢马特和肯特的评论。如果我有积分会将他们的答案标记为有帮助。

于 2008-12-20T09:42:21.130 回答
0

我相信问题出在 StringRedir 类的构造函数中。您正在传入 ProgessTextBlock,并且正在对它执行以下操作:

local.Text = "";

这有效地覆盖了之前为 ProgressTextBlock.Text 设置的值,即:

{Binding Text}

明白了吗?通过显式设置 TextBlock 的 Text 属性的值,您已经取消了绑定。

如果我没看错,看起来将 TextBlock 传递给 StringRedir 的 ctor 的想法是在您尝试直接绑定之前的遗留问题。我会放弃它并坚持绑定的想法,因为它更多地体现在 WPF 的“精神”中。

于 2008-12-19T06:50:43.103 回答