2008-12-19 75 views
1

我正在C#中构建一个小的WPF应用程序。当一个按钮被点击时,第三个派对dll函数会构造一个像对象一样的树。该对象绑定到树形视图 。这工作正常,但需要一些时间来加载。当 dll函数构造该对象时,它会向 控制台输出进度信息。我想将其重定向到TextBlock,以便用户 可以看到进度消息。WPF问题刷新的文本块绑定到console.stdout

我的窗口构造函数如下所示:

 
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问题,直到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"); 
    } 


} 

回答

1

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

0

我相信问题出在你的StringRedir类的构造函数中。您正在传递ProgessTextBlock,和你这样做是对的:

local.Text = ""; 

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

{Binding Text} 

见我的意思是?通过明确地为TextBlock的Text属性设置一个值,你已经取消了绑定。

如果我正确地阅读,看起来像将TextBlock传递到StringRedir的ctor的想法是在尝试直接绑定之前的宿醉。我会抛弃它,坚持这个约束性的想法,因为它更像WPF的“精神”。

+0

谢谢马特。好吧...这让我真的想到我在用数据绑定做什么:) StringRedir类代码,我在msdn上找到并盲目地假设我需要本地TextBlock引用来传回文本。哇数据绑定...所以多数民众赞成在做什么:) – Sharun 2008-12-19 08:14:20

+0

不要忘了标记这是答案,如果它确实解决了问题。 – 2008-12-19 08:25:31

1

因此,在对WPF线程模型(http://msdn.microsoft.com/en-us/library/ms741870.aspx)进行一些阅读之后,我终于通过调用Dispatching 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,因为它带有滚动

我还是觉得尽管对整个流程感到不安。有一个更好的方法吗? 感谢马特和肯特的评论。如果我有积分,那么他们的答案会很有帮助。