Convert MaterialDesignColors.MaterialDesignColor to SolidColorBrush? - wpf

I am using this MaterialDesign library in my C# WPF application.
How can I programatically get the HEX color ID for example from the color MaterialDesignColors.MaterialDesignColor.LightBlue500 and then convert it to a SolidColorBrush?

In general, you can get any MaterialDesignColor using the SwatchHelper.
var lightBlue500Color = SwatchHelper.Lookup[MaterialDesignColor.LightBlue500];
You can also get it directly from the corresponding swatch, here LightBlueSwatch.
var lightBlue500Color = LightBlueSwatch.LightBlue500;
var lightBlueSwatch = new LightBlueSwatch();
var lightBlue500Color = lightBlueSwatch.Lookup[MaterialDesignColor.LightBlue500];
From that color, you can create a SolidColorBrush using its constructor.
var lightBlue500SolidColorBrush = new SolidColorBrush(lightBlue500Color);
If you need the hex color string in #AARRGGBB format, you can use the ToString method of Color.
var lightBlue500HexString= LightBlueSwatch.LightBlue500.ToString(); // = "#FF03A9F4"
If you need the #RRGGBB format, you can use a custom format string.
var lightBlue500Color = LightBlueSwatch.LightBlue500;
var lightBlue500HexString = string.Format("#{0:X2}{1:X2}{2:X2}", lightBlue500Color.R, lightBlue500Color.G, lightBlue500Color.B); // = "#03A9F4"
In general, if you want to create a solid color brush from a hex string, you can do this.
var lightBlue500Color = (Color)ColorConverter.ConvertFromString(#FF03A9F4);
var lightBlue500SolidColorBrush = new SolidColorBrush(lightBlue500Color);

Related

Geometry.Combine doesn't work for curves

I want to combine 2 curves like this:
Then here is my code:
// Create a path to draw a geometry with.
Path myPath = new Path();
myPath.Stroke = Brushes.Black;
myPath.StrokeThickness = 1;
var gmy1 = (StreamGeometry)StreamGeometry.Parse("M100,100C110,118.333333333333 138.333333333333,206.666666666667 160,210 181.666666666667,213.333333333333 205,123.333333333333 230,120 255,116.666666666667 280,186.666666666667 310,190 340,193.333333333333 396.666666666667,156.666666666667 410,140 423.333333333333,123.333333333333 393.333333333333,98.3333333333333 390,90");
var gmy2 = (StreamGeometry)StreamGeometry.Parse("M180,241.25L180,241.25 230,290 300,246.66667175293 330,160");
var gmy = Geometry.Combine(gmy1, gmy2, GeometryCombineMode.Union, null);
myPath.Data = gmy;
// Add path shape to the UI.
this.panel1.Children.Add(myPath);
But the result is this:
How to combine the curves in WPF?
And because of the project limitation, we have to implement this without layout and xaml. That means we need the result type is Geometry.
More general than concatenating path strings:
If you have a set of arbitrary Geometries and want to group them, use a GeometryGroup:
Geometry gmy1 = ...;
Geometry gmy2 = ...;
var gmy = new GeometryGroup();
gmy.Children.Add(gmy1);
gmy.Children.Add(gmy2);
myPath.Data = gmy;
Easy:
Path myPath = new Path();
myPath.Stroke = Brushes.Black;
myPath.StrokeThickness = 1;
var gmy1 = (StreamGeometry)StreamGeometry.Parse("M100,100C110,118.333333333333 138.333333333333,206.666666666667 160,210 181.666666666667,213.333333333333 205,123.333333333333 230,120 255,116.666666666667 280,186.666666666667 310,190 340,193.333333333333 396.666666666667,156.666666666667 410,140 423.333333333333,123.333333333333 393.333333333333,98.3333333333333 390,90");
var gmy2 = (StreamGeometry)StreamGeometry.Parse("M180,241.25L180,241.25 230,290 300,246.66667175293 330,160");
var gmy = (StreamGeometry)StreamGeometry.Parse(gmy1.ToString() + gmy2.ToString());
myPath.Data = gmy;
// Add path shape to the UI.
this.panel1.Children.Add(myPath);
The path definition language is a language. Use it as one. StreamGeometry.ToString() unparses a Geometry back to its Path Definition Language representation, which you can then merge with another one.
Note that this works because each starts with a M for Move command: It starts a new line. I don't think there's any realistic case where you'd run into any trouble with that (and it won't let you start with L for Line), but theory's not exactly my strongest subject.
Just add both of them to a Grid or Canvas, Combine does a intersecting combination, you just seem to want to overlay them. Alternatively add both of them to a GeometryGroup and add that to your panel.

How can I set a value for TextBox.FontFamily property?

I am trying to learn WPF, the problem is I need to learn XAML first. In System.Windows.Controls.TextBox class, there is property 'FontFamily'. I will have to set a font for it. In one of my book I saw But where can I get this font(Verdana). Where is list of all font's in MSDN Library?
Ikbal Hassan
You can bind to the string name of the font as shown below as font.Name. The following code is loading up a ComboBox of all the fonts.
var installedfonts = new InstalledFontCollection();
int idFont = 0;
foreach ( var font in installedfonts.Families )
{
var fonttype = new LookupSelectItem { Id = idFont, Name = font.Name };
FontTypeList.Add( fonttype );
++ idFont;
}

How do you format in code AxisLabel for DependentRangeAxis?

I cannot get the axis to format as currency, any idea?
What am I doing wrong? I need to be able to change the formatting on the fly and for this test I wanted to set it as currency for the Y axis on the scale of values.
Anyone?
Thanks...
var columnSeries = new ColumnSeries
{ Title = reportProcedureNode.Value,
IndependentValuePath = "PrimaryKey",
DependentValuePath = "Value",
IndependentAxis = new CategoryAxis { Orientation = AxisOrientation.X, ShowGridLines = false, Location = AxisLocation.Bottom},
DependentRangeAxis = new LinearAxis(){Orientation = AxisOrientation.Y, ShowGridLines = false}
};
var labelStyle = new Style(typeof(AxisLabel));
labelStyle.Setters.Add(new Setter(AxisLabel.StringFormatProperty, "{}{0:C0}"));
var axis = (LinearAxis)columnSeries.DependentRangeAxis;
axis.AxisLabelStyle = labelStyle;
In my WPF4 version of the charting toolkit, your code crashes. I needed to change:
labelStyle.Setters.Add(new Setter(AxisLabel.StringFormatProperty, "{}{0:C0}"));
to:
labelStyle.Setters.Add(new Setter(AxisLabel.StringFormatProperty, "{0:C0}"));
That is, remove the {}. The {} comes from markup extension syntax:
{} Escape Sequence / Markup Extension
and is only needed when being parsed by XAML as a markup extension inside "{...}".
Since you are setting the property directly, no markup extension is involved and including it prevents the real currency format from being seen.

How to format specific text in WPF?

I have this code that adds dotted lines under text in text box:
// Create an underline text decoration. Default is underline.
TextDecoration myUnderline = new TextDecoration();
// Create a linear gradient pen for the text decoration.
Pen myPen = new Pen();
myPen.Brush = new LinearGradientBrush(Colors.White, Colors.White, new Point(0, 0.5), new Point(1, 0.5));
myPen.Brush.Opacity = 0.5;
myPen.Thickness = 1.0;
myPen.DashStyle = DashStyles.Dash;
myUnderline.Pen = myPen;
myUnderline.PenThicknessUnit = TextDecorationUnit.FontRecommended;
// Set the underline decoration to a TextDecorationCollection and add it to the text block.
TextDecorationCollection myCollection = new TextDecorationCollection();
myCollection.Add(myUnderline);
PasswordSendMessage.TextDecorations = myCollection;
My problem is I need only the last 6 characters in the text to be formatted!
Any idea how can I achieve that?
Instead of setting the property on the entire TextBlock, create a TextRange for the last six characters and apply the formatting to that:
var end = PasswordSendMessage.ContentEnd;
var start = end.GetPositionAtOffset(-6) ?? PasswordSendMessage.ContentStart;
var range = new TextRange(start, end);
range.ApplyPropertyValue(Inline.TextDecorationsProperty, myCollection);
If PasswordSendMessage is a TextBox rather than a TextBlock, then you cannot use rich text like this. You can use a RichTextBox, in which case this technique will work but you will need to use PasswordSendMessage.Document.ContentEnd and PasswordSendMessage.Document.ContentStart instead of PasswordSendMessage.ContentEnd and PasswordSendMessage.ContentStart.
You could databind your text to the Inlines property of TextBox and make a converter to build the run collection with a seperate Run for the last 6 characters applying your decorations

Printing a WPF FlowDocument

I'm building a demo app in WPF, which is new to me. I'm currently displaying text in a FlowDocument, and need to print it.
The code I'm using looks like this:
PrintDialog pd = new PrintDialog();
fd.PageHeight = pd.PrintableAreaHeight;
fd.PageWidth = pd.PrintableAreaWidth;
fd.PagePadding = new Thickness(50);
fd.ColumnGap = 0;
fd.ColumnWidth = pd.PrintableAreaWidth;
IDocumentPaginatorSource dps = fd;
pd.PrintDocument(dps.DocumentPaginator, "flow doc");
fd is my FlowDocument, and for now I'm using the default printer instead of allowing the user to specify print options. It works OK, except that after the document prints, the FlowDocument displayed on screen has changed to to use the settings I specified for printing.
I can fix this by manually resetting everything after I print, but is this the best way? Should I make a copy of the FlowDocument before I print it? Or is there another approach I should consider?
yes, make a copy of the FlowDocument before printing it. This is because the pagination and margins will be different. This works for me.
private void DoThePrint(System.Windows.Documents.FlowDocument document)
{
// Clone the source document's content into a new FlowDocument.
// This is because the pagination for the printer needs to be
// done differently than the pagination for the displayed page.
// We print the copy, rather that the original FlowDocument.
System.IO.MemoryStream s = new System.IO.MemoryStream();
TextRange source = new TextRange(document.ContentStart, document.ContentEnd);
source.Save(s, DataFormats.Xaml);
FlowDocument copy = new FlowDocument();
TextRange dest = new TextRange(copy.ContentStart, copy.ContentEnd);
dest.Load(s, DataFormats.Xaml);
// Create a XpsDocumentWriter object, implicitly opening a Windows common print dialog,
// and allowing the user to select a printer.
// get information about the dimensions of the seleted printer+media.
System.Printing.PrintDocumentImageableArea ia = null;
System.Windows.Xps.XpsDocumentWriter docWriter = System.Printing.PrintQueue.CreateXpsDocumentWriter(ref ia);
if (docWriter != null && ia != null)
{
DocumentPaginator paginator = ((IDocumentPaginatorSource)copy).DocumentPaginator;
// Change the PageSize and PagePadding for the document to match the CanvasSize for the printer device.
paginator.PageSize = new Size(ia.MediaSizeWidth, ia.MediaSizeHeight);
Thickness t = new Thickness(72); // copy.PagePadding;
copy.PagePadding = new Thickness(
Math.Max(ia.OriginWidth, t.Left),
Math.Max(ia.OriginHeight, t.Top),
Math.Max(ia.MediaSizeWidth - (ia.OriginWidth + ia.ExtentWidth), t.Right),
Math.Max(ia.MediaSizeHeight - (ia.OriginHeight + ia.ExtentHeight), t.Bottom));
copy.ColumnWidth = double.PositiveInfinity;
//copy.PageWidth = 528; // allow the page to be the natural with of the output device
// Send content to the printer.
docWriter.Write(paginator);
}
}
You can use the code from the URL below, it wraps the flow document in a fixed document and prints that, the big advantage is that you can use it to add margin, headers and footers.
https://web.archive.org/web/20150502085246/http://blogs.msdn.com:80/b/fyuan/archive/2007/03/10/convert-xaml-flow-document-to-xps-with-style-multiple-page-page-size-header-margin.aspx
The following works with both text and non-text visuals:
//Clone the source document
var str = XamlWriter.Save(FlowDoc);
var stringReader = new System.IO.StringReader(str);
var xmlReader = XmlReader.Create(stringReader);
var CloneDoc = XamlReader.Load(xmlReader) as FlowDocument;
//Now print using PrintDialog
var pd = new PrintDialog();
if (pd.ShowDialog().Value)
{
CloneDoc.PageHeight = pd.PrintableAreaHeight;
CloneDoc.PageWidth = pd.PrintableAreaWidth;
IDocumentPaginatorSource idocument = CloneDoc as IDocumentPaginatorSource;
pd.PrintDocument(idocument.DocumentPaginator, "Printing FlowDocument");
}
I am also generating a WPF report off a Flow document, but I am purposely using the flow document as a print preview screen. I there for want the margins to be the same. You can read about how I did this here.
In your scenario I'm thinking why not just make a copy of your settings, instead of the entire flow document. You can then re-apply the settings if you wish to return the document back to it's original state.

Resources