I'm using the DataVisualization charting within WPF and creating a BarSeries in code, but I can't get the numbers formatted on the X axis.
I don't want to do this in XAML because the type of chart can vary according to user selection and it seemed more flexible to do all of this in code rather than having different chart types. The number of data series also fluctuates.
The XAML is just
xmlns:chttk="clr-namespace:System.Windows.Controls.DataVisualization.Charting;assembly=System.Windows.Controls.DataVisualization.Toolkit"
<chttk:Chart Name="DataChart1" Margin="0" Title="{Binding AxisXTitle}" DataContext="{Binding GraphData1}" Style="{StaticResource ChartStyle1}" BorderBrush="Transparent"/>
The code behind is
Dim dataChart As System.Windows.Controls.DataVisualization.Charting.Chart = DataChart1
Dim s As New System.Windows.Controls.DataVisualization.Charting.BarSeries
s.Title = "My Chart"
s.DependentValuePath = "Value"
s.IndependentValuePath = "Key"
s.DataContext = New Binding("[0]")
s.ItemsSource = CType(itm, IEnumerable)
dataChart.Series.Add(s)
The DataContext is a DataSeries.Collection with the data in KeyValuePairs. The values are all Double values.
The graph is displaying, but the values on the axis are un-formatted, e.g. 120000. I have found a few examples pointing at different Axis types and LabelFormat and LabelStyle.Format but I can't find anything that works in the WPF environment in the code behind.
Thanks for the input - I finally managed to get it working with the following code:
Dim n As Integer
dataChart.Series.Clear()
Dim x As New System.Windows.Controls.DataVisualization.Charting.LinearAxis
x.Orientation = DataVisualization.Charting.AxisOrientation.X
Dim y As New System.Windows.Controls.DataVisualization.Charting.CategoryAxis
y.Orientation = DataVisualization.Charting.AxisOrientation.Y
Dim stl As New Style(GetType(System.Windows.Controls.DataVisualization.Charting.AxisLabel))
stl.Setters.Add(New Setter(System.Windows.Controls.DataVisualization.Charting.AxisLabel.StringFormatProperty, "{0:#,0}"))
x.AxisLabelStyle = stl
For Each itm As Object In o
Dim srs As New System.Windows.Controls.DataVisualization.Charting.BarSeries
pi = itm.GetType.GetProperty("SeriesTitle")
srs.Title = pi.GetValue(itm, Nothing)
srs.DependentValuePath = "Value"
srs.IndependentValuePath = "Key"
srs.DataContext = New Binding("[" & n & "]")
srs.ItemsSource = CType(itm, IEnumerable)
srs.DependentRangeAxis = x
srs.IndependentAxis = y
dataChart.Series.Add(srs)
n += 1
Next
Some of the gotchas that tripped me up were adding the axis. You need to add the right type of axis to the DependentRangeAxis or IndependentAxis. With a BarSeries the DependentRangeAxis is the X axis and can be a LinearAxis and the IndependentAxis is the Y axis and for me was a CategoryAxis. Also if you have multiple series then you need to apply the same axis to all series.
Hope this helps someone else.
Related
I define a variable as follows:
x = Color.FromArgb(<some integer>)
and use it as follows when specifying a rectangle:
Dim Cell As New Shapes.Rectangle With
{
.Fill = New SolidColorBrush(x),
'......
}
However, this gives an error message:
Value of type 'Color' cannot be converted to 'Color'
What is wrong here?
There are two different Color types.
System.Drawing.Color (the one that you are using, GDI+)
System.Windows.Media.Color (the one WPF uses)
A SolidColorBrush or brushes in general in WPF expect the latter type.
Public Sub New (color As Color)
Unfortunately, this type does not have an overload for a single int, which means you have to convert it and use this FromArgb method instead:
Public Shared Function FromArgb (a As Byte, r As Byte, g As Byte, b As Byte) As Color
You can use one of the approaches from Convert integer to color in WPF, like this one:
Dim bytes = BitConverter.GetBytes(/* some integer */)
Dim color = Color.FromArgb(bytes(3), bytes(2), bytes(1), bytes(0))
Dim brush = New SolidColorBrush(color)
Dim Cell As New Shapes.Rectangle With
.Fill = brush
}
How do I make an array of PictureBoxes in Visual Basic?
I'm trying to make a row of PictureBoxes -that's all the same size, and same picture- to display across the form. How could I do this?
I made the array using this:
Dim blk(10) As PictureBox
and the code to place the PictureBoxes is this:
'Create PictureBoxes
blk(0) = blk_Green()
blk(0).Image = imgl_blk.Images(0)
blk(0).Visible = True
blk(0).SetBounds(10, 10, blk_Green.Width, blk_Green.Height)
For i = 1 To 10 Step 1
blk(i) = blk_Green()
blk(i).Image = imgl_blk.Images(0)
blk(i).Visible = True
blk(i).SetBounds(i * 10, 10, blk_Green.Width, blk_Green.Height)'I will change this according to what it needs to be
Next
imgl_blk is an ImageList, and blk_Green is a ImageBox I've already made on the form.
When I run it, only one of the PictureBoxes will show up, instead of all 10 from the array.
This is what i'm trying to get (Or something like this):
This is what happens instead:
How could I make this work? Thanks in advance!
If you want to create a control array:
Dim blk() As PictureBox
blk = New PictureBox() {PictureBox1, PictureBox2, PictureBox3, PictureBox4}
Then you can reference PictureBox1 with blk(0), PictureBox2 with blk(1), PictureBox3 with blk(2) and PictureBox4 with blk(3).
You're assigning the same Object's reference to all 10 PictureBoxes. You need to instantiate each one of your PictureBoxes separately and then assign each one's Image property.
BTW, you should really look into GDI+'s drawing methods such as Graphics.DrawImage() to do this kind of stuff. It would be a lot faster and less of a memory-hog.
You may try this :
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim Shapes(10) As PictureBox
For i = 1 To 10
Shapes(i) = New PictureBox
Shapes(i).Name = "rect" + Str(i)
Shapes(i).BackColor = Color.Green
Shapes(i).Location = New Point(10 + 50 * i, 20)
Shapes(i).Size = New Size(40, 20)
Shapes(i).Visible = True
Me.Controls.Add(Shapes(i))
Next
End Sub
End Class
Basically I want to achieve something like this:
but I have no idea how to do it, I tried with 2 labels to combine them but the result isn't that great..
You need to draw the text from a different point of view, namely, the baseline:
Public Class MyLabel
Inherits Label
<Browsable(False)> _
Public Overrides Property AutoSize As Boolean
Get
Return False
End Get
Set(value As Boolean)
'MyBase.AutoSize = value
End Set
End Property
Protected Overrides Sub OnPaint(e As PaintEventArgs)
'MyBase.OnPaint(e)
Dim fromLine As Integer = Me.ClientSize.Height * 0.75
Dim g As Graphics = e.Graphics
Dim fontParts() As String = Me.Text.Split(".")
Using bigFont As New Font(Me.Font.FontFamily, 20)
TextRenderer.DrawText(g, fontParts(0), bigFont, _
New Point(0, fromLine - GetBaseLine(bigFont, g)), _
Me.ForeColor, Color.Empty)
If fontParts.Length > 1 Then
Dim bigWidth As Integer = TextRenderer.MeasureText(g, fontParts(0), bigFont, _
Point.Empty, TextFormatFlags.NoPadding).Width
Using smallFont As New Font(Me.Font.FontFamily, 8)
TextRenderer.DrawText(g, "." & fontParts(1), smallFont, _
New Point(bigWidth + 3, fromLine - GetBaseLine(smallFont, g)), _
Me.ForeColor, Color.Empty)
End Using
End If
End Using
End Sub
Private Function GetBaseLine(fromFont As Font, g As Graphics) As Single
Dim fontHeight As Single = fromFont.GetHeight(g)
Dim lineSpacing As Single = fromFont.FontFamily.GetLineSpacing(fromFont.Style)
Dim cellAscent As Single = fromFont.FontFamily.GetCellAscent(fromFont.Style)
Return fontHeight * cellAscent / lineSpacing
End Function
End Class
The code basically measures the height of the font from a line. In my example, I used the bottom 25% of the Label's client space to say, start drawing from this line: Me.ClientSize.Height * 0.75.
For each font you use, you would have to measure that font's baseline and subtract that from your drawing line in order to offset your drawing position of the text.
Measuring an individual character's dimensions is not easy due to aliasing and glyph overhangs. I added a small padding between the big text and the small text: bigWidth + 3 to try to make it look good. If the big number ends in a 7, the distance looks a little off because the stem of the 7 is angled.
Result:
Create a new class inherited from Label, and override the void OnPaint(PaintEventArgs e) method to change the default rendering behavior:
public class MyLabel : Label
{
protected override void OnPaint(PaintEventArgs e)
{
e.Graphics.DrawString("A", Font, new SolidBrush(ForeColor), 10, 10);
e.Graphics.DrawString("B", new Font(Font.FontFamily, 20), new SolidBrush(ForeColor), 50, 10);
}
}
As a result, "B" will be two times larger the "A". You can achieve your goal in the same way, but you have to calculate the position of your sub-strings ("145", ".", "54") and draw them.
Use devexpress LabelControl.AllowHtmlString property to true and use the supported <size> tag within the LabelControl's Text property as detailed in the HTML Text Formatting documentation.
you can use user control WPF in windows form. to do that do this step.
1. add user control to the windows form
2.from xml of usercontrol name grid like t1
3. add this function to the usercontrol.wpf.cs
public void Actor(string text)
{
StringBuilder sb = new StringBuilder();
sb.Append(#"<TextBlock xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'> ");
sb.Append(text);
sb.Append(#"</TextBlock>");
TextBlock myButton = (TextBlock)XamlReader.Parse(sb.ToString());
this.t1.Children.Clear();
t1.Children.Add(myButton);
}
4. after that from form1.css add this function in every where you want.
userControl11.Actor("<Run Text='Hi ' FontWeight='Bold'/><Run Text='Hitler ' FontWeight='Bold'/>");
userControl11.Actor(" < Run FontWeight = 'Bold' FontSize = '14' Text = 'This is WPF TextBlock Example. ' />");
you can mange the write code "" of Actor function by using xml wpf.
There is a DataGridView which is created at runtime with data fetching from database. There are four types of columns in data grid view:
DataGridViewTextBoxColumn
DataGridViewComboboxColumn
DataGridViewButtonColumn
DataGridViewCheckBoxColumn
Code for creating that datagridview is as below:
_form.DGV_.AutoGenerateColumns = False
_form.DGV_.Columns.Clear()
'Required Variables
Dim pom_DataGridViewTextBoxColumn As DataGridViewTextBoxColumn = Nothing
Dim pom_DataGridViewComboBoxColumn As DataGridViewComboBoxColumn = Nothing
Dim pom_DataGridViewButtonColumn As DataGridViewButtonColumn = Nothing
Dim pom_DataGridViewCheckBoxColumn As DataGridViewCheckBoxColumn = Nothing
'Column-1 (ID: jntDate)
pom_DataGridViewTextBoxColumn = New DataGridViewTextBoxColumn
pom_DataGridViewTextBoxColumn.DataPropertyName = "jntDate"
pom_DataGridViewTextBoxColumn.HeaderText = "Date"
pom_DataGridViewTextBoxColumn.DefaultCellStyle.Format = "d"
_form.DGV_.Columns.Add(pom_DataGridViewTextBoxColumn)
'Column-2 (ID: jntAcc)
pom_DataGridViewComboBoxColumn = New DataGridViewComboBoxColumn
pom_DataGridViewComboBoxColumn.DataPropertyName = "jntAcc"
'Cond: If dataset Acc does not contain any table then add table from database.
If Acc.Tables.Count > 0 Then
pom_DataGridViewComboBoxColumn.DataSource = Acc.Tables.Item(0)
Else
Acc.Tables.Add(Tbl_Select("SELECT *, accNo AS byNo, accName as byName FROM tblAccounts", False, ""))
pom_DataGridViewComboBoxColumn.DataSource = Acc.Tables.Item(0)
End If
'Cond: If _Account_Name_Number is True then set DisplayMember property to 'byName'.
If _Account_Name_Number Then
pom_DataGridViewComboBoxColumn.DisplayMember = "byName"
Else
pom_DataGridViewComboBoxColumn.DisplayMember = "byNo"
End If
pom_DataGridViewComboBoxColumn.ValueMember = "accID"
pom_DataGridViewComboBoxColumn.HeaderText = "Account"
_form.DGV_.Columns.Add(pom_DataGridViewComboBoxColumn)
'Column-3 (ID: xxxx)
pom_DataGridViewButtonColumn = New DataGridViewButtonColumn
pom_DataGridViewButtonColumn.DataPropertyName = "xxxx"
pom_DataGridViewButtonColumn.UseColumnTextForButtonValue = True
pom_DataGridViewButtonColumn.HeaderText = "X"
pom_DataGridViewButtonColumn.Text = "X"
pom_DataGridViewButtonColumn.Width = 32
pom_DataGridViewButtonColumn.DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter
pom_DataGridViewButtonColumn.DefaultCellStyle.ApplyStyle(pom_DataGridViewButtonColumn.DefaultCellStyle)
_form.DGV_.Columns.Add(pom_DataGridViewButtonColumn)
'Column-4 (ID: jntReview)
pom_DataGridViewCheckBoxColumn = New DataGridViewCheckBoxColumn
pom_DataGridViewCheckBoxColumn.DataPropertyName = "jntReview"
pom_DataGridViewCheckBoxColumn.HeaderText = "Review"
pom_DataGridViewCheckBoxColumn.DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter
pom_DataGridViewCheckBoxColumn.DefaultCellStyle.ApplyStyle(pom_DataGridViewCheckBoxColumn.DefaultCellStyle)
_form.DGV_.Columns.Add(pom_DataGridViewCheckBoxColumn)
In WPF application, there is a need to populate same DataGrid with these four columns.
How can I create and bind data to four types of columns in DataGrid in WPF ?
Why not skip doing all that stuff in cs code? You'll start pinning yourself in the corner and WILL hit the wall when the datagrid will need more complex templates, data triggers, custom styles, animations, etc... Besides, it will make it easier not only on the next person, but you as well. When you have to add/fix something in the beast you create in .cs code 3-6 months down the road, it might take you quite a while to understand what is going on :)
Instead, do all your work in xaml, Create a UserControl, put this datagrid in it, Pass the DataContext from various instances of the UserControl down to it's DataGrid.
I want to add a number of canvas to another canvas but the following code doesn't seem to work, the application compiles but only a blank window is displayed. Ideally this would show the canvases in a diagonal line.
Here is my vb.net code:
For r As Integer = 1 To 10
X += 5
Y += 5
Dim c As Canvas = New Canvas()
Dim s As SolidColorBrush = New SolidColorBrush
s.Color = Color.FromRgb(255, 0, 0)
c.Background = s
c.Name = "cnv" + CStr(X)
c.Margin = New Thickness(X, Y, 0, 0)
cnvOverLay.Children.Add(c)
cnvOverLay.UpdateLayout()
Next
I have tried to add multiple buttons using dim b As Button = new Button() instead of creating a new canvas every time, that worked fine.
Am I missing something simple?
You cannot see the canvases be because the do not have a width and a height.