I am trying to print a chart generated during a report. I am able to put the chart on a DocumentPaginator document, but I am having trouble resizing the chart to fit the page. I noticed that if I changed the size of the reporting program which would change the Charts size would affect the scaling of the Chart. This realization showed me that the Chart's ActualWidth and ActualHeight were directly linked to the scaling.
I tried:
myChart.Width = newWidth;
myChart.Height = newHeight;
Measure(myChart.RenderSize);
Arrange(new Rect(0, 0, newWidth, newHeight));
But this caused my visual Chart in the reporting program to resize and the printable chart wouldn't resize to the new size until the second print.
Realizing that myChart was connected to reportChart I tried to copy/clone reportChart to myChart.
I tried:
public class Copy<T>
{
public static T DeepCopy<T>(T element)
{
string xaml = XamlWriter.Save(element);
StringReader xamlString = new StringReader(xaml);
XmlTextReader xmlTextReader = new XmlTextReader(xamlString);
var DeepCopyobject = (T)XamlReader.Load(xmlTextReader);
return DeepCopyobject;
}
}
or
myChart = XamlReader.Parse(XamlWriter.Save(reportChart.DataContext)) as Chart
but string xaml = XamlWriter.Save(element); would take too long and both would cause a stackoverflow.
I am using
myChart = new Chart() { DataContext = reportChart.DataContext }
to make my copy, but ActualWidth and ActualHeight come across '0' so I can't tell if the Chart's DataContext copied correctly.
I did get my Chart to resize using
myChart.Width = newWidth;
myChart.Height = newHeight;
myChart.Measure(new System.Windows.Size(newWidth, newHeight));
myChart.Arrange(new Rect(0, 0, newWidth, newHeight));
or to say my Chart's ActualWidth and ActualHeight to update to the size I want, but I am getting a black image on my document where the chart should be.
So how do I print a chart with it properly scaled to a selected paper size?
So I found something that works for me. I don't feel it is the cleanest way to do it.
Since I need to scale the Chart I am trying to print I need to copy/clone the Chart.
I used myNewChart = new Chart() { DataContext = myOldChart.DataContext } like stated before.
I added a new window to my project, and rendered my new chart in there so I don't get a black image from it.
ConvertingWindow.xaml Code. This code matches my orignal Chart's code.
<Window x:Class="QScanReportPrinting.ConvertingWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="ConvertingWindow"
xmlns:cht="clr-namespace:System.Windows.Controls.DataVisualization.Charting;assembly=System.Windows.Controls.DataVisualization.Toolkit">
<Grid>
<Grid.Resources>
<!-- CutomColumnStyle Style -->
<Style x:Key="CutomColumnStyle" TargetType="cht:ColumnDataPoint">
<!--Background Color-->
<Setter Property="Background" Value="{Binding barColor}"/>
<!--Annotations, or column value labels-->
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="cht:ColumnDataPoint">
<Grid>
<Rectangle Fill="{TemplateBinding Background}" Stroke="Black"/>
<Grid Margin="0 -20 0 0" HorizontalAlignment="Center" VerticalAlignment="Top">
<TextBlock Text="{TemplateBinding FormattedDependentValue}" FontWeight="Bold" Margin="2">
<TextBlock.RenderTransform>
<RotateTransform Angle="-60" />
</TextBlock.RenderTransform>
</TextBlock>
</Grid>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Grid.Resources>
<!--Chart for Graph-->
<cht:Chart x:Name="UI_Chart" Title="{Binding GraphTitle}" Background="White">
<cht:Chart.Series>
<cht:ColumnSeries Title="{Binding ChartKey}" ItemsSource="{Binding GraphDataCollection}" IndependentValueBinding="{Binding Path=X}" DependentValueBinding="{Binding Path=Y}"
DataPointStyle="{StaticResource CutomColumnStyle}">
<cht:ColumnSeries.IndependentAxis>
<cht:CategoryAxis Orientation="X">
<cht:CategoryAxis.AxisLabelStyle>
<Style TargetType="cht:AxisLabel">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="cht:AxisLabel">
<TextBlock Text="{TemplateBinding FormattedContent}">
<TextBlock.LayoutTransform>
<RotateTransform Angle="-60"/>
</TextBlock.LayoutTransform>
</TextBlock>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</cht:CategoryAxis.AxisLabelStyle>
</cht:CategoryAxis>
</cht:ColumnSeries.IndependentAxis>
</cht:ColumnSeries>
</cht:Chart.Series>
</cht:Chart>
</Grid>
Then in my VM I call.
private void GetChartVisual()
{
// Initialize variable
cw = new ConvertingWindow();
cw.UI_Chart.DataContext = myNewChart.DataContext;
// Set MainWindow to be the owner of this window
cw.Owner = Application.Current.MainWindow;
// Set DataContext to this DataContext
// Allows binding with variables already loaded
cw.DataContext = this;
cw.Show();
myNewChart = cw.UI_Chart;
cw.Close();
}
By doing this it renders my visual. I then can resize it to what I want and not affect my original Chart. Not the prettiest thing, but it works.
Related
I have a ListBox with a Canvas as ItemsPanel.
<UserControl.Resources>
<DataTemplate x:Key="itemTemplate">
<Border BorderBrush="LightBlue" BorderThickness="1">
<Grid Margin="0,2,2,2" Width="{Binding Width}" Height="{Binding Height}">
<Rectangle Cursor="Hand" Fill="AliceBlue"
MouseDown="Rectangle_MouseDown"
MouseMove="Rectangle_MouseMove"
MouseUp="Rectangle_MouseUp"/>
<Label Content="{Binding Name}" Margin="5" IsHitTestVisible="False"/>
</Grid>
</Border>
</DataTemplate>
</UserControl.Resources>
<ListBox ItemsSource="{Binding Items}"
x:Name="listBox"
SelectionMode="Extended"
ItemTemplate="{StaticResource itemTemplate}">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<Canvas Background="Transparent"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="Canvas.Left" Value="{Binding X}"/>
<Setter Property="Canvas.Top" Value="{Binding Y}"/>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
The problem is that whenever I add a new item to Items, which Listbox is binding to, it only shows that new item on screen. All previous items in the list are not shown. I can see that all the items are indeed in the Items list, and ListBoxItems are added to the visual tree. But I cannot see them. Only the last item added.
This is what it looks like running (only ever one item is shown)
This is what it looks like in designer and how it should look like running
Any suggestions?
UPDATE 1
The code the designer uses is this
public class DrawingPanelViewModelMockup: DrawingPanelViewModel
{
public DrawingPanelViewModelMockup()
{
//Pc subclasses DrawingComponent
var pc = new Pc();
pc.Name = "PC";
pc.X = 20;
pc.Y = 40;
pc.Width = 100;
pc.Height = 50;
Items.Add(pc);
...
}
}
And the real code that adds to Items (ObservableCollection) is this. It's part of a Drag-n-drop operation.
var comp = e.Data.GetData(typeof(DrawingComponent).FullName) as DrawingComponent;
var drawingPanelVm = ServiceLocator.Current.GetInstance<DrawingPanelViewModel>();
comp.X = mousePos.X;
comp.Y = mousePos.Y;
comp.Width = 100;
comp.Height = 50;
drawingPanelVm.Items.Add(comp);
The XAML works fine, and you've confirmed that there's only one copy of the viewmodel created, hence only one Items collection, and the first drop works.
Looking at your code, what jumps out at me is this line:
var comp = e.Data.GetData(typeof(DrawingComponent).FullName) as DrawingComponent;
That's not creating a DrawingComponent; it's pulling one out of a hat that something else put it into. I'd put a breakpoint in there and see if you're actually getting multiple items in Items, but they're all the same actual object instance, with the same property values.
Or I'd just go straight to the code that starts the drag, and make sure you're creating a new DrawingComponent every time -- or else create a clone each time on the drop end. Doing it on the drag end seems better though, because then you can drag different subclasses of DrawingComponent from different sources and the drop code doesn't need to worry about it.
I am designing a View in XAML, and somewhere in the layout there is an Image element, which will be put inside some combination of ViewBox, ScrollViewer and Inkcanvas (not sure about the order yet). Current early prototype is like this:
<Window x:Class="InkCanvasTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow"
x:Name="ThisWindow">
<DockPanel x:Name="root" DataContext="{Binding ElementName=ThisWindow}">
<StackPanel Orientation="Horizontal" DockPanel.Dock="Bottom" HorizontalAlignment="Center" Margin="0,0,5,0">
<StackPanel.Resources>
<Style TargetType="{x:Type Button}" x:Key="EstiloBotão">
<Setter Property="Height" Value="40"/>
<Setter Property="Width" Value="130" />
<Setter Property="Margin" Value="5,5,0,5" />
</Style>
</StackPanel.Resources>
<Button Content="Limpar Alterações" Style="{DynamicResource EstiloBotão}"/>
<Button Content="Concluir" Style="{DynamicResource EstiloBotão}" Click="Concluir_Click" />
</StackPanel>
<!-- Magic Happens Here -->
<ScrollViewer HorizontalScrollBarVisibility="Visible" VerticalScrollBarVisibility="Visible" PanningMode="Both" Width="752">
<InkCanvas x:Name="cv" Cursor="Cross" Width="{Binding Width, ElementName=canvas_image}" Height="{Binding Height, ElementName=canvas_image}" >
<Image x:Name="canvas_image" Stretch="Uniform" Source="C:\Users\helton\Desktop\franjas_binarizadas.png"/>
</InkCanvas>
</ScrollViewer>
</DockPanel>
</Window>
I cannot know beforehand what will be the dimensions of the source image, but I want to be sure that the Image element has its Width and Height properly "setup". The reason is that I will paint over the image (which is inside an InkCanvas element) and then save the result as an image with the same size as the source image.
Currently, my "Save" method does this:
private void Concluir_Click(object sender, RoutedEventArgs e)
{
int dWidth = (int)cv.ActualWidth; // SHOULD BE Width not ActualWidth, but is zero!!!
int dHeight = (int)cv.ActualHeight; // Here the same thing
double dpiX = 96;
double dpiY = 96;
RenderTargetBitmap rtb = new RenderTargetBitmap(dWidth, dHeight, dpiX, dpiY, PixelFormats.Pbgra32);
rtb.Render(cv);
PngBitmapEncoder pnge = new PngBitmapEncoder();
pnge.Frames.Add(BitmapFrame.Create(rtb));
Stream stream = File.Create("franjas_binarizadas_limpas.png");
pnge.Save(stream);
stream.Close();
}
THE PROBLEM: when I try to read "Width" or "Height", they are zero. When I read "ActualHeight" or "ActualWidth", sometimes they are not the value I am expecting (due to the ScrollView clipping, or the ViewBox scale layout transform).
THE GOAL: Set the Image's Width and Height properties to be equal of its Source image (via binding, or somehow else).
Any ideas?
Set the Stretch Property to None. That will make the Image control maintain the size of the original bitmap.
<Image Stretch="None"/>
Imagine a form designer with a grid overlay that would represent coordinates on a plane. I'm trying to bind the properties of the grid overlay to the Canvas within a custom ItemsControl.
The grid is created using a VisualBrush. The VisualBrush's Viewbox and Viewport are bound to a Rect in the code, as well are the Height and Width of the Rectangle used to display the grid tile. However, when the control displays, the grid tiles seem to be "infinitely small" (the grid is just grey) in that if I zoom into the grid, the program will eventually just seize up, unable to render it. Obviously, this is not the effect I'm going for.
<Style TargetType="{x:Type Controls:FormControl}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Controls:FormControl}">
<Border Background="White"
BorderBrush="Black"
BorderThickness="1"
Padding="49">
<Grid Height="{TemplateBinding CanvasHeight}"
Width="{TemplateBinding CanvasWidth}">
<Grid.Background>
<!--"0,0,6,11.3266666666667"-->
<VisualBrush TileMode="Tile"
Viewbox="{TemplateBinding GridUnitViewbox}"
ViewboxUnits="Absolute"
Viewport="{TemplateBinding GridUnitViewbox}"
ViewportUnits="Absolute">
<VisualBrush.Visual>
<Rectangle Height="{Binding RelativeSource={RelativeSource TemplatedParent},Path=GridUnitViewbox.Height}"
HorizontalAlignment="Left"
Opacity="{TemplateBinding GridOpacity}"
Stroke="Black"
StrokeThickness=".1"
VerticalAlignment="Top"
Width="{Binding RelativeSource={RelativeSource TemplatedParent},Path=GridUnitViewbox.Width}" />
</VisualBrush.Visual>
</VisualBrush>
</Grid.Background>
<ItemsPresenter />
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<Canvas />
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
<Setter Property="ItemContainerStyle">
<Setter.Value>
<Style TargetType="Controls:FormControlItem">
<Setter Property="Canvas.Left"
Value="{Binding Path=X}" />
<Setter Property="Canvas.Top"
Value="{Binding Path=Y}" />
</Style>
</Setter.Value>
</Setter>
</Style>
Any idea what I am doing wrong here. Thanks.
EDIT:
Maybe a little more background of what I'm doing may put it in better context. I work for a tax preparation software company and, currently, our forms division creates substitute forms using a markup that was written for our product like a million years ago. It's a bit cumbersome creating forms this way, so I'm developing a visual "Form Designer" for them that will be more like a WYSIWYG and translate the contents of the designer into markup. Well, the IRS is real anal about everything on the form being EXACTLY where it was on the original, so there is a very loose standard by which a "grid overlay" can be placed over the form to determine where things need to go; basically a coordinate plane of sorts.
FormControl is essentially the visual representation of one of these substitute forms that one of the forms designers would be creating.
CanvasWidth and CanvasHeight are CLR wrappers to Dependency Properties. They are assigned values in OnApplyTemplate() by multiplying the dimensions of GridUnitViewbox by however many grid tiles need to be in the grid overlay, ie. a 78x63 grid in most cases.
The names CanvasWidth and CanvasHeight I think might be a little misleading in that they do not refer to the Canvas control, but to the Grid that houses the Canvas (probably need to change the naming convention). That said, CanvasHeight, CanvasWidth and GridUnitViewbox are not dependent on any control's properties, but rather calculations that are done in OnApplyTemplate().
public static readonly DependencyProperty GridUnitViewboxProperty =
DependencyProperty.Register("GridUnitViewbox", typeof(Rect), typeof(FormControl),
new FrameworkPropertyMetadata(new Rect(0, 0, 6, 11.3266666666667),
FrameworkPropertyMetadataOptions.AffectsMeasure |
FrameworkPropertyMetadataOptions.AffectsParentMeasure));
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
FormattedText formattedText = new FormattedText(
"X",
CultureInfo.GetCultureInfo("en-us"),
FlowDirection.LeftToRight,
new Typeface("Courier New"),
10,
Brushes.Black);
this.GridUnitViewbox = new Rect(0, 0, formattedText.WidthIncludingTrailingWhitespace, formattedText.Height);
if (this.PageLayout == PageLayoutType.Landscape)
{
this.CanvasHeight = this.GridUnitViewbox.Height * 48.0;
this.CanvasWidth = this.GridUnitViewbox.Width * 109.0;
}
if (this.PageLayout == PageLayoutType.Portrait)
{
this.CanvasHeight = this.GridUnitViewbox.Height * 63.0;
this.CanvasWidth = this.GridUnitViewbox.Width * 78.0;
}
}
The Grid control is actually doing exactly what I want it to do. It is the VisualBrush and the Rectangle within that are either not binding correctly or are not being updated properly. The comment right below <Grid.Background> was the hard-coded testing value that I was using for VisualBrush's Viewbox and Viewport as well as Rectangle's dimensions before I got around to binding the values and it produced, visually, exactly what I was going for. I've also confirmed that 6 and 11.3266666666667 are, in fact, the values for the GridUnitViewbox's dimensions during runtime.
I have a feeling that the binding is producing '0,0,0,0' however, because the grid overlay is just a grey shading that is eating up an immense amount of resources; locks the program, in fact, if you zoom into it. As you can see, in the code I tried adding AffectsMeasure and AffectsParentMeasure to the Metadata options of the dependency property in hopes that perhaps the UI was not updating properly after GridUnitViewbox's dimensions were updated, but I was wrong. I'm not sure what else it could be.
Alright, just in case anyone else encounters a similar issue, I found the workaround. Apparently VisualBrush is a little finicky about TemplateBindings. I adjusted the XAML thusly and it solved the problem:
<VisualBrush TileMode="Tile"
Viewbox="{Binding RelativeSource={RelativeSource TemplatedParent},Path=GridUnitViewbox}"
ViewboxUnits="Absolute"
Viewport="{Binding RelativeSource={RelativeSource TemplatedParent},Path=GridUnitViewbox}"
ViewportUnits="Absolute">
Here is the article where I got the information from.
What is CanvasWidth and CanvasHeight? Are they defined?
Also, I believe that a canvas has no size unless explicitly specified. When you bind to it, the width/height may be zero.
Try ActualWidth and ActualHeight or the canvas after the rendering pass to see if they contain any values, but afaik they don't unless you provide one.
I am learning WPF and am trying to follow some sort of best practice. I am kind of lost at the moment, and need some direction.
I am creating a very simple app that reads a text file (error log) and splits it into the individual error messages. I want to display these messages (stored in a model object) as a list of messages. Since the list can consist of many items and I want the window to be resizeable, I need a a vertical scroll bar, but I want the content to wrap (i.e. no need for a horizontal scroll bar).
<Window x:Class="ErrorLog.UI.WPF.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="800" Width="1200" Loaded="Window_Loaded">
<StackPanel Name="mainContainer">
<StackPanel Orientation="Horizontal" Name="Menu">
<Button Name="Refresh">Refresh</Button>
</StackPanel>
<ScrollViewer VerticalScrollBarVisibility="Auto">
<StackPanel Name="errorMessagePlaceHolder"></StackPanel>
</ScrollViewer>
</StackPanel>
I am at the moment reading the file in the code behind and adding to the stackPanel as a bunch of textboxes with the value being the error message. I have also added some mouseover effects like this:
private void LoadData()
{
IErrorLogReader errorLogReader = new ErrorLogReader();
var errors = errorLogReader.RetrieveErrors();
if (errors.Count == 0)
{
TextBox noErrors = new TextBox();
noErrors.Text = "No errors found";
errorMessagePlaceHolder.Children.Add(noErrors);
}
else
{
for (var i = errors.Count - 1; i > 0; i--)
{
TextBox errorMessage = new TextBox();
errorMessage.IsReadOnly = true;
errorMessage.Padding = new Thickness(10);
errorMessage.Text = errors[i].ErrorMessage;
errorMessage.TextWrapping = TextWrapping.Wrap;
errorMessage.MouseEnter += ErrorMessageMouseEnter;
errorMessage.MouseLeave += ErrorMessageMouseLeave;
errorMessagePlaceHolder.Children.Add(errorMessage);
}
}
}
protected void ErrorMessageMouseEnter(object sender, RoutedEventArgs e)
{
((TextBox) sender).Background = Brushes.AntiqueWhite;
}
protected void ErrorMessageMouseLeave(object sender, RoutedEventArgs e)
{
((TextBox) sender).Background = null;
}
So the first things I want to know is:
Is the way I am binding ok?
Scroll bar is coming up disabled
Is the way I am doing the mouseover effect bad?
Cheers.
Is the way I am binding ok?
It might work, but it's not best practice. Best practice is to use actual data binding. First, you need to replace your StackPanel with something that can be bound to a list. An ItemsControl is the thing closest to a simple StackPanel, other options would be, for example, a ListBox.
<ScrollViewer VerticalScrollBarVisibility="Auto">
<ItemsControl Name="errorMessageList" />
</ScrollViewer>
private void LoadData()
{
IErrorLogReader errorLogReader = new ErrorLogReader();
var errors = errorLogReader.RetrieveErrors();
errorMessageList.ItemsSource = errors;
}
To specify how you want the error messages to be displayed, you can set a template for the ItemsControl:
<ScrollViewer VerticalScrollBarVisibility="Auto">
<ItemsControl Name="errorMessageList">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBox IsReadOnly="true" ... Text="{Binding ErrorMessage}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
Scroll bar is coming up disabled
You are nesting your ScrollViewer inside a StackPanel... that won't work: The StackPanel takes as much vertical space as it needs, so the ScrollViewer will always have enough space and never show the scroll bar. You need to replace your top-level StackPanel by something that takes only as much space as is available; a DockPanel, for example:
<DockPanel Name="mainContainer">
<StackPanel DockPanel.Dock="Top" Orientation="Horizontal" Name="Menu">
<Button Name="Refresh">Refresh</Button>
</StackPanel>
<ScrollViewer VerticalScrollBarVisibility="Auto">
<StackPanel Name="errorMessagePlaceHolder"></StackPanel>
</ScrollViewer>
</StackPanel>
Is the way I am doing the mouseover effect bad?
That can be done with a style and a trigger instead. Define the following style:
<Window ...>
<Window.Resources>
<Style x:Key="hoverTextBox" TargetType="{x:Type TextBox}">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="AntiqueWhite" />
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>
...
</Window>
and assign it to your TextBox inside the DataTemplate:
<TextBox IsReadOnly="true" ... Text="{Binding ErrorMessage}"
Style="{StaticResource hoverTextBox}" />
I need to do this in order to create a dynamic background brush for a custom control (inherits ContentControl). My custom control has two dependency properties: StartColor and EndColor. In the control template for the custom control, the control is wrapped in a border that's background is a RadialGradientBrush with gradient stops. one gradient stop's color is bound to StartColor and the other's is bound to EndColor. I have this WORKING in XAML, but I need to convert it to VB code. The border element of the control template in XAML is done with the following code:
<Style x:Key="{x:Type wpf:MyControl}"
TargetType="{x:Type wpf:MyControl}"
BasedOn="{StaticResource {x:Type ContentControl}}">
<Style.Setters>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type wpf:MyControl}">
...
<Border HorizontalAlignment="Stretch"
x:Name="background" Width="Auto"
Grid.RowSpan="3"
Opacity="0.9"
CornerRadius="{TemplateBinding CornerRadius}">
<Border.Background>
<Custom:RadialGradientBrush>
<Custom:GradientStop Color="{Binding Path=EndColor,
RelativeSource={RelativeSource TemplatedParent},
Mode=OneWay}"
Offset="0.462"/>
<Custom:GradientStop Color="{Binding StartColor,
RelativeSource={RelativeSource TemplatedParent},
Mode=OneWay}"
Offset="1"/>
</Custom:RadialGradientBrush>
</Border.Background>
</Border>
...
</ControlTemplate>
</Setter.Value>
</Setter>
</Style.Setters>
</Style>
I tried to create the border in VB code as follows, but it did not work:
...
Dim backgroundBorder As New FrameworkElementFactory(GetType(Border))
With backgroundBorder
.Name = "background"
.SetValue(Grid.RowSpanProperty, 3)
.SetValue(Grid.OpacityProperty, 0.9)
.SetBinding(Border.CornerRadiusProperty, New Binding("CornerRadius") With {.RelativeSource = New RelativeSource(RelativeSourceMode.TemplatedParent)})
End With
Dim backgroundBrush As New RadialGradientBrush()
Dim startColorGradientStop As New GradientStop()
startColorGradientStop.Offset = 1.0
BindingOperations.SetBinding(startColorGradientStop, GradientStop.ColorProperty, New Binding("StartColor") With {.RelativeSource = New RelativeSource(RelativeSourceMode.TemplatedParent), .Mode = BindingMode.OneWay})
backgroundBrush.GradientStops.Add(startColorGradientStop)
Dim endColorGradientStop As New GradientStop()
endColorGradientStop.Offset = 0.462
BindingOperations.SetBinding(endColorGradientStop, GradientStop.ColorProperty, New Binding("EndColor") With {.RelativeSource = New RelativeSource(RelativeSourceMode.TemplatedParent), .Mode = BindingMode.OneWay})
backgroundBrush.GradientStops.Add(endColorGradientStop)
backgroundBorder.SetValue(Border.BackgroundProperty, backgroundBrush)
...
Any ideas of how I can accomplish this in VB code?
Do you know the FrameworkElementFactory approach is not recommended anymore, according to MS? The recommended approach is to create any element/resource in code with XamlReader.Parse.
You have to access the Parent ContentControl to which the Border should be a Content. And set that in your VB code.
What I meant by ContentControl here is whichever control is the parent of the Border, you need to access that on your OnApplyTemplate override function and add your VB.NET created border as child to that visual.