How to Write inside a Dock Content in C# - c#

There is a DockPanel and when I exercise this code it adds the dock content to the right Dock BUT I can't get it to show the text (i.e. Perform Step1 and Step2 etc. as seen below). I have done so much research, nothing has worked. Thanks in advance for your help.
public void ShowInstructionForm()
{
dragDropForm = new DockContent();
dragDropForm.Name = "Hints";
dragDropForm.TabText = "Hints2";
dragDropForm.ShowHint = DockState.DockRight;
dragDropForm.BackColor = Color.White;
dragDropForm.Text = "- Perform the step number 1 ."
+ Environment.NewLine + " - Perform the Step number 2";
try
{
dragDropForm.Show(this.oDock.MainDock);
}
catch (Exception e)
{
MessageBox.Show(this.oDock.MainDock, "error happened " + e.Message);
}
}

Personally I would use data binding to achieve what it is you want so that you are adhering to a more rigid design pattern.
XAML
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525"
DataContext="{Binding RelativeSource={RelativeSource Self}}">
<DockPanel>
<TextBlock Text="{Binding Path=Foo}" />
</DockPanel>
</Window>
C#
public partial class MainWindow : Window
{
public string Foo { get; set; }
public MainWindow()
{
Foo = "hello world"; // Changing Foo 'automagically' changes your textblock value
InitializeComponent();
}
}
This allows you to be more flexible by having your business logic separated from your UI code. Obviously this is just an example of data binding with a text block inside a dock panel but hopefully this gives you a better understanding.

Can you go into xaml and place a textblock in in the DockPanel like this:
<DockPanel>
<TextBlock Text="- Perform the step number 1 ."/>
</DockPanel>

Related

using C# Format colour of line in RichTextBox based on the content of the string

I am using C# for the first time and my goal is to create an application that outputs text to a window. The windows structure is defined in a .XAML file and the text in question is to be added to a RichTextBox. Depending on the content of the string to be appended I want the text color to be different. I.E if the string contains the word "passed" I want the text to be green and red if it contains "failed". I have found a method that almost works but instead changes the color of all the text in the box instead of just the desired line.
The name of the RichTextBox is "TextResults" as shown below:
I have used the ForeGround property and assigned it to a SolidColorBrush object
if (dispText[1].Contains("passed")) textResults.Foreground = new SolidColorBrush(Colors.Green);
else if (dispText[1].Contains("failed")) textResults.Foreground = new SolidColorBrush(Colors.Red);
else textResults.Foreground = new SolidColorBrush(Colors.Black);
textScript.AppendText(dispText[0] + Environment.NewLine);
textResults.AppendText(dispText[1] + Environment.NewLine);
The problem is, this method applies the color to all strings in the RichTextBox, so assuming the final string contains "failed", all the text goes red.
I have looked online at lots of different methods and none seem to help, this is my first stack overflow post so apologies if I have committed any sins in this post. Any help would be much appreciated.
Use this simple Example, with MainWindow.xaml.cs:
using System.Windows.Documents;
using System.Windows.Media;
namespace Stack2
{
public partial class MainWindow
{
public MainWindow()
{
InitializeComponent();
AppendTextWithColor("Text1 Req passed",Brushes.Blue);
AppendText("New status eq");
AppendText("Text1 Req failed");
AppendText("Text1 Req passed");
AppendText("New status eq");
AppendText("New status failed");
}
private void AppendText(string text)
{
Paragraph par = new Paragraph(new Run(text));
if (text.Contains("passed"))
{
par.Foreground = Brushes.Blue;
} else if (text.Contains("failed"))
{
par.Foreground = Brushes.Red;
}
else
{
par.Foreground = Brushes.Black;
}
textResults.Document.Blocks.Add(par);
}
private void AppendTextWithColor(string text, Brush c)
{
Paragraph par = new Paragraph(new Run(text));
par.Foreground = c;
textResults.Document.Blocks.Add(par);
}
}
}
And MainWindow.xaml:
<Window x:Class="Stack2.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Stack2"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<StackPanel>
<RichTextBox x:Name="textResults">
<FlowDocument>
<Paragraph>
This is flow content and you can <Bold>edit me!</Bold>
</Paragraph>
</FlowDocument>
</RichTextBox>
</StackPanel>
</Grid>
</Window>
public static class WpfHelperExtensions
{
public static void AppendColoredText(this RichTextBox box, string text, Color color)
{
var range = new TextRange(box.Document.ContentEnd, box.Document.ContentEnd)
{
Text = text
};
range.ApplyPropertyValue(TextElement.ForegroundProperty, new SolidColorBrush(color));
box.ScrollToEnd();
}
}
Usage
if (dispText[1].Contains("passed"))
textResults.AppendColoredText(dispText[1], new SolidColorBrush(Colors.Green));
else if (dispText[1].Contains("failed"))
textResults.AppendColoredText(dispText[1], new SolidColorBrush(Colors.Red));
else
textResults.AppendColoredText(dispText[1], new SolidColorBrush(Colors.Black));

How to multicolor row text in listbox C#?

i wanna do a log lister app in C#. I have a listbox called LogBox and i wanna color multiple times a row. like: "[04:30:20] - Admin: Hello" but each variable should be different color at row in Listbox.
How should i do this with button action?
I tried LogBox.Items.Add(LogBox.ForeColor = color.red + "[" etc etc etc. but its doesn't work.
I guess you might be looking for something like this.
It can be easily achieved if you have a model class which is bound to your ListBox.
Follow the below steps
Step 1 - Create a model class, say suppose "ListBoxItemModel.cs"
public class ListBoxItemModel
{
public string Text { get; set; }
public Brush ForegroundBrush { get; set; }
}
Note:- I am not following any MVVM approach here for demo. If you are familiar then you can implement with this code.
Step 2 - Create a window with ListBox and define a DataTemplate for your Model class as below in your MainWindow.
Assign the DataTemplate to your ListBox ItemTemplate property.
<Window x:Class="SO61263305.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:SO61263305"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.Resources>
<DataTemplate x:Key="LocalTemplate" DataType="local:ListBoxItemModel">
<TextBlock Text="{Binding Text}" Foreground="{Binding ForegroundBrush}" />
</DataTemplate>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<ListBox x:Name="ItemsListBox" Grid.Row="0" Height="200" Width="200"
ItemTemplate="{StaticResource LocalTemplate}"/>
</Grid>
Step 3 - Create an List of "ListBoxItemModel" and bound to ListBox from code-behind of your window or user control. In my case it is MainWindow.xaml.cs
private void LoadDataObjects()
{
var items = new List<ListBoxItemModel>();
var item = new ListBoxItemModel()
{
Text = "John ABCD 1",
ForegroundBrush = new SolidColorBrush(Color.FromRgb(0, 0, 0))
};
items.Add(item);
item = new ListBoxItemModel()
{
Text = "John ABCD 2",
ForegroundBrush = new SolidColorBrush(Color.FromRgb(200, 79, 24))
};
items.Add(item);
ItemsListBox.ItemsSource = items;
}
In the above method you need to add each item with the Text which you wanted to display and Foreground Brush.
Step 4 - Call above method from your constructor of code-behind or else you can call from any other events like Button click to load the data to a listbox.
See below of my complete MainWindow.xaml.cs (code behind of the MainWindow)
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
LoadDataObjects();
}
private void LoadDataObjects()
{
var items = new List<ListBoxItemModel>();
var item = new ListBoxItemModel()
{
Text = "John ABCD 1",
ForegroundBrush = new SolidColorBrush(Color.FromRgb(0, 0, 0))
};
items.Add(item);
item = new ListBoxItemModel()
{
Text = "John ABCD 2",
ForegroundBrush = new SolidColorBrush(Color.FromRgb(200, 79, 24))
};
items.Add(item);
ItemsListBox.ItemsSource = items;
}
}
Hope this should give you some idea and you can improve your requirements on top of it.
Give a try and let us know in case if you face any difficulties.

Card View material design in Windows Universal Apps

I want to develop a Blog application similar design like Universal MSN News App of Microsoft. I want similar design like shown in picture below.
I looked into this News app and found that lots of cool features is integreted with Pivot design.
Few Questions I have:
How do I make dynamic card view layout like this in News app. This app has
dynamic Grid View. Some GridView are bigger some are small. How do we adjust these grid view next to each other
even if they have different heights. Are there any samples for this?
Lazy Loading is implemented to load the feeds when we scroll down.
Any idea how to get work done for lazy loading.
Thank you. Any help is appreciated.
You could use some third-party library: The-UWP-Tools-List
It's easy to integrate Marduk.Controls by the following command:
PM> Install-Package Marduk.Controls
You could see my code sample:
<Page
x:Class="App1.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:App1"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:controls="using:Marduk.Controls"
mc:Ignorable="d">
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<ScrollViewer>
<controls:WaterfallFlowView x:Name="Panel" ItemSource="{Binding cc}" StackCount="3" DelayMeasure="True">
<controls:WaterfallFlowView.Resizer>
<local:MyItemResizer/>
</controls:WaterfallFlowView.Resizer>
<controls:WaterfallFlowView.ItemContainerStyle>
<Style TargetType="ContentControl">
<Setter Property="HorizontalAlignment" Value="Stretch"></Setter>
<Setter Property="HorizontalContentAlignment" Value="Stretch"></Setter>
</Style>
</controls:WaterfallFlowView.ItemContainerStyle>
<controls:WaterfallFlowView.ItemTemplate>
<DataTemplate>
<Border Height="{Binding Length}" Background="{Binding Brush}" HorizontalAlignment="Stretch">
<TextBlock FontSize="50" Text="{Binding Num}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</DataTemplate>
</controls:WaterfallFlowView.ItemTemplate>
</controls:WaterfallFlowView>
</ScrollViewer>
</Grid>
public sealed partial class MainPage : Page
{
public ObservableCollection<Test> cc { get; set; }
public MainPage()
{
this.InitializeComponent();
cc = new ObservableCollection<Test>();
cc.Add(new Test() {Length=200,Brush= new SolidColorBrush(Colors.Red),Num=1 });
cc.Add(new Test() { Length = 150, Brush = new SolidColorBrush(Colors.Blue), Num = 2 });
cc.Add(new Test() { Length = 100, Brush = new SolidColorBrush(Colors.LightCyan), Num = 3 });
cc.Add(new Test() { Length = 50, Brush = new SolidColorBrush(Colors.SandyBrown), Num = 4 });
this.DataContext = this;
}
}
public class Test
{
public double Length { get; set; }
public SolidColorBrush Brush { get; set; }
public int Num { get; set; }
}
public class MyItemResizer : IItemResizer
{
public Size Resize(object item, Size oldSize, Size availableSize)
{
return new Size(availableSize.Width, oldSize.Height);
}
}
UWPCommunityToolkit
Custom-sized grids
Create your own widget (extend the base widget class) to represent a single grid. The size of the grid will be decided by the amount of text in it or any other factor you wish.
Use a table or grid layout. For Gtk+, see here: https://developer.gnome.org/gtk3/stable/GtkGrid.html
Attach your custom widgets to the layout.
Lazy loading
The scrolling widget of all toolkits I know emit a signal when the user reaches the bottom (or top or left edge or right edge).
Catch that signal and add more custom grid widgets to the layout. You might need to redisplay the contents of the layout which is a bit inefficient; use multithreading perhaps.
In Gtk+ 3, edge-reached is emitted by ScrolledWindow when any of the edge is reached.
This is the general concept. A quick Google search will reveal how your choice of GUI toolkit does the above.

Dynamic UI Layout in DataGridCell using ItemsControl and a Button

This screenshot is from the mockup of my ideal UI. Right now, this is a DataGridTemplateColumn, with header = "ATTENDEES". I am running into issues creating the layout of this DataGridColumn's cell.
I currently have an ItemsControl bound to a List of strings which are the attendees' emails. If there are too many attendees and the ItemsControls' bounds cannot fit in the cell, then a Button with Content = "See more" should appear at the bottom of the cell, under the last attendee email that can be rendered within in the cell's bounds.
Then once the Button ("See more") is clicked, the row should expand to an appropriate height for the attendees to all be visible, and the "See more" Button should disappear.
I could not wrap my head around a clean implementation with a TemplateSelector, ValueConverter, or DataTrigger in pure XAML since I need to compare the ItemsControls' height against the DataGridRow's height and then perform a modification of the cell's layout at runtime by hiding all the items in the ItemsControl that cannot fit within the cell and then showing at Button below it.
I concluded on attempting to do this in the code-behind by subscribing to the ItemControls' load event. I first attempted to use the Height, MaxHeight, DesiredSize.Height, RenderedSize.Height, and ActualSize.Height properties of the ItemsControl but those all were equal to the clipped height of the ItemsControl, not the intrinsic height of all its contents.
I am now measuring the total height of all its items' strings using the FormattedText class. Then I compare this summed height with the row's height and that's as far as I have progressed; I am unsure of how to next change the layout of the cell or if this is even the correct approach.
I feel like I am fighting against the design of the WPF framework by doing rudimentary calculations and crude layout changes to the view in the code-behind.
Any help on this would be greatly appreciated!
Here is my event handler for the ItemsControl.Load:
private void AttendeesItemsControl_Loaded(object sender, RoutedEventArgs e)
{
if (currentRowIndex == -1)
{
return;
}
List<ModelBase> eventsData = ModelManager.events.data;
var eventObj = (Event)eventsData[currentRowIndex];
var attendees = eventObj.attendees;
var totalItemsHeight = 0;
for(int i = 0; i < attendees.Count; i++)
{
totalItemsHeight += heightOfString(attendees[i]);
}
var itemsControl = (ItemsControl)sender;
var controlRenderHeight = itemsControl.RenderSize.Height;
// Check if the intrinsic height is greater than what can be drawn inside the cell
if (controlRenderHeight < totalItemsHeight)
{
var itemHeight = totalItemsHeight / attendees.Count;
var visibleItemsCount = controlRenderHeight / itemHeight;
// .... not sure how to proceed
}
}
And the helper function that measures the height of one of its items:
private int heightOfString(string candidate)
{
var fontFamily = new FontFamily("Lato");
var fontStyle = FontStyles.Normal;
var fontWeight = FontWeights.Normal;
var fontStretch = FontStretches.Normal;
var fontSize = 12;
var typeFace = new Typeface(fontFamily, fontStyle, fontWeight, fontStretch);
var formattedText = new FormattedText(candidate, CultureInfo.CurrentUICulture, FlowDirection.LeftToRight, typeFace, fontSize, Brushes.Black);
return (int)formattedText.Height;
}
Finally, this is the DataGridTemplateColumn's XAML, with the cell template definition:
<DataGridTemplateColumn Header="ATTENDEES" Width="*">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ItemsControl ItemsSource="{Binding Path=attendees}" x:Name="AttendeesItemsControl" Loaded="AttendeesItemsControl_Loaded">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock FontFamily="Lato" FontSize="12" FontWeight="Normal" Text="{Binding}">
</TextBlock>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
I had to do some real work but I got this set up. Hopefully you can follow it. Here is a screen shot of what it looks like. Obviously i didn't attempt to style it yet. Just getting the resizing. This way you let WPF handle the height of your control you leave it autosized. You just manage your list.
I created a control for the list called AttendeeListControl
<UserControl xmlns:stackoverflow="clr-namespace:stackoverflow" x:Class="stackoverflow.AttendeeListControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid Background="GhostWhite">
<Grid.RowDefinitions>
<RowDefinition Height="37"/>
<RowDefinition Height="*"/>
<RowDefinition Height="23"/>
</Grid.RowDefinitions>
<Label Content="Attendees" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top"/>
<ListBox Name="listBoxAttendees" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Grid.Row="1" />
<Button Content="SeeMore" Name="lblMore" HorizontalAlignment="Left" Margin="10,0,0,0" Grid.Row="2" VerticalAlignment="Top" Click="lblMore_Click"/>
</Grid>
</UserControl>
This is the code behind
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Windows.Controls;
namespace stackoverflow
{
/// <summary>
/// Interaction logic for AttendeeListControl.xaml
/// </summary>
///
public partial class AttendeeListControl : UserControl
{
public AttendeeListViewModel vm { get; set; }
public AttendeeListControl()
{
InitializeComponent();
var emails = new List<string>() { "email#gmail.com", "email#aol.com", "email.yahoo.com", "email#msn.com" };
var displayed = new ObservableCollection<string>() { emails[0], emails[1] };
vm = new AttendeeListViewModel()
{
EmailList = emails,
DisplayList = displayed,
Expanded = false
};
DataContext = vm;
listBoxAttendees.ItemsSource = vm.DisplayList;
}
private void lblMore_Click(object sender, System.Windows.RoutedEventArgs e)
{
if (vm.Expanded)
{
//remove all but last 2
do
{
vm.DisplayList.RemoveAt(vm.DisplayList.Count - 1);
} while (vm.DisplayList.Count > 2);
lblMore.Content = "Show More";
}
else
{
//don't want the first 2
for (int i = 2; i < vm.EmailList.Count; i++)
{
vm.DisplayList.Add(vm.EmailList[i]);
}
lblMore.Content = "Show Less";
}
vm.Expanded = !vm.Expanded;
}
}
}
and here is the model i used
using System.Collections.Generic;
using System.Collections.ObjectModel;
namespace stackoverflow
{
public class AttendeeListViewModel
{
public bool Expanded { get; set; }
public List<string> EmailList { get; set; }
public ObservableCollection<string> DisplayList { get; set; }
}
}
this was all just put on the mainwindow
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:stackoverflow" x:Class="stackoverflow.MainWindow"
Title="MainWindow" Height="350" Width="525">
<Grid>
<local:AttendeeListControl HorizontalAlignment="Left" Margin="55,53,0,0" VerticalAlignment="Top"/>
<local:AttendeeListControl HorizontalAlignment="Left" Margin="340,53,0,0" VerticalAlignment="Top"/>
</Grid>
</Window>

FlowDocument and XamlReader x:Class

In my MainWindow I have a FlowDocumentScrollViewer binding its property Document to a FlowDocument in my MainViewModel.
This document is loaded from an external xaml file store on a remote computer. Currently I'm able to load this document properly via XamlReader.Load(xamlfile) and display it in the FlowDocumentScrollViewer. So far so good.
The problem occurs when I try to add hyperlink in this document. Because to handle the RequestNavigate event I need a x:Class. For the time being this Class need to be my MainWindow because the event is handle in the code-behind. Obviously when I add x:Class="Ugrader.MainWindow" in my external document I get a lovely 'System.Windows.Markup.XamlParseException' at the moment of parsing.
So is there a way to solve this ?
Here is piece of my code
MainWindow.xaml
<Window x:Class="Ugrader.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Geco3-Upgrading version"
WindowStyle="none" ResizeMode="NoResize" ShowInTaskbar="False" WindowStartupLocation="CenterScreen"
Height="400" Width="700"
DataContext="{Binding Main,Source={StaticResource Locator}}">
<FlowDocumentScrollViewer Grid.Column="1" Background="{x:Null}" VerticalScrollBarVisibility="Hidden"
Document="{Binding WhatsNewDoc}"/>
</Window>
MainViewModel.cs
namespace Ugrader.ViewModel
{
public class MainViewModel : ViewModelBase
{
#region Constructor
public MainViewModel()
{
try
{
FileStream xamlFile = new FileStream(updateLocation + "whatsnew.xaml", FileMode.Open, FileAccess.Read);
FlowDocument current = System.Windows.Markup.XamlReader.Load(xamlFile) as FlowDocument;
WhatsNewDoc = current;
}
catch (Exception)
{
}
}
#endregion
#region Properties
private FlowDocument _watsNewDoc = new FlowDocument();
public FlowDocument WhatsNewDoc
{
get
{
return _watsNewDoc;
}
set
{
if(_watsNewDoc != value)
{
_watsNewDoc = value;
RaisePropertyChanged("WhatsNewDoc");
}
}
}
#endregion
}
}
The external FlowDocument
<FlowDocument x:Class="Ugrader.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
ColumnWidth="400" FontSize="12" FontFamily="Century Gothic" Foreground="LightGray">
<Paragraph>
<Italic>
For additionnal information, please watch this
<Hyperlink TextDecorations="{x:Null}" RequestNavigate="Hyperlink_Clicked" NavigateUri="path_to_the_file" >video</Hyperlink>
</Italic>
</Paragraph>
</FlowDocument>
By the way, is there a way to handle this parse exception (in case of bad external file), because even in this try/catch block, this stop my program.
Thanks you in advance,
Bastien.
I find a way to deal with my problem, it's not really beautiful, do not respect the spirit of mvvm, but well, this is working.
So, as it's not possible to add x:Class at runtime (I guess), I came to the idea of handling the RequestNavigate event of each Hyperlinkat runtime. So the solution is pretty simple (and dirty).
In code-behind (yeah I know, it's ugly), on the MainWindow loaded event, I find all hyperlinks in my document, and handle each RequestNavigate events. As simple (and dirty) as this.
Here is some code :
private void Window_Loaded(object sender, RoutedEventArgs e)
{
var hyperlinks = GetVisuals(this).OfType<Hyperlink>();
foreach (var link in hyperlinks)
link.RequestNavigate += link_RequestNavigate;
}
public static IEnumerable<DependencyObject> GetVisuals(DependencyObject root)
{
foreach (var child in LogicalTreeHelper.GetChildren(root).OfType<DependencyObject>())
{
yield return child;
foreach (var descendants in GetVisuals(child))
yield return descendants;
}
}
If someone has a better solution, I take it.

Categories

Resources