刷新文本块的WPF问题绑定到console.stdout

时间:2008-12-19 06:06:49

标签: c# wpf user-interface console refresh

我正在用C#构建一个小型的wpf应用程序。按下按钮时,第三个按钮 party dll函数构造一个类似于对象的树。这个对象是绑定的 到树视图。这工作正常但需要一些时间来加载。作为 dll函数构造它打印进度信息的对象 安慰。我想将其重定向到TextBlock以便用户 得到进展信息。

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

InitializeComponent(); 
StringRedir s = new StringRedir(ref ProgressTextBlock); 
Console.SetOut(s); 
Console.SetError(s); 
this.DataContext = s; 

xaml:

<TextBlock Text="{Binding Path=Text}" Width="244" 
x:Name="ProgressTextBlock" TextWrapping="Wrap"  /> 
<TreeView >...</TreeView> 

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

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"); 
    } 


} 

3 个答案:

答案 0 :(得分:1)

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

答案 1 :(得分:1)

因此,在对WPF线程模型(http://msdn.microsoft.com/en-us/library/ms741870.aspx)进行一些阅读之后,我终于通过调用Dispatcher Invoke()并将Dispatch priority设置为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(object sender, DataTransferEventArgs e)
{
    TextBox t = sender as TextBox;
    t.ScrollToEnd();
    t.Dispatcher.Invoke(new EmptyDelegate(() => { }), System.Windows.Threading.DispatcherPriority.Render);
}

注意:早些时候我使用的是TextBlock,但我更改为TextBox,因为它带有滚动

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

答案 2 :(得分:0)

我认为问题出在你的StringRedir类的构造函数中。你正在传递ProgessTextBlock,你正在这样做:

local.Text = "";

这实际上是覆盖以前为ProgressTextBlock.Text设置的值,这是:

{Binding Text}

明白我的意思?通过显式设置TextBlock的Text属性值,您已取消绑定。

如果我正确阅读,看起来将TextBlock传递给StringRedir的ctor的想法是在您尝试直接绑定之前的宿醉。我倾向于坚持并坚持具有约束力的想法,因为它更多地体现在WPF的“精神”中。