create inkcanvas class dynamically in wpf with tool tip display - c#

I want to create a multiple inkcanvases with tooltip displayes.so i want to create ink canvas class dynamically.whenever i create instance of inkcanvas class ,a new ink canvas with tool display have to be created in WPF window.
class1 mycanvas1 = new class1(" aa");
class1 mycanvas2 = new class1("bb")
The letter in the string is the text of tool tip display.can u tell me the way .
I created a ink canvas usercontrol with tooltip empty text.but i unable to call this wpf user control in the above way.

InkCanvas Customized class with ToolTip:
[DebuggerDisplay("[{Scene}]Strokes:{Strokes.Count}, Children:{Children.Count}")]
public class InkCanvas_SandeepJadhav : InkCanvas
{
public InkCanvas_SandeepJadhav(string toolTip)
{
ToolTip = toolTip;
}
}
Inkcanvas class created dynamically.
public partial class MainWindow : Window
{
public InkCanvas_SandeepJadhav currCanvas = null;
double width = 0, height = 0, toolWindowHeight = 0;
public MainWindow()
{
InitializeComponent();
this.WindowState = System.Windows.WindowState.Maximized;
width = System.Windows.SystemParameters.WorkArea.Width;
height = System.Windows.SystemParameters.WorkArea.Height;
currCanvas = new InkCanvas_SandeepJadhav("Sandy");
currCanvas.Width = width;
currCanvas.Height = height - 150;
currCanvas.Background = (System.Windows.Media.Brush)new SolidColorBrush(Colors.Lime);
toolWindowHeight = (height / 10);
currCanvas.Margin = new Thickness(0, 0, 0, toolWindowHeight);
myGrid.Children.Add(currCanvas);
}
}
XAML Code
<Window x:Class="WpfMultiInkCanvas.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">
<Grid x:Name="myGrid"></Grid>
</Window>

here my code
namespace strokecollectio
{
class mycan : InkCanvas
{
public mycan()
{
this.Width = 300;
this.Height = 200;
}
}
}

Related

Custom button not rendering correctly

I've got a custom class for a button with a circular image as I'll be using it multiple times through my program. I thought it'd be pretty simple of creating class, inheriting from Button and slapping my setup into a constructor, but when I'm running the program the buttons are massive and plain (no image or text). Here's my class:
public class ImageButton : Button
{
public Button Button;
public ImageButton(string filename) : this(HorizontalAlignment.Center, VerticalAlignment.Center, filename)
{ }
public ImageButton(HorizontalAlignment hAlignment, VerticalAlignment vAlignment, string filename)
{
Button = new Button
{
Width = 35,
Height = 35,
Background = Brushes.Transparent,
HorizontalAlignment = hAlignment,
BorderBrush = Brushes.Transparent,
VerticalAlignment = vAlignment,
Content = new Image
{
Source = new BitmapImage(new Uri("pack://application:,,,/Resources/" + filename))
}
};
}
}
And here's my implementation of one of the instances
private void SetupHeaders(Grid resultGrid)
{
RowDefinition backbtn = new RowDefinition();
backbtn.Height = new GridLength(0.2, GridUnitType.Star);
resultGrid.RowDefinitions.Add(backbtn);
btn_Return = new ImageButton(HorizontalAlignment.Left, VerticalAlignment.Top, "returnicon.png");
Grid.SetRow(btn_Return, 0);
Grid.SetColumn(btn_Return, 0);
resultGrid.Children.Add(btn_Return);
}
with btn_Return being defined at the top of the class as simply
ImageButton btn_Return;
Here's an image of one of the buttons.
In you constructor you inititalize a Button with you properties and then assign it to a property. You never actually use the initialized button. You are always using ImageButton which is nothing more than an inherited button therefore you get the default behavior.
You have to change your constructor.
public ImageButton(HorizontalAlignment hAlignment, VerticalAlignment vAlignment, string filename)
{
Width = 35;
Height = 35;
Background = Brushes.Transparent;
HorizontalAlignment = hAlignment;
BorderBrush = Brushes.Transparent;
VerticalAlignment = vAlignment;
Content = new Image
{
Source = new BitmapImage(new Uri("pack://application:,,,/Resources/" + filename))
};
}

WPF Grid white stripes

I have a Grid with a lot of buttons inside. These buttons are supposed to be seamlessly connecting. In most of the cases, this is actually working, but sometimes there's a white stripe between the columns / rows of the grid:
I'm adding the buttons to the grid via the code behind like this (I'm sorry for non-minimal code, but I really don't know what might be relevant here):
public partial class MainWindow
{
private int _xCount;
private int _yCount;
public MainWindow ()
{
InitializeComponent ();
SetSize (40, 40);
}
public void SetSize (int x, int y)
{
_xCount = x;
_yCount = y;
Grid.ColumnDefinitions.Clear ();
Grid.RowDefinitions.Clear ();
for (var i = 0; i < x; i++)
Grid.ColumnDefinitions.Add (new ColumnDefinition {Width = new GridLength (100, GridUnitType.Star)});
for (var i = 0; i < y; i++)
Grid.RowDefinitions.Add (new RowDefinition {Height = new GridLength (100, GridUnitType.Star)});
for (var xI = 0; xI < x; xI++)
for (var yI = 0; yI < y; yI++)
{
var button = new Button
{
BorderThickness = new Thickness (1),
BorderBrush = Brushes.Gray,
Foreground = Brushes.DarkGray,
Content = "",
Background = Brushes.DarkGray
};
Grid.Children.Add (button);
Grid.SetColumn (button, xI);
Grid.SetRow (button, yI);
}
SetButtonSizes ();
}
private void SetButtonSizes ()
{
var gridWidth = Grid.Width;
var gridHeight = Grid.Height;
var buttonWidth = gridWidth / _xCount;
var buttonHeight = gridHeight / _yCount;
foreach (var button in Grid.Children)
{
((Button) button).Width = buttonWidth;
((Button) button).Height = buttonHeight;
}
}
protected override void OnRenderSizeChanged (SizeChangedInfo sizeInfo)
{
base.OnRenderSizeChanged (sizeInfo);
SetButtonSizes ();
}
}
The WPF is pretty trivial and looks like that:
<Window x:Class="Minesweeper.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="1000"
Width="1000">
<Grid Name="Grid" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"/>
</Window>
I already tried Pixel Snapping, which didn't make any difference.
You should set UseLayoutRounding to true on the Grid and not programmatically resize the Buttons.
However, you could greatly simplify your code by using a UniformGrid
<Window ...>
<UniformGrid x:Name="grid"/>
</Window>
and add Buttons like this:
public MainWindow()
{
InitializeComponent();
SetSize(40, 40);
}
private void SetSize(int x, int y)
{
grid.Children.Clear();
grid.Columns = x;
for (int i = 0; i < x * y; i++)
{
grid.Children.Add(new Button
{
BorderThickness = new Thickness(1),
BorderBrush = Brushes.Gray,
Background = Brushes.DarkGray,
Foreground = Brushes.DarkGray,
Content = ""
});
}
}

How to add a proceduaraly generated billboard to helix 3D

I have a set of procedural images that I would like to add as billboards to my helix 3D application.
Currently my application looks as following:
public partial class _3DControl
{
HelixViewport3D hVp3D;
public _3DControl()
{
InitializeComponent();
createView();
}
public void createView()
{
hVp3D = new HelixViewport3D();
var lights = new SunLight();
lights.Altitude=40;
lights.Ambient=0.4;
this.Content = hVp3D;
hVp3D.Children.Add(lights);
this.Show();
}
public void UploadBillboard(BitmapImage im, System.Windows.Media.Media3D.Point3D position,double width,double height)
{
//create material
var mat = MaterialHelper.CreateImageMaterial(im, 0);
var bboard = new BillboardVisual3D();
bboard.Material = mat;
//set coordinates
bboard.Position = position;
bboard.Width = width;
bboard.Height = height;
//add the billboard
hVp3D.Children.Add(bboard);
}
However when I call the function to add a billboard:
HelixLinker.GetHelix().UploadBillboard(((Bitmap)e).bitmapToBitmapImage(),
new System.Windows.Media.Media3D.Point3D(0, 0, 0), 100, 100);
Then I see nothing being added, any idea what I' m doing wrong?
I also tried with the RectangleVisual3D class.
public void UploadRect(BitmapImage im, System.Windows.Media.Media3D.Point3D position, double width, double height)
{
var mat = MaterialHelper.CreateImageMaterial(im, 0);
var bboard = new RectangleVisual3D ();
bboard.Material = mat;
bboard.Width = width;
hVp3D.Children.Add(bboard);
}
Which if execuded in the same way results in a (promising) image however in this case the material appears not to be properly set.
Note: I hope that the BillboardVisual3D is the right class, I'm working on something that will allow me to put image "on the floor" so to speak, I want to have flat images that don't have a depth and allow for transparancy.
Why do you set the Opacity to 0? Then you wont see anything.
Try this:
//create material
var mat = MaterialHelper.CreateImageMaterial(im);
See the documentation
Edit:
Sorry, my bad with the string. But this ist working for me:
Code:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
CreateBilboard();
}
private void CreateBilboard()
{
BitmapImage im = new BitmapImage(new System.Uri(#"C:\Users\Public\Pictures\Sample Pictures\Lighthouse.jpg"));
var mat = MaterialHelper.CreateImageMaterial(im, 1);
var bboard = new BillboardVisual3D();
bboard.Material = mat;
var position = new System.Windows.Media.Media3D.Point3D(0, 0, 0);
var width = 100;
var height = 100;
//set coordinates
bboard.Position = position;
bboard.Width = width;
bboard.Height = height;
//add the billboard
viewPort.Children.Add(bboard);
}
}
XAML:
<Window x:Class="BillboardImageMaterialDemo.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ht="clr-namespace:HelixToolkit.Wpf;assembly=HelixToolkit.Wpf"
Title="BillboardImageMaterialDemo" Height="480" Width="640">
<Grid>
<ht:HelixViewport3D x:Name="viewPort" ZoomExtentsWhenLoaded="True">
<!-- Remember to add some lights -->
<ht:SunLight/>
</ht:HelixViewport3D>
</Grid>
</Window>
Result:

Server-side rendering of WPF UserControl

I am writing a server side console app in C#/.Net 4.5 that gets some data and creates static chart images that are saved to be displayed by a web server.
I am mostly using the method described here:
http://lordzoltan.blogspot.com/2010/09/using-wpf-to-render-bitmaps.html
However, I added a mainContainer.UpdateLayout(); after the Arrange() so that the databindings would update and be visible in the rendered image, as well as a Measure() before it for good... ah, I'm not gonna go there.
Here is the method that does the rendering:
void RenderAndSave(UIElement target, string filename, int width, int height)
{
var mainContainer = new Grid
{
HorizontalAlignment = HorizontalAlignment.Stretch,
VerticalAlignment = VerticalAlignment.Stretch
};
mainContainer.Children.Add(target);
mainContainer.Measure(new Size(width, height));
mainContainer.Arrange(new Rect(0, 0, width, height));
mainContainer.UpdateLayout();
var encoder = new PngBitmapEncoder();
var render = new RenderTargetBitmap(width, height, 96, 96, PixelFormats.Pbgra32);
render.Render(mainContainer);
encoder.Frames.Add(BitmapFrame.Create(render));
using (var s = File.Open(filename, FileMode.Create))
{
encoder.Save(s);
}
}
The target parameter to the method will be an instance of a WPF/XAML UserControl I made - fairly simple at this point, just a grid with some text databinding to a ViewModel object that I assigned to the DataContext.
The saved image on disk looks good EXCEPT for the OxyPlot Plot object - it is entirely white.
Now, when I am in the designer in Visual Studio 2013, I can see it. I have added a design-time DataContext which is the same object that I use at runtime (this is a spike I am doing - the viewmodel is not in its final form yet, just having a bunch of default data while I work out the kinks). In the designer I see the chart as OxyPlot paints it.
Is there anything special I need to do in order to get my rendering to also contain this OxyPlot chart? It is more or less the point of the exercise so it would be awesome to actually get it to show up!
Thanks in advance for any insights and suggestions!
If you're correctly binding data at runtime as well, then it should work.
[STAThread]
static void Main(string[] args)
{
string filename = "wpfimg.png";
RenderAndSave(new UserControl1(), filename, 300, 300);
PictureBox pb = new PictureBox();
pb.Width = 350;
pb.Height = 350;
pb.Image = System.Drawing.Image.FromFile(filename);
Form f = new Form();
f.Width = 375;
f.Height = 375;
f.Controls.Add(pb);
f.ShowDialog();
}
XAML:
<UserControl x:Class="WpfApp92.UserControl1"
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:oxy="http://oxyplot.org/wpf"
xmlns:local="clr-namespace:WpfApp92"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<oxy:PlotView Model="{Binding Model}"/>
</Grid>
</UserControl>
CS:
public partial class UserControl1 : UserControl
{
public PlotModel Model { get; set; }
public UserControl1()
{
InitializeComponent();
Model = new PlotModel();
Model.LegendBorderThickness = 0;
Model.LegendOrientation = LegendOrientation.Horizontal;
Model.LegendPlacement = LegendPlacement.Outside;
Model.LegendPosition = LegendPosition.BottomCenter;
Model.Title = "Simple model";
var categoryAxis1 = new CategoryAxis();
categoryAxis1.MinorStep = 1;
categoryAxis1.ActualLabels.Add("Category A");
categoryAxis1.ActualLabels.Add("Category B");
categoryAxis1.ActualLabels.Add("Category C");
categoryAxis1.ActualLabels.Add("Category D");
Model.Axes.Add(categoryAxis1);
var linearAxis1 = new LinearAxis();
linearAxis1.AbsoluteMinimum = 0;
linearAxis1.MaximumPadding = 0.06;
linearAxis1.MinimumPadding = 0;
Model.Axes.Add(linearAxis1);
var columnSeries1 = new ColumnSeries();
columnSeries1.StrokeThickness = 1;
columnSeries1.Title = "Series 1";
columnSeries1.Items.Add(new ColumnItem(25, -1));
columnSeries1.Items.Add(new ColumnItem(137, -1));
columnSeries1.Items.Add(new ColumnItem(18, -1));
columnSeries1.Items.Add(new ColumnItem(40, -1));
Model.Series.Add(columnSeries1);
var columnSeries2 = new ColumnSeries();
columnSeries2.StrokeThickness = 1;
columnSeries2.Title = "Series 2";
columnSeries2.Items.Add(new ColumnItem(12, -1));
columnSeries2.Items.Add(new ColumnItem(14, -1));
columnSeries2.Items.Add(new ColumnItem(120, -1));
columnSeries2.Items.Add(new ColumnItem(26, -1));
Model.Series.Add(columnSeries2);
DataContext = this;
}
}
I don't know anything about this OxyPlat, but I do know that most charts are often rendered using hardware APIs. Hardware acceleration is usually error-prone when working outside the expected environment (i.e. a client showing a visible Desktop window).
On application initialization, try disabling hardware acceleration:
RenderOptions.ProcessRenderMode = RenderMode.SoftwareOnly;
Another possible tweak is to call DoEvents() before you render your bitmap. Possibly with priority set to SystemIdle. This will make sure your DataContext has been successfully bound.
public static void DoEvents(
DispatcherPriority priority = DispatcherPriority.Background)
{
Dispatcher.CurrentDispatcher.Invoke(new Action(delegate { }), priority);
}

C# WPF. How to add Ellipces dynamically into canvas?

I'm trying to add some ellipces with random positions into my canvas, but i can see them on my canvas. Progmab is compilling quite saccesfull. Code:
for (int i = 0; i < FirefliesCount; ++i)
{
Firefly CurrentFirefly = new Firefly();
CurrentFirefly.Speed = Randomer.Next(1, 3);
CurrentFirefly.Body = new Ellipse();
CurrentFirefly.Body.Margin = new Thickness(Randomer.Next(10, (int)MainCanvas.Width - 10),
Randomer.Next(10, (int)MainCanvas.Height - 10),
0, 0);
CurrentFirefly.Body.Fill = Brushes.Black;
CurrentFirefly.Body.Height = MainCanvas.Height / 4;
CurrentFirefly.Body.Width = 1.5 * CurrentFirefly.Body.Height;
MainCanvas.Children.Add(CurrentFirefly.Body);
}
And Fireflie class:
class Firefly
{
public Ellipse Body { get; set; }
public int Speed { get; set; }
}
Probably you did not set the Width and Height properties of your MainCanvas; then they have the value NaN and therefore you will not see the ellipses.
My suggestion is to use ActualWidth and ActualHeight instead and to delay the adding of the ellipses until the canvas is loaded. Here is an example:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
MainCanvas.Loaded += MainCanvas_Loaded;
}
void MainCanvas_Loaded(object sender, RoutedEventArgs e)
{
Init();
}
private void Init()
{
const int FirefliesCount = 100;
Random Randomer = new Random();
for (int i = 0; i < FirefliesCount; ++i)
{
Firefly CurrentFirefly = new Firefly();
CurrentFirefly.Speed = Randomer.Next(1, 3);
CurrentFirefly.Body = new Ellipse();
CurrentFirefly.Body.Margin = new Thickness(Randomer.Next(10, (int)MainCanvas.ActualWidth - 10),
Randomer.Next(10, (int)MainCanvas.ActualHeight - 10),
0, 0);
CurrentFirefly.Body.Fill = Brushes.Black;
CurrentFirefly.Body.Height = MainCanvas.ActualHeight / 4;
CurrentFirefly.Body.Width = 1.5 * CurrentFirefly.Body.Height;
MainCanvas.Children.Add(CurrentFirefly.Body);
}
}
}
The corresponding xaml file looks like this:
<Window x:Class="WpfApplication7.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">
<Canvas x:Name="MainCanvas"/>
</Window>

Categories

Resources