I am developing a GUI where a user can connect to server and read the data. The data needs to be displayed on the GUI. For this I am using TabControl whose ContentTemplate is set to RichTextBox. The XAML code is as below
<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>
The background code for adding new tab and setting its header/content (static) is below
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));
}
}
However I need to set the content of the header dynamically (the data read from the socket). I can read the data I have it in string format. Kindly suggest me how do I set the content of RichTextBox by appending the string. I am new to C#. Thanks in advance
Edit: After button click event, my application gets connected to the server. Also I start a parallel task which reads data from the socket.
Problem facing: Too much of CPU time taken (I can see upto 80 under Processes in Task Manager).
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();
}
}
You could look up the Item
to update in Titles
and set its Content
property.
For example, this sets the property of the first item (index 0) in the ObservableCollection<Item>
:
Titles[0].Content += "append...";
The Item
class should also implement INotifyPropertyChanged
for you to see the changes without switching tabs:
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));
}
}