dynamicdatadisplay (wpf) how to make a string marker? - c#

I'm using dynamicdatadisplay library for WPF! not SilverLight
I've finish my backend codding already and stuck with graph.
I have an X-Axis that is a DateTime (hours).
Also I Have an Y-Axis that is Decimal.
But I can't find how to put between this axes custom marker (or whatever) which will be a dynamic string.
For example in 10 hours 03.11.2013 (x-axis) the price of the Stock was 120$ (y-axis) but in graph (in the cross of the axes) it must be a string "Volume: 50" which will show how much stocks was sell.
How to make it in code? Please give me some examples or advice.
Now my project look's like this:
========= XAML ==========
<d3:ChartPlotter Name="plotter" Margin="20,20,20,70">
<d3:ChartPlotter.HorizontalAxis>
<d3:HorizontalDateTimeAxis Name="xAxis"/>
</d3:ChartPlotter.HorizontalAxis>
<d3:ChartPlotter.VerticalAxis>
<d3:VerticalIntegerAxis Name="yAxis"/>
</d3:ChartPlotter.VerticalAxis>
</d3:ChartPlotter>
<Button Content="Button" HorizontalAlignment="Left" Margin="254,364,0,0" VerticalAlignment="Top" Width="145" Height="46" Click="Button_Click_1"/>
</Grid>
=============================================
================ MainWindow.cs =================
private void Button_Click_1(object sender, RoutedEventArgs e)
{
List<DataForChart> dataForChart = new List<DataForChart>();
dataForChart.Add(new DataForChart(new DateTime(2013, 11, 03, 22, 10, 0), 45));
dataForChart.Add(new DataForChart(new DateTime(2013, 11, 03, 22, 20, 0), 48));
dataForChart.Add(new DataForChart(new DateTime(2013, 11, 03, 22, 30, 0), 24));
DateTime[] dates = new DateTime[dataForChart.Count];
int[] price = new int[dataForChart.Count];
for (int i = 0; i < dataForChart.Count; ++i)
{
dates[i] = dataForChart[i].date;
price[i] = dataForChart[i].price;
}
var datesDataSource = new EnumerableDataSource<DateTime>(dates);
datesDataSource.SetXMapping(x => xAxis.ConvertToDouble(x));
var numberOpenDataSource = new EnumerableDataSource<int>(price);
numberOpenDataSource.SetYMapping(y => y);
CompositeDataSource compositeDataSource1 = new
CompositeDataSource(datesDataSource, numberOpenDataSource);
plotter.AddLineGraph(compositeDataSource1,
new Pen(Brushes.Blue, 2),
new CirclePointMarker { Size = 10.0, Fill = Brushes.Blue },
new PenDescription("Price Chart"));
plotter.Viewport.FitToView();
}
public class DataForChart
{
public DateTime date;
public int price;
public DataForChart(DateTime Date, int Price)
{
date = Date;
price = Price;
}
}

// Create a custom marker control as follows
// CustomMarker.xaml:
<d3:ViewportUIContainer x:Class="MyNamespace.CustomMarker"
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"
xmlns:d3="clr-namespace:Microsoft.Research.DynamicDataDisplay.Charts;assembly=DynamicDataDisplay"
mc:Ignorable="d" >
<Grid>
<TextBlock Name="TxtBlk1" Text="Some Text" />
</Grid>
</d3:ViewportUIContainer>
// Marker control code behind CustomMarker.cs
using System;
using System.Windows;
using System.Windows.Media;
namespace MyNamespace
{
public partial class CustomMarker : Microsoft.Research.DynamicDataDisplay.Charts.ViewportUIContainer
{
public CustomMarker()
{
InitializeComponent();
}
public CustomMarker(Point position, string text, Color color) : this()
{
Position = position;
TxtBlk1.Text = text;
TxtBlk1.Foreground = new SolidColorBrush(color);
}
}
}
//In your mainwindow.cs
var position = new Point(x value, y value);
plotter.Children.Add(new CustomMarker(position, "Text", Colors.Black));

Related

Pop-up content after clicking on an item from the wpf list

I need to implement this drop-down menu in WPF:
When you click on the number of the question, it should open additional content. I can't attach the code, because there is not even an approximate implementation. I tried to implement via Grid.Row and Grid.Column, ListBox, StackPanel but I just didn't have enough knowledge.
Here is the code I've tried:
<Grid>
<ListBox HorizontalContentAlignment="Left">
<Button Content="1"/>
<TextBlock Text="Content"/>
<Button Content="2"/>
</ListBox>
</Grid>
Step 1: Add a User Control to your project.
Step 2: Name it Arrow.
Step 3: This Control will act as a drop-down arrow for us. Add the following XAML code to the control:
<UserControl x:Class="Question_Builder_App.Controls.Arrow"
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">
<Grid>
<Border BorderThickness="0,0,5,0" Height="15" BorderBrush="Black" RenderTransformOrigin="0.5,0.5" Width="10" Margin="0,0,0,10">
<Border.RenderTransform>
<TransformGroup>
<ScaleTransform/>
<SkewTransform/>
<RotateTransform Angle="135"/>
<TranslateTransform/>
</TransformGroup>
</Border.RenderTransform>
</Border>
<Border BorderThickness="0,0,5,0" BorderBrush="Black" RenderTransformOrigin="0.5,0.5" Height="15" Width="10" Margin="0,11,0,0" Grid.RowSpan="2">
<Border.RenderTransform>
<TransformGroup>
<ScaleTransform/>
<SkewTransform/>
<RotateTransform Angle="225"/>
<TranslateTransform/>
</TransformGroup>
</Border.RenderTransform>
</Border>
</Grid>
The control should look like this:
Step 4: Add the following XAML to your MainWindow:
<Window x:Class="Question_Builder_App.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"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800" Background="#FF283246">
<Grid x:Name="MainGrid">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<StackPanel x:Name="LeftPanel" Grid.Column="0">
<Border CornerRadius="10,10,10,10" HorizontalAlignment="Center" VerticalAlignment="Center" Background="#FF033B50" Margin="50,20,50,0">
<Button x:Name="AddQuestion_BTN" FontSize="24" Content="+" HorizontalAlignment="Stretch" VerticalAlignment="Center" Foreground="White" HorizontalContentAlignment="Left" Padding="10,0,10,0" Click="AddQuestion_BTN_Click" Background="{x:Null}" BorderBrush="{x:Null}"/>
</Border>
</StackPanel>
<Frame x:Name="RightPanel" Grid.Column="1" NavigationUIVisibility="Hidden"/>
</Grid>
The designer should look like this:
Step 5: Now lets add some C# codes to our MainWindow:
using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
namespace Question_Builder_App
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
AddSampleData("Test Button 1", "Test Button");
AddSampleData("Test Button 2", "Test Button");
AddSampleData("Test Button 3", "Test Button");
}
private int ButtonCount = 0;
private ObservableCollection<DataModel> PageCollection = new ObservableCollection<DataModel>();
private class DataModel
{
public string MainButtonName { get; set; }
public string PageName { get; set; }
public Page DisplayPage { get; set; }
}
private static string CreateInputWindow(string WindowDescription)
{
Window ButtonInfoWindow = new Window();
ButtonInfoWindow.Background = null; ButtonInfoWindow.SizeToContent = SizeToContent.WidthAndHeight;
StackPanel SP = new StackPanel();
Border TextDescription = AddBorder(WindowDescription, 24);
TextBox TB = new TextBox();
TB.MinWidth = 100; TB.FontSize = 24;
Button B = new Button();
B.FontSize = 24; B.Margin = new Thickness(0, 10, 0, 0); B.Content = "Set";
B.Click += delegate { ButtonInfoWindow.Close(); };
SP.Children.Add(TextDescription); SP.Children.Add(TB); SP.Children.Add(B);
ButtonInfoWindow.Content = SP;
ButtonInfoWindow.ShowDialog();
return TB.Text;
}
private void AddQuestion_BTN_Click(object sender, RoutedEventArgs e)
{
Border TopBorder = new Border();
TopBorder.CornerRadius = new CornerRadius(10); TopBorder.Background = new SolidColorBrush(Color.FromRgb(3, 59, 80)); TopBorder.HorizontalAlignment = HorizontalAlignment.Left;
TopBorder.Margin = new Thickness(40, 20, 40, 0);
StackPanel TopSPPanel = new StackPanel();
TopBorder.Child = TopSPPanel;
StackPanel LowerPanel = new StackPanel();
LowerPanel.Visibility = Visibility.Collapsed;
string MainButtonName = CreateInputWindow("What is the name of the button you wish to create?");
Border NewQuestion_BTN = AddBorder(ButtonCount + 1 + ". " + MainButtonName, 24);
NewQuestion_BTN.MouseLeftButtonDown += delegate
{
if (LowerPanel.Visibility == Visibility.Visible)
{
LowerPanel.Visibility = Visibility.Collapsed;
NewQuestion_BTN.Background = new SolidColorBrush(Color.FromRgb(3, 59, 80));
}
else
{
LowerPanel.Visibility = Visibility.Visible;
NewQuestion_BTN.Background = new SolidColorBrush(Colors.Blue);
}
};
TopSPPanel.Children.Add(NewQuestion_BTN);
LowerPanel.Margin = new Thickness(0, 10, 0, 10);
Border LowerNewQuestion_BTN = AddBorder("+", 24);
LowerNewQuestion_BTN.MouseLeftButtonDown += delegate
{
string InputText = CreateInputWindow("What is the name of the button you wish to create?");
Border ChooseQuestionBTN = AddBorder(LowerPanel.Children.Count + ". " + InputText, 16);
ChooseQuestionBTN.MouseLeftButtonDown += delegate
{
UncheckAllButtons();
ChooseQuestionBTN.Background = new SolidColorBrush(Colors.Aquamarine);
NavigateToPage(MainButtonName, InputText);
};
LowerPanel.Children.Insert(LowerPanel.Children.Count - 1, ChooseQuestionBTN);
};
LowerPanel.Children.Add(LowerNewQuestion_BTN); TopSPPanel.Children.Add(LowerPanel);
LeftPanel.Children.Insert(ButtonCount, TopBorder);
ButtonCount++;
}
private void NavigateToPage(string MainButtonText, string NameChecker)
{
bool CheckIfToADDANewPage = true;
foreach (DataModel PageFinder in PageCollection)
{
if (PageFinder.PageName == NameChecker && PageFinder.MainButtonName == MainButtonText)
{
RightPanel.Navigate(PageFinder.DisplayPage);
CheckIfToADDANewPage = false;
}
}
if (CheckIfToADDANewPage == true)
{
DataModel SavePage = new DataModel();
SavePage.MainButtonName = MainButtonText; SavePage.PageName = NameChecker; SavePage.DisplayPage = CreateANewPage();
PageCollection.Add(SavePage);
RightPanel.Navigate(SavePage.DisplayPage);
}
}
private static Page CreateANewPage()
{
Page QuestionPage = new Page();
StackPanel QuestionPanel = new StackPanel();
Border QuestionBorder = AddBorder("+", 24);
QuestionBorder.Margin = new Thickness(5, 20, 0, 0); QuestionBorder.Background = new SolidColorBrush(Colors.Aqua);
QuestionBorder.MouseLeftButtonDown += delegate
{
StackPanel UpperQuestionPanel = new StackPanel(); UpperQuestionPanel.Orientation = Orientation.Horizontal;
UpperQuestionPanel.Margin = new Thickness(0, 20, 0, 0);
Border QuestionNumberTXT = AddBorder(QuestionPanel.Children.Count.ToString(), 24);
QuestionNumberTXT.VerticalAlignment = VerticalAlignment.Top; QuestionNumberTXT.Background = new SolidColorBrush(Colors.Aqua);
Controls.Arrow PanelArrow = new Controls.Arrow();
PanelArrow.Margin = new Thickness(20, 10, 10, 0); PanelArrow.VerticalAlignment = VerticalAlignment.Top;
StackPanel InnerQuestionPanel = new StackPanel(); InnerQuestionPanel.Visibility = Visibility.Collapsed; InnerQuestionPanel.Margin = new Thickness(0, 10, 10, 0);
PanelArrow.MouseLeftButtonDown += delegate
{
if (InnerQuestionPanel.Visibility == Visibility.Collapsed)
{
InnerQuestionPanel.Visibility = Visibility.Visible;
PanelArrow.RenderTransform = new RotateTransform(90);
PanelArrow.Margin = new Thickness(45, 20, 10, 0);
if (InnerQuestionPanel.ActualWidth < 1)
{
Border InnerQuestionBorder = AddBorder(CreateInputWindow("Please enter description of the question: "), 24);
InnerQuestionBorder.MaxWidth = 800;
InnerQuestionPanel.Children.Insert(0, InnerQuestionBorder);
}
}
else
{
InnerQuestionPanel.Visibility = Visibility.Collapsed;
PanelArrow.RenderTransform = new RotateTransform(0);
PanelArrow.Margin = new Thickness(20, 10, 10, 0);
}
};
WrapPanel NewQuestionWrapPanel = new WrapPanel();
NewQuestionWrapPanel.Orientation = Orientation.Horizontal;
Border AddNewQuestionBTN = AddBorder("+", 24);
AddNewQuestionBTN.Margin = new Thickness(10, 10, 0, 0);
AddNewQuestionBTN.MouseLeftButtonDown += delegate
{
NewQuestionWrapPanel.MaxWidth = InnerQuestionPanel.ActualWidth;
Border ChooseNewQuestion = AddBorder(CreateInputWindow("Add new question: "), 24);
ChooseNewQuestion.Margin = new Thickness(10, 10, 0, 0);
NewQuestionWrapPanel.Children.Insert(NewQuestionWrapPanel.Children.Count - 1, ChooseNewQuestion);
};
NewQuestionWrapPanel.Children.Insert(NewQuestionWrapPanel.Children.Count, AddNewQuestionBTN); InnerQuestionPanel.Children.Add(NewQuestionWrapPanel);
UpperQuestionPanel.Children.Add(QuestionNumberTXT); UpperQuestionPanel.Children.Add(PanelArrow); UpperQuestionPanel.Children.Add(InnerQuestionPanel);
QuestionPanel.Children.Insert(QuestionPanel.Children.Count - 1, UpperQuestionPanel);
};
QuestionPanel.Children.Insert(QuestionPanel.Children.Count, QuestionBorder); QuestionPage.Content = QuestionPanel;
return QuestionPage;
}
private static Border AddBorder(string InnerText, int SetFontSize)
{
Border NewBorder = new Border();
NewBorder.CornerRadius = new CornerRadius(10); NewBorder.Background = new SolidColorBrush(Color.FromRgb(3, 59, 80)); NewBorder.HorizontalAlignment = HorizontalAlignment.Left;
NewBorder.Margin = new Thickness(10, 0, 10, 0);
TextBlock NewButton = new TextBlock();
NewButton.FontSize = SetFontSize; NewButton.VerticalAlignment = VerticalAlignment.Stretch; NewButton.Foreground = new SolidColorBrush(Colors.White);
NewButton.Margin = new Thickness(10, 0, 10, 0);
NewButton.Text = InnerText;
NewButton.TextWrapping = TextWrapping.Wrap;
NewBorder.Child = NewButton;
return NewBorder;
}
private void AddSampleData(string MainButtonText, string SecondaryButtonText)
{
Border TopBorder = new Border();
TopBorder.CornerRadius = new CornerRadius(10); TopBorder.Background = new SolidColorBrush(Color.FromRgb(3, 59, 80)); TopBorder.HorizontalAlignment = HorizontalAlignment.Left;
TopBorder.Margin = new Thickness(40, 20, 40, 0);
StackPanel TopSPPanel = new StackPanel();
TopBorder.Child = TopSPPanel;
StackPanel LowerPanel = new StackPanel();
LowerPanel.Visibility = Visibility.Collapsed;
Border NewQuestion_BTN = AddBorder(ButtonCount + 1 + ". " + MainButtonText, 24);
NewQuestion_BTN.MouseLeftButtonDown += delegate
{
if (LowerPanel.Visibility == Visibility.Visible)
{
LowerPanel.Visibility = Visibility.Collapsed;
NewQuestion_BTN.Background = new SolidColorBrush(Color.FromRgb(3, 59, 80));
}
else
{
LowerPanel.Visibility = Visibility.Visible;
NewQuestion_BTN.Background = new SolidColorBrush(Colors.Blue);
}
};
TopSPPanel.Children.Add(NewQuestion_BTN);
LowerPanel.Margin = new Thickness(0, 10, 0, 10);
Border LowerNewQuestion_BTN = AddBorder("+", 24);
LowerNewQuestion_BTN.MouseLeftButtonDown += delegate
{
string InputText = CreateInputWindow("What is the name of the button you wish to create?");
Border ChooseQuestionBTN = AddBorder(LowerPanel.Children.Count + ". " + InputText, 16);
ChooseQuestionBTN.MouseLeftButtonDown += delegate
{
UncheckAllButtons();
ChooseQuestionBTN.Background = new SolidColorBrush(Colors.Aquamarine);
NavigateToPage(MainButtonText, InputText);
};
LowerPanel.Children.Insert(LowerPanel.Children.Count - 1, ChooseQuestionBTN);
};
Border SampleQuestionBTN = AddBorder(LowerPanel.Children.Count + 1 + ". " + SecondaryButtonText, 16);
SampleQuestionBTN.MouseLeftButtonDown += delegate
{
UncheckAllButtons();
SampleQuestionBTN.Background = new SolidColorBrush(Colors.Aquamarine);
NavigateToPage(MainButtonText, SecondaryButtonText);
};
LowerPanel.Children.Insert(LowerPanel.Children.Count, SampleQuestionBTN);
LowerPanel.Children.Add(LowerNewQuestion_BTN); TopSPPanel.Children.Add(LowerPanel);
LeftPanel.Children.Insert(ButtonCount, TopBorder);
ButtonCount++;
}
private void UncheckAllButtons()
{
foreach (Border _BR in LeftPanel.Children)
{
if (_BR.Child is StackPanel)
{
StackPanel SP = (StackPanel)_BR.Child;
foreach (UIElement UE in SP.Children)
{
if (UE is StackPanel)
{
StackPanel SP1 = (StackPanel)UE;
foreach (Border B in SP1.Children)
{
B.Background = null;
}
}
}
}
}
}
}
}

How to made multiple LineChart in WPF Dynamic Data Display?

I have 3 collection in c# (wpf application). I need to show them a line chart graph. I researched too much websites and i only have dynamic data display d3. so i tried to make a chart as below in wpf.
i found a code from stackoverflow but i couldnt make it as i thought. i can only show one line in the field and it can only show as below.
and my another problem is horizontal axis. How can i make horizontal values as string or as [10-2016]. Here is codes i found.
MainWindow.xaml
<Window x:Class="WpfApplication1.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:WpfApplication1"
xmlns:d3="clr-namespace:Microsoft.Research.DynamicDataDisplay;assembly=DynamicDataDisplay"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525" Loaded="Window_Loaded">
<Grid>
<d3:ChartPlotter>
<d3:LineGraph DataSource="{Binding Data}"></d3:LineGraph>
</d3:ChartPlotter>
</Grid>
</Window>
MainWindow.xaml.cs
MyViewModel viewModel;
public MainWindow()
{
InitializeComponent();
viewModel = new MyViewModel();
DataContext = viewModel;
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
double[] my_array = new double[10];
for (int i = 0; i < my_array.Length; i++)
{
my_array[i] = Math.Sin(i)*3;
viewModel.Data.Collection.Add(new Point(i, my_array[i]));
}
}
MyViewModel.cs
public class MyViewModel
{
public ObservableDataSource<Point> Data { get; set; }
public MyViewModel()
{
Data = new ObservableDataSource<Point>();
}
}
Is there any easy way to make chart as upper picture. I dont know anything about wpf charts and i dont have any budget to pay wpf chart libraries. I hope anyone can help me.
I would recommend you use Live Charts.
Each line on the graph is represented by a 'LineSeries' and it is designed to be MVVM friendly. It's 100% free, and you can install using NuGet.
Live Charts
How to install
Example:
Xaml:
<Grid>
<lvc:CartesianChart Series="{Binding SeriesCollection}" LegendLocation="Right" >
<lvc:CartesianChart.AxisY>
<lvc:Axis Title="Sales" LabelFormatter="{Binding YFormatter}"></lvc:Axis>
</lvc:CartesianChart.AxisY>
<lvc:CartesianChart.AxisX>
<lvc:Axis Title="Month" Labels="{Binding Labels}"></lvc:Axis>
</lvc:CartesianChart.AxisX>
</lvc:CartesianChart>
</Grid>
ViewModel:
public class ViewModel
{
public SeriesCollection SeriesCollection { get; set; }
public string[] Labels { get; set; }
public Func<double, string> YFormatter { get; set; }
public ViewModel()
{
SeriesCollection = new SeriesCollection
{
new LineSeries
{
Title = "Series 1",
Values = new ChartValues<double> { 4, 6, 5, 2 ,4 }
},
new LineSeries
{
Title = "Series 2",
Values = new ChartValues<double> { 6, 7, 3, 4 ,6 },
PointGeometry = null
},
new LineSeries
{
Title = "Series 3",
Values = new ChartValues<double> { 4,2,7,2,7 },
PointGeometry = DefaultGeometries.Square,
PointGeometrySize = 15
}
};
Labels = new[] {"Jan", "Feb", "Mar", "Apr", "May"};
YFormatter = value => value.ToString("C");
//modifying the series collection will animate and update the chart
SeriesCollection.Add(new LineSeries
{
Title = "Series 4",
Values = new ChartValues<double> {5, 3, 2, 4},
LineSmoothness = 0, //0: straight lines, 1: really smooth lines
PointGeometry = Geometry.Parse("m 25 70.36218 20 -28 -20 22 -8 -6 z"),
PointGeometrySize = 50,
PointForeground = Brushes.Gray
});
//modifying any series values will also animate and update the chart
SeriesCollection[3].Values.Add(5d);
}
}
Output:

XAML is VirtualCanvas (just like VirtualStackPanel) possible?

I am creating a vertical scrolling game that utilizes a canvas. Though there is no performance issues just yet I am anticipating that there will be since I don't believe the canvas inherently offers virtualization. Is there such thing as a VirtualCanvas similar to the VirtualStackPanel? I want the same functionality where it only draws what is currently being displayed.
Right now my structure looks like this
<canvas Name="GameCanvas">
<canvas Name="StaticBG">
</canvas>
<canvas Name="DynamIcBG">
</canvas>
<canvas Name="CollidableObjects">
</canvas>
<canvas Name="Hud">
</canvas>
</canvas>
I would like to virtualize the DynamicBG and the CollidableObjects canvases
EDIT:
Can I possibly put all of my stuff inside of a VirtualStackPanel? Would that work?
<Canvas>
<Canvas>
<VirtualizingStackPanel>
<Canvas Name="Collidables">
<TextBlock>HOMES IT WORKS</TextBlock>
</Canvas>
</VirtualizingStackPanel>
</Canvas>
<Canvas>
<VirtualizingStackPanel>
<Canvas Name="DynamicBG">
<TextBlock>IT WORKS HOMES</TextBlock>
</Canvas>
</VirtualizingStackPanel>
</Canvas>
</Canvas>
The Canvas is NOT Virtualized - at least, not in the way you'd typically define Virtualization.
The following LINQPad-ready harness will show this - even if the "bugs" are outside of the window extents, the contained bugs will continue to render.
void Main()
{
var bugCount = 4;
var window = System.Windows.Markup.XamlReader.Parse(someXaml)
as System.Windows.Window;
window.Show();
var canvas = window.FindName("canvas")
as System.Windows.Controls.Canvas;
var bugs = new List<Bug>();
var r = new Random();
if(canvas != null)
{
for(int i=0; i < bugCount; i++)
{
var bug = new Bug();
bug.Height = 50;
bug.Width = 50;
bug.Location = new System.Windows.Point(
r.Next(0, (int)canvas.Width),
r.Next(0, (int)canvas.Height));
canvas.Children.Add(bug);
bugs.Add(bug);
}
}
var dt = new System.Windows.Threading.DispatcherTimer();
dt.Tick += (o,e) => MoveIt(bugs);
dt.Interval = TimeSpan.FromMilliseconds(100);
dt.Start();
}
public void MoveIt(List<Bug> bugs)
{
var r = new Random();
foreach (var bug in bugs)
{
var dir = r.Next(0,4);
switch (dir)
{
case 0:
bug.Location =
new System.Windows.Point(bug.Location.X + 1, bug.Location.Y);
break;
case 1:
bug.Location =
new System.Windows.Point(bug.Location.X - 1, bug.Location.Y);
break;
case 2:
bug.Location =
new System.Windows.Point(bug.Location.X, bug.Location.Y + 1);
break;
case 3:
bug.Location =
new System.Windows.Point(bug.Location.X, bug.Location.Y - 1);
break;
}
}
}
public class Bug : System.Windows.Controls.UserControl
{
private static int _bugCounter = 0;
public Bug()
{
this.BugId = _bugCounter++;
}
public int BugId {get; private set;}
private System.Windows.Point _location;
public System.Windows.Point Location
{
get { return _location; }
set
{
_location = value;
System.Windows.Controls.Canvas.SetLeft(this, value.X);
System.Windows.Controls.Canvas.SetTop(this, value.Y);
InvalidateVisual();
}
}
protected override void OnRender(System.Windows.Media.DrawingContext ctx)
{
base.OnRender(ctx);
Console.WriteLine("Yo, bug #{0} is rendering!", BugId);
ctx.DrawRectangle(
System.Windows.Media.Brushes.Red,
new System.Windows.Media.Pen(System.Windows.Media.Brushes.White, 1),
new System.Windows.Rect(Location, this.RenderSize));
var formattedText = new System.Windows.Media.FormattedText(
this.BugId.ToString(),
System.Globalization.CultureInfo.CurrentCulture,
System.Windows.FlowDirection.LeftToRight,
new System.Windows.Media.Typeface("Arial"),
12,
System.Windows.Media.Brushes.White);
ctx.DrawText(
formattedText,
new System.Windows.Point(Location.X + 10, Location.Y + 10));
}
}
string someXaml =
#"
<Window
xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation""
xmlns:x=""http://schemas.microsoft.com/winfx/2006/xaml""
Width=""320""
Height=""240""
>
<Canvas
x:Name=""canvas""
Width=""640""
Height=""480""
Background=""LightGray""
/>
</Window>
";
The answer to this question is that the Canvas fakes virtualization. If you load a bunch of objects on the canvas and they don't need to be drawn on the screen they are overlooked. I say fakes virtualization because this comes from my own investigation and research. I have yet to find a single article relating to this topic.
If you however were to load 200 images that were 100x100 onto a canvas in various spots both on and off the screen. You will notice that as you move the canvas around you will experience no delay.

How to refresh WPF chart after updating the Y Axis Maximum value?

I 'm creating a Line chart using WPFToolKit.
The chart comes up fine but i want to change the Maximum property of the Y Axis upon button click of a modal window after loading the chart for the first time. And the chart should be refreshed with the updated Y Axis Max value
Below line shows how Chart is defined in xaml.
<DVC:Chart Canvas.Top="80" Canvas.Left="10" Name="mcChart" VerticalAlignment="Stretch"/>
I'm calling below code in windows.xaml.cs constructor and it is setting Y-Axis Max to 200
mcChart.Axes.Add(new LinearAxis()
{
Minimum = 0,
Maximum = YMax > 0 ? YMax : 200,
Orientation = AxisOrientation.Y,
ShowGridLines = true,
});
mcChart.UpdateLayout();
How can i change the Y-Axis Max value from a modal window's button click event and refresh chart to display with new YMax.
I'm not sure if i have to do something with RegisteredListeners.
I'm new to WPF and any help is appreciated!
Please note that i'm looking to achieve this from the C# code behind and not in xaml.
Thanks,
Sujay
If you have access to the chart, you can find the neccessary axis and change the Maximum property without updating layout. Here is an example with a linear Y axis:
var yAxis = this.mcChart.ActualAxes.OfType<LinearAxis>().FirstOrDefault(ax => ax.Orientation == AxisOrientation.Y);
if (yAxis != null)
yAxis.Maximum = 300;
The complete version of this example:
MainWindow.xaml
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="20"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Button Content="Set max value = 300" HorizontalAlignment="Center" Click="Button_Click"/>
<charting:Chart Grid.Row="1" x:Name="mcChart">
<charting:Chart.Series>
<charting:LineSeries ItemsSource="{Binding LineItems}" IndependentValuePath="Date" DependentValuePath="Value"/>
</charting:Chart.Series>
</charting:Chart>
</Grid>
MainWindow.xaml.cs
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
//Add a linear Y axis
int YMax = 150;
mcChart.Axes.Add(new LinearAxis()
{
Minimum = 0,
Maximum = YMax > 0 ? YMax : 200,
Orientation = AxisOrientation.Y,
ShowGridLines = true,
});
//Create and set a view model
var items = Enumerable.Range(0, 50).Select(i => new ChartItemModel { Date = new DateTime(2010, 1, 1).AddDays(i), Value = 30 + i }).ToList();
this.DataContext = new MainViewModel { LineItems = items };
}
//Set Maximum=300
private void Button_Click(object sender, RoutedEventArgs e)
{
var yAxis = this.mcChart.ActualAxes.OfType<LinearAxis>().FirstOrDefault(ax => ax.Orientation == AxisOrientation.Y);
if (yAxis != null)
yAxis.Maximum = 300;
}
}
public class MainViewModel
{
public List<ChartItemModel> LineItems { get; set; }
}
public class ChartItemModel
{
public DateTime Date { get; set; }
public double Value { get; set; }
}

aliasing problem

the code below draws two vertical lines on a canvas. these lines appear to be of different thickness on the screen although they are the same in code. i am tying to find a way to make them look as sharp as the border around the canvas. setting Path.SnapsToDevicePixels does not have any effect. The code is a contrived example, and in general the canvas that plots these lines can be nested deeper inside the visual tree.
thanks for any help
konstantin
<Window x:Class="wpfapp.MyWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid>
<Border BorderBrush="Black"
BorderThickness="1"
Margin="10">
<Canvas x:Name="Canvas"
SizeChanged="OnCanvasSizeChanged" />
</Border>
</Grid>
</Window>
using System.Windows;
using System.Windows.Media;
using System.Windows.Shapes;
namespace wpfapp
{
public partial class MyWindow : Window
{
public MyWindow()
{
InitializeComponent();
}
private void OnCanvasSizeChanged(object sender, SizeChangedEventArgs e)
{
StreamGeometry g = new StreamGeometry();
double h = this.Canvas.ActualHeight;
using (StreamGeometryContext c = g.Open())
{
c.BeginFigure(new Point(7, 0), false, false);
c.LineTo(new Point(7, h), true, false);
c.BeginFigure(new Point(14, 0), false, false);
c.LineTo(new Point(14, h), true, false);
}
g.Freeze();
Path p = new Path();
p.Data = g;
p.SnapsToDevicePixels = true;
p.Stroke = new SolidColorBrush(Colors.Black);
p.StrokeThickness = 1;
this.Canvas.Children.Clear();
this.Canvas.Children.Add(p);
}
}
}
need to use GuidelineSet:
protected override void OnRender(DrawingContext c)
{
base.OnRender(c);
Pen pen = new Pen(Brushes.Black, 1);
double h = this.ActualHeight;
double d = pen.Thickness / 2;
foreach (double x in new double[] { 7, 14 })
{
GuidelineSet g = new GuidelineSet(new double[] { x + d },
new double[] { 0 + d, h + d });
c.PushGuidelineSet(g);
c.DrawLine(pen, new Point(x, 0), new Point(x, h));
c.Pop();
}
}

Categories