代码之家  ›  专栏  ›  技术社区  ›  Sharun

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

  •  1
  • Sharun  · 技术社区  · 17 年前

    我正在C中构建一个小的WPF应用程序。当一个按钮被点击三分之一 参与方dll函数构造类似树的对象。此对象已绑定 到树视图。这很好,但需要一点时间加载。作为 dll函数构造将进度信息打印到的对象 慰问。我想将此重定向到一个文本块,以便用户 获取以查看进度消息。

    我的窗口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类如下所示。问题是的文本块 在TreeView之前,某些原因不会用消息更新 加载。单步执行时,我看到文本属性正在更新 但文本块没有刷新。我添加了一个消息框。显示 ()在文本更新时,这似乎导致 每次刷新窗口,我都能看到每条消息。所以我 我想我需要某种方法来显式刷新屏幕……但是这个 我认为数据绑定会导致 属性更改时刷新。我这里缺什么?我该怎么办 让它刷新?感谢您的任何建议!

    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 回复  |  直到 14 年前
        1
  •  1
  •   Tim Cooper    14 年前

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

        2
  •  1
  •   Sharun    17 年前

    所以在阅读了WPF线程模型之后( http://msdn.microsoft.com/en-us/library/ms741870.aspx )我最后通过调用调度器invoke()来刷新它,调度器的调度优先级设置为render。正如Kent所建议的,调度程序队列中的UI更新可能是低优先级的。我最后做了这样的事。

    XAML

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

    目标更新处理程序代码

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

    注意:之前我使用的是一个文本块,但随着滚动的出现,我改为文本框。

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

        3
  •  0
  •   Matt Hamilton    17 年前

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

    local.Text = "";
    

    这是有效的 重写 以前为progresstextblock.text设置的值,即:

    {Binding Text}
    

    明白我的意思吗?通过显式设置textBlock的text属性值,您取消了绑定。

    如果我读得对,那么将一个文本块传递到StringRedir的ctor中的想法似乎是您直接尝试绑定之前的遗留问题。我会摒弃这个想法,坚持有约束力的想法,因为它更符合WPF的“精神”。