如何使用 xaml 将内容动态添加到 wpf 应用程序中的富文本框

how to dynamically add content to a rich text box in a wpf application using xaml

我正在开发一个 GUI,用户可以在其中连接到服务器并读取数据。数据需要显示在 GUI 上。为此,我使用 TabControl,其 ContentTemplate 设置为 RichTextBox。 XAML代码如下

<TabControl x:Name="tabControl1" HorizontalAlignment="Stretch" MinHeight="50" Margin="0,0,0,0.2" Width="884"
                            ItemsSource="{Binding Titles, Mode=TwoWay}" Height="454" VerticalAlignment="Bottom">
                    <TabControl.ItemTemplate>
                        <DataTemplate>
                            <TextBlock Text="{Binding Header}"/>
                        </DataTemplate>
                    </TabControl.ItemTemplate>
                    <TabControl.ContentTemplate>
                        <DataTemplate>
                            <RichTextBox Margin="10" VerticalScrollBarVisibility="Visible" >
                                <FlowDocument>
                                    <Paragraph FontSize="12" FontFamily="Courier New">
                                        <Run Text="{Binding Content}"></Run>
                                    </Paragraph>
                                </FlowDocument>
                            </RichTextBox>
                        </DataTemplate>
                    </TabControl.ContentTemplate>
</TabControl>

添加新标签并设置其header/content(静态)的后台代码如下

    public class MainWindowVM : INotifyPropertyChanged
    {
        public MainWindowVM()
        {
            Titles = new ObservableCollection<Item>();
        }

        public class Item
        {
            public string Header { get; set; }
            public string Content { get; set; }
        }
        public ObservableCollection<Item> Titles
        {
            get { return _titles; }
            set
            {
                _titles = value;
                OnPropertyChanged("Titles");
            }
        }

        static int tabs = 1;
        private ObservableCollection<Item> _titles;
        private ICommand _addTab;
        private ICommand _removeTab;

        public ICommand AddTab
        {
            get
            {
                 _addTab = new TabRelayCommand(
                    x =>
                    {
                        AddTabItem();
                    });
                return _addTab;
            }
        }
        public ICommand RemoveTab
        {
            get
            {
                _removeTab = new TabRelayCommand(
                    x =>
                    {
                        RemoveTabItem();
                    });
                return _removeTab;
            }
        }
        private void RemoveTabItem()
        {
            if (Titles.Count > 0)
            {
                Titles.Remove(Titles.Last());
                tabs--;
            }
        }

        public Item AddTabItem()
        {
            var header = "Log_" + tabs;
            var content = "Content " + tabs;
            var item = new Item { Header = header, Content = content };
            Titles.Add(item);
            tabs++;
            OnPropertyChanged("Titles");
            return item;
        }

        public void AddTabItem(string strFileName, string strContent)
        {
            var header = strFileName;
            var content = strContent;
            var item = new Item { Header = header, Content = content };
            Titles.Add(item);
            tabs++;
            OnPropertyChanged("Titles");
        }


        public event PropertyChangedEventHandler PropertyChanged;
        private void OnPropertyChanged(string propertyName)
        {
            var handler = PropertyChanged;
            handler?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }

    }

不过我需要动态设置header的内容(从socket读取的数据)。我可以读取字符串格式的数据。 请建议我如何通过附加字符串来设置 RichTextBox 的内容。 我是 C# 的新手。提前致谢

编辑: 按钮单击事件后,我的应用程序连接到服务器。我还启动了一个从套接字读取数据的并行任务。

面临的问题: 花费了太多 CPU 时间(我可以在任务管理器中的进程下看到最多 80) .

 private void BtnConnect_Click(object sender, RoutedEventArgs e)
        {
            //connect
            TCPClientClass tcpClient = TCPConnHandler.ConnectToService(tbIPAddress.Text);
            if (tcpClient != null)
            {
                MessageBox.Show("Connected to " + tbIPAddress.Text);
                //open new tab
                var item = MainWindowVMObj.AddTabItem();


                //now run a task to display the data in the tab
                Thread thTabControl = new Thread(() =>
                {
                    while (tcpClient.Connected)
                    {
                        String str = tcpClient.GetDataFromServer();
                        if (!String.IsNullOrEmpty(str))
                            tabControl1.Dispatcher.BeginInvoke((Action)(() => item.Content += str));
                        Thread.Sleep(200);
                    }
                    //item.Dispatcher.BeginInvoke
                });

                thTabControl.Start();
            }

        }

您可以在 Titles 中查找要更新的 Item 并设置其 Content 属性。

例如,这会设置 ObservableCollection<Item> 中第一项(索引 0)的 属性:

Titles[0].Content += "append...";

Item class 也应该实现 INotifyPropertyChanged 以便您在不切换标签的情况下看到更改:

public class Item : INotifyPropertyChanged
{
    public string Header { get; set; }

    private string _content;
    public string Content
    {
        get { return _content; }
        set { _content = value; OnPropertyChanged(nameof(Content)); }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    private void OnPropertyChanged(string propertyName)
    {
        var handler = PropertyChanged;
        handler?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}