How do I create a WPF Rounded Corner container? - wpf

We are creating an XBAP application that we need to have rounded corners in various locations in a single page and we would like to have a WPF Rounded Corner container to place a bunch of other elements within. Does anyone have some suggestions or sample code on how we can best accomplish this? Either with styles on a or with creating a custom control?

You don't need a custom control, just put your container in a border element:
<Border BorderBrush="#FF000000" BorderThickness="1" CornerRadius="8">
<Grid/>
</Border>
You can replace the <Grid/> with any of the layout containers...

I know that this isn't an answer to the initial question ... but you often want to clip the inner content of that rounded corner border you just created.
Chris Cavanagh has come up with an excellent way to do just this.
I have tried a couple different approaches to this ... and I think this one rocks.
Here is the xaml below:
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Background="Black"
>
<!-- Rounded yellow border -->
<Border
HorizontalAlignment="Center"
VerticalAlignment="Center"
BorderBrush="Yellow"
BorderThickness="3"
CornerRadius="10"
Padding="2"
>
<Grid>
<!-- Rounded mask (stretches to fill Grid) -->
<Border
Name="mask"
Background="White"
CornerRadius="7"
/>
<!-- Main content container -->
<StackPanel>
<!-- Use a VisualBrush of 'mask' as the opacity mask -->
<StackPanel.OpacityMask>
<VisualBrush Visual="{Binding ElementName=mask}"/>
</StackPanel.OpacityMask>
<!-- Any content -->
<Image Source="http://chriscavanagh.files.wordpress.com/2006/12/chriss-blog-banner.jpg"/>
<Rectangle
Height="50"
Fill="Red"/>
<Rectangle
Height="50"
Fill="White"/>
<Rectangle
Height="50"
Fill="Blue"/>
</StackPanel>
</Grid>
</Border>
</Page>

I just had to do this myself, so I thought I would post another answer here.
Here is another way to create a rounded corner border and clip its inner content. This is the straightforward way by using the Clip property. It's nice if you want to avoid a VisualBrush.
The xaml:
<Border
Width="200"
Height="25"
CornerRadius="11"
Background="#FF919194"
>
<Border.Clip>
<RectangleGeometry
RadiusX="{Binding CornerRadius.TopLeft, RelativeSource={RelativeSource AncestorType={x:Type Border}}}"
RadiusY="{Binding RadiusX, RelativeSource={RelativeSource Self}}"
>
<RectangleGeometry.Rect>
<MultiBinding
Converter="{StaticResource widthAndHeightToRectConverter}"
>
<Binding
Path="ActualWidth"
RelativeSource="{RelativeSource AncestorType={x:Type Border}}"
/>
<Binding
Path="ActualHeight"
RelativeSource="{RelativeSource AncestorType={x:Type Border}}"
/>
</MultiBinding>
</RectangleGeometry.Rect>
</RectangleGeometry>
</Border.Clip>
<Rectangle
Width="100"
Height="100"
Fill="Blue"
HorizontalAlignment="Left"
VerticalAlignment="Center"
/>
</Border>
The code for the converter:
public class WidthAndHeightToRectConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
double width = (double)values[0];
double height = (double)values[1];
return new Rect(0, 0, width, height);
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}

VB.Net code based implementation of kobusb's Border control solution. I used it to populate a ListBox of Button controls. The Button controls are created from MEF extensions. Each extension uses MEF's ExportMetaData attribute for a Description of the extension. The extensions are VisiFire charting objects. The user pushes a button, selected from the list of buttons, to execute the desired chart.
' Create a ListBox of Buttons, one button for each MEF charting component.
For Each c As Lazy(Of ICharts, IDictionary(Of String, Object)) In ext.ChartDescriptions
Dim brdr As New Border
brdr.BorderBrush = Brushes.Black
brdr.BorderThickness = New Thickness(2, 2, 2, 2)
brdr.CornerRadius = New CornerRadius(8, 8, 8, 8)
Dim btn As New Button
AddHandler btn.Click, AddressOf GenericButtonClick
brdr.Child = btn
brdr.Background = btn.Background
btn.Margin = brdr.BorderThickness
btn.Width = ChartsLBx.ActualWidth - 22
btn.BorderThickness = New Thickness(0, 0, 0, 0)
btn.Height = 22
btn.Content = c.Metadata("Description")
btn.Tag = c
btn.ToolTip = "Push button to see " & c.Metadata("Description").ToString & " chart"
Dim lbi As New ListBoxItem
lbi.Content = brdr
ChartsLBx.Items.Add(lbi)
Next
Public Event Click As RoutedEventHandler
Private Sub GenericButtonClick(sender As Object, e As RoutedEventArgs)
Dim btn As Button = DirectCast(sender, Button)
Dim c As Lazy(Of ICharts, IDictionary(Of String, Object)) = DirectCast(btn.Tag, Lazy(Of ICharts, IDictionary(Of String, Object)))
Dim w As Window = DirectCast(c.Value, Window)
Dim cc As ICharts = DirectCast(c.Value, ICharts)
c.Value.CreateChart()
w.Show()
End Sub
<System.ComponentModel.Composition.Export(GetType(ICharts))> _
<System.ComponentModel.Composition.ExportMetadata("Description", "Data vs. Time")> _
Public Class DataTimeChart
Implements ICharts
Public Sub CreateChart() Implements ICharts.CreateChart
End Sub
End Class
Public Interface ICharts
Sub CreateChart()
End Interface
Public Class Extensibility
Public Sub New()
Dim catalog As New AggregateCatalog()
catalog.Catalogs.Add(New AssemblyCatalog(GetType(Extensibility).Assembly))
'Create the CompositionContainer with the parts in the catalog
ChartContainer = New CompositionContainer(catalog)
Try
ChartContainer.ComposeParts(Me)
Catch ex As Exception
Console.WriteLine(ex.ToString)
End Try
End Sub
' must use Lazy otherwise instantiation of Window will hold open app. Otherwise must specify Shutdown Mode of "Shutdown on Main Window".
<ImportMany()> _
Public Property ChartDescriptions As IEnumerable(Of Lazy(Of ICharts, IDictionary(Of String, Object)))
End Class

If you're trying to put a button in a rounded-rectangle border, you should check out msdn's example. I found this by googling for images of the problem (instead of text). Their bulky outer rectangle is (thankfully) easy to remove.
Note that you will have to redefine the button's behavior (since you've changed the ControlTemplate). That is, you will need to define the button's behavior when clicked using a Trigger tag (Property="IsPressed" Value="true") in the ControlTemplate.Triggers tag. Hope this saves someone else the time I lost :)

Related

WPF binding backgrounds as SolidColorBrush

I have this grid:
<Grid x:Name="topGrid" Height="100" VerticalAlignment="Top" Margin="10,0,0,0" />
In my code if I set the background like this:
topGrid.Background = "#FF3C3C3C".ToBrush()
Using this extension:
Module Extensions
<Extension()>
Function ToBrush(ByVal HexColorString As String) As SolidColorBrush
Return CType((New BrushConverter().ConvertFrom(HexColorString)),
SolidColorBrush)
End Function
End Module
I can change background just fine, but i have around 20 grids on my form and i want to change backgrounds of all grids at once using bindings.
I have tried doing it like this:
This is xml:
<Grid x:Name="topGrid" Background="{Binding MyBackgroundColor}" Height="100" VerticalAlignment="Top" Margin="10,0,0,0" >
This is code:
Private Sub button1_Click(sender As Object, e As RoutedEventArgs) Handles button1.Click
MyBackgroundColor = "#FF3C3C3C".ToBrush()
End Sub
Private _myBackgroundColor As SolidColorBrush
Public Property MyBackgroundColor() As SolidColorBrush
Get
Return _myBackgroundColor
End Get
Set
_myBackgroundColor = Value
End Set
End Property
Public Sub New()
InitializeComponent()
End Sub
If you want to change all the backgrounds on many grids then a style is another way to go.
Although this is c# there's very little code and you could run it through an online converter.
I've done this in app.xaml for quickness but you'd want to put it in a resource dictionary merged in app.xaml in a proper app.
<Application.Resources>
<SolidColorBrush x:Key="gridBackgroundBrush" Color="Blue"/>
<Style TargetType="{x:Type Grid}">
<Setter Property="Background" Value="{DynamicResource gridBackgroundBrush}"/>
</Style>
</Application.Resources>
</Application>
And you can change that brush:
private void Button_Click_1(object sender, RoutedEventArgs e)
{
Color colour = (Color)ColorConverter.ConvertFromString("#FFD700");
Application.Current.Resources["gridBackgroundBrush"] = new SolidColorBrush(colour);
}
If you don't want one or two grids to have this behaviour you could just set their background to white or transparent and this will have precedence over the style.
If your requirement is instead more complicated then you could lose the style and instead use the resource directly as DynamicResource. Which might be what Clemens means.
<Grid Background="{DynamicResource gridBackgroundBrush}"

How do I find the image in a WPF Datagrid ColumnHeader so I can change the image?

I'm attempting to implement Excel-like column filtering and sorting. To do this, I used a DataTemplate to define the Column Header.
<DataGrid x:Name="dataGrid" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" CanUserSortColumns="False">
<DataGrid.Resources>
<Style TargetType="{x:Type DataGridColumnHeader}">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="23"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Button x:Name="ExcelFilterButton" Tag="{Binding}" Click="ExcelFilterButton_Click" Margin="0,0,0,0" BorderThickness="0" Style="{StaticResource {x:Static ToolBar.ButtonStyleKey}}" Focusable="False" Grid.Column="0">
<Image Source="Resources\NoSortNoFilter.png" Width="19" Height="19" />
</Button>
<TextBlock Text="{Binding}" HorizontalAlignment="Center" VerticalAlignment="Center" Grid.Column="1" />
</Grid>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</DataGrid.Resources>
</DataGrid>
And it comes out nicely.
I tried using VisualTreeHelper to find the image from the Column Header, but the Header property is a string. I've tried using the HeaderStyle and HeaderTemplate properties also but to no avail.
Using a WPF Spy program called Snoop, I can see the image in there, but still can't figure out how to access it in code. The reason I need to access it in code is to change the image based on whether that column is sorted and/or filtered. (Could this be done in XAML?)
Ok, I figured out how to do it. This most likely not the right way to do it, but I found a way that works.
To give you a little about the process.
The user clicks a header button. The buttons Tag property is bound to the column header.
The click event handler instantiates the context menu and sets its Tag to equal the button Tag.
The user clicks on a menu item.
The event handler sends the Context Menu Tag property and image name to the routine that finds the button, and then the image in the button, and changes the image.
now for the code.
The button click event handler:
Private Sub ExcelFilterButton_Click(sender As Object, e As RoutedEventArgs)
With DirectCast(Resources("sortContextMenu"), ContextMenu)
.Tag = DirectCast(sender, Button).Tag
.IsOpen = True
End With
End Sub
The menu item click event handler
Private Sub ContextMenuItem_Click(Sender As Object, e As RoutedEventArgs)
If TypeOf Sender Is MenuItem Then
'just testing, of course this isn't all this handler does.
SetColumnSortImage(Sender.Tag, "Filtered")
End If
End Sub
The SetColumnSortImage routine, which calls the two following routines.
Private Sub SetColumnSortImage(Tag As String, ImageName As String)
Dim btn As Button = Nothing
GetSortButton(Of Button)(dataGrid, Tag, btn)
If btn IsNot Nothing Then
Dim img As Image = GetChildOfType(Of Image)(btn)
img.Source = New BitmapImage(New Uri("pack://application:,,,/Resources/" & ImageName & ".png"))
End If
End Sub
The GetSortButton routine
Private Sub GetSortButton(Of T As DependencyObject)(dep As DependencyObject, Tag As String, ByRef out As DependencyObject)
If dep IsNot Nothing Then
If TypeOf dep Is Button AndAlso CType(dep, Button).Tag = Tag Then
out = dep
Else
If VisualTreeHelper.GetChildrenCount(dep) > 0 Then
For i As Integer = 0 To VisualTreeHelper.GetChildrenCount(dep) - 1
GetSortButton(Of T)(VisualTreeHelper.GetChild(dep, i), Tag, out)
Next
End If
End If
End If
End Sub
This routine was found elsewhere on StackOverflow in C#. I converted it to VB.
Private Function GetChildOfType(Of T As DependencyObject)(depObj As DependencyObject) As T
If depObj Is Nothing Then
Return Nothing
End If
For i As Integer = 0 To VisualTreeHelper.GetChildrenCount(depObj) - 1
Dim child = VisualTreeHelper.GetChild(depObj, i)
Dim result = If(TryCast(child, T), GetChildOfType(Of T)(child))
If result IsNot Nothing Then
Return result
End If
Next
Return Nothing
End Function
You may have a better way. Please post if you do.

Wpf UserControl with its own data context and external dependency property

I'm trying to create a simple AudioPlayer control multiple reuse in a solution I'm working on. I have seen numerous example in various posts and blogs around the net and from those have created a small control with four buttons.
The xaml is defined thus:
<UserControl x:Class="AudioPlayer"
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"
d:DesignHeight="30" d:DesignWidth="150">
<StackPanel Orientation="Horizontal">
<StackPanel.Resources>
<Style TargetType="{x:Type Button}">
<Setter Property="Margin" Value="10,0,0,0" />
</Style>
</StackPanel.Resources>
<MediaElement Name="media" Source="{Binding Source}" LoadedBehavior="{Binding LoadedBehavior}"/>
<Button Width="24" Height="24" x:Name="Repeat" Background="Transparent" BorderBrush="Transparent">
<Image Source="Images/button_blue_repeat.png" ToolTip="Repeat"/>
</Button>
<Button Width="24" Height="24" x:Name="Play" Background="Transparent" BorderBrush="Transparent">
<Image Source="Images/button_blue_play.png" ToolTip="Play"/>
</Button>
<Button Width="24" Height="24" x:Name="Pause" Background="Transparent" BorderBrush="Transparent">
<Image Source="Images/button_blue_pause.png" ToolTip="Pause"/>
</Button>
<Button Width="24" Height="24" x:Name="Stop" Background="Transparent" BorderBrush="Transparent">
<Image Source="Images/button_blue_stop.png" ToolTip="Stop"/>
</Button>
</StackPanel>
With fairly simple code in the background;
Public Class AudioPlayer
Public Sub New()
InitializeComponent()
DataContext = New AudioPlayerViewModel With {.MediaElement = media, .Source = "bag1.mp3", .LoadedBehavior = MediaState.Manual, .CanCommandExecute = True}
End Sub
End Class
Public Class AudioPlayerViewModel
Inherits DependencyObject
Public Sub New()
Me.MediaCommand = New MediaElementCommand(Me)
End Sub
Public Property MediaElement() As MediaElement
Public Property Source() As String
Public Property LoadedBehavior() As MediaState
Public Property CanCommandExecute() As Boolean
Public Property MediaCommand() As ICommand
End Class
Public Class MediaElementCommand
Implements ICommand
Private vm As AudioPlayerViewModel
Public Sub New(ByVal vm As AudioPlayerViewModel)
Me.vm = vm
End Sub
Public Function CanExecute(ByVal parameter As Object) As Boolean Implements ICommand.CanExecute
Return vm.CanCommandExecute
End Function
Public Custom Event CanExecuteChanged As EventHandler Implements ICommand.CanExecuteChanged
AddHandler(ByVal value As EventHandler)
AddHandler CommandManager.RequerySuggested, value
End AddHandler
RemoveHandler(ByVal value As EventHandler)
RemoveHandler CommandManager.RequerySuggested, value
End RemoveHandler
RaiseEvent(ByVal sender As System.Object, ByVal e As System.EventArgs)
End RaiseEvent
End Event
Public Sub Execute(ByVal parameter As Object) Implements ICommand.Execute
Dim action As String = DirectCast(parameter, String)
Select Case action.ToLower()
Case "play"
vm.MediaElement.Position = TimeSpan.Zero
vm.MediaElement.Play()
Case "stop"
vm.MediaElement.Stop()
Case "pause"
vm.MediaElement.Pause()
Case "resume"
vm.MediaElement.Play()
Case Else
Throw New NotSupportedException(String.Format("Unknown media action {0}", action))
End Select
End Sub
End Class
My question quite simply is this. From the code you can see that at present the sound that is being played is hard coded. What I would like to know is wheteher it would be possible to create a dependency property for this control (I presume it would be of type string to represent a path to a sound file but I'm not sure) so that when the control is created in other controls or windows their viewmodels can pass a sound property to it (if that makes sense!).
If it is possible where should I create it in respect of the code snippets shown?
Many thanks
You could create a DP, but it would not work the way users would expect.
For example, if the user were to write
<local:AudioPlayer Media="{Binding SomeString}" />
Then WPF tries to set Media = DataContext.SomeString
But since you have hardcoded DataContext = New AudioPlayerViewModel in the constructor, then the binding will most likely fail because users will be expecting their inherited DataContext to be used by the UserControl, but the hardcoded DataContext will be used instead.
It is always my advice to never hardcode the DataContext property inside of a UserControl. It breaks the entire WPF design pattern of having separate layers for UI and Data.
Either build a UserControl specifically for use with a specific Model or ViewModel being used as the DataContext, such as this :
<!-- Draw anything of type AudioPlayerViewModel with control AudioPlayer -->
<!-- DataContext will automatically set to the AudioPlayerViewModel -->
<DataTemplate DataType="{x:Type local:AudioPlayerViewModel}}">
<local:AudioPlayer />
</DataTemplate>
Or build it with the expectation that the DataContext can be absolutely anything, and DependencyProperites will be used to give the control the data it needs :
<!-- DataContext property can be anything, as long as it as the property MyString -->
<local:AudioPlayer Media="{Binding MyString}" />
The easiest way to get your code to work would probably be
Create the ViewModel as a private property instead of assiging it to the UserControl.DataContext
Bind or set the DataContext of the top level child inside your UserControl to your private property (in your case, the StackPanel)
Adjust the binding for your MediaElement to read from a custom DependencyProperty instead of from StackPanel.DataContext
Something like this :
<UserControl x:Name="MyAudioPlayer" ...>
<StackPanel x:Name="AudioPlayerRoot">
...
<MediaElement Source="{Binding ElementName=MyAudioPlayer, Path=MediaDependecyProperty}" ... />
...
</StackPanel>
</UserControl>
Public Sub New()
InitializeComponent()
AudioPlayerRoot.DataContext = New AudioPlayerViewModel ...
End Sub

WPF: Placing a textbox randomly on a canvas

I have a canvas of sorts derived from a 'Panel' used for custom drawing of lines and other geometries, all from VB code. I got this approach from a book and I'm not sure it's the best approach. The drawing part works so far for me.
But what I need is to put a textbox control on the control containing text which can be edited by the user. The textbox needs to be placed at coordinates determined dynamically and later deleted. There will probably be other controls handled so.
The following code does nothing:
tb = New TextBox()
tb.Text = "How now brown cow?"
tb.BorderThickness = New Thickness(3)
tb.BorderBrush = Brushes.CadetBlue
drawingSurface.Children.Add(tb)
This is the definition of my DrawingCanvas:
Public Class DrawingCanvas
Inherits Panel
Private visuals As New List(Of Visual)()
Private hits As New List(Of DrawingVisual)()
Protected Overrides Function GetVisualChild(ByVal index As Integer) As Visual
Return visuals(index)
End Function
Protected Overrides ReadOnly Property VisualChildrenCount() As Integer
Get
Return visuals.Count
End Get
End Property
Public Sub AddVisual(ByVal visual As Visual)
visuals.Add(visual)
MyBase.AddVisualChild(visual)
MyBase.AddLogicalChild(visual)
End Sub
Public Sub DeleteVisual(ByVal visual As Visual)
visuals.Remove(visual)
MyBase.RemoveVisualChild(visual)
MyBase.RemoveLogicalChild(visual)
End Sub
Public Function GetVisual(ByVal point As Point) As DrawingVisual
Dim hitResult As HitTestResult = VisualTreeHelper.HitTest(Me, point)
Return TryCast(hitResult.VisualHit, DrawingVisual)
End Function
Public Function GetVisuals(ByVal region As Geometry) As List(Of DrawingVisual)
hits.Clear()
Dim parameters As New GeometryHitTestParameters(region)
Dim callback As New HitTestResultCallback(AddressOf Me.HitTestCallback)
VisualTreeHelper.HitTest(Me, Nothing, callback, parameters)
Return hits
End Function
Private Function HitTestCallback(ByVal result As HitTestResult) As HitTestResultBehavior
Dim geometryResult As GeometryHitTestResult = CType(result, GeometryHitTestResult)
Dim visual As DrawingVisual = TryCast(result.VisualHit, DrawingVisual)
If visual IsNot Nothing AndAlso geometryResult.IntersectionDetail = IntersectionDetail.FullyInside Then
hits.Add(visual)
MsgBox("Ouch")
End If
Return HitTestResultBehavior.Continue
End Function
End Class
Here is the XAML. I added a textbox to the DrawingCanvas just to see if something appears. Nothing did. In fact, I want to do this in code, not XAML. I thought I could hide or move it around dynamically.
<Window x:Class="MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Music"
Title="MainWindow" Height="539" Width="892">
<DockPanel>
<Menu DockPanel.Dock="Top" Name="MainMenu" VerticalAlignment="Top" Height="25">
<MenuItem Name="File" Header="File">
<MenuItem Name="Open" Header="Bla bla..."/>
</MenuItem>
</Menu>
<local:DrawingCanvas DockPanel.Dock="Bottom" x:Name="drawingSurface" RenderTransformOrigin="0.5,0.5" >
<TextBox Height="0" Name="TextBox1" Width="45" Text="How now brown cow?" />
</local:DrawingCanvas>
</DockPanel>
</Window>
Thanks for helping a nooby. A solution would be very useful for me. This was easy with windows forms, but I need the drawing speed of WPF.
I think you are a bit off here. In WPF you have a control called Canvas. I would suggest you use that instead of your own "DrawingCanvas", which I can't get to work btw. :( (For some reason I cant create code blocks so if someone can edit it I would be pleased)
Anyhow,
<local:DrawingCanvas DockPanel.Dock="Bottom" x:Name="drawingSurface" RenderTransformOrigin="0.5,0.5" >
<TextBox Height="0" Name="TextBox1" Width="45" Text="How now brown cow?" />
</local:DrawingCanvas>
Turns into:
<Canvas x:Name="drawingSurface">
</Canvas>
And then to add a textbox just do as your current code:
Dim tb as New TextBox
drawingSurface.Children.Add(tb)
This should give you what you need.
Heres the code for adding a rectangle to your canvas.
Private Sub DrawBackground()
Dim Rect As New Rectangle()
Rect.Height = 50
Rect.Width = 50
Rect.Fill = Brushes.Cornsilk
drawingSurface.SetTop(Rect, 30)
drawingSurface.SetLeft(Rect, 100)
drawingSurface.Children.Add(Rect)
End Sub
I'll add another answer that might be more in the line of what you are looking for. This is a class that inherits from Canvas that will allow you to draw stuff in the same way as say you do in your comment.
I also creates a textbox on a random location when it is created.
Public Class DrawingCanvas
Inherits Canvas
Public RandomTextBox As New TextBox
Protected Overrides Sub OnRender(dc As System.Windows.Media.DrawingContext)
Dim brush As Brush = Brushes.Black
Dim drawingPen As Pen = New Pen(Brushes.Green, 3)
dc.DrawRectangle(brush, drawingPen, New Rect(5, 5, Me.ActualWidth - 5, Me.ActualHeight - 5))
RandomTextBox.Text = "Herpdiderp"
If Not Me.Children.Contains(RandomTextBox) Then
Dim r As New Random()
RandomTextBox.Height = 23
RandomTextBox.Width = 100
Me.SetTop(RandomTextBox, r.Next(0, Me.ActualHeight - RandomTextBox.Height))
Me.SetLeft(RandomTextBox, r.Next(0, Me.ActualWidth - RandomTextBox.Width))
Me.Children.Add(RandomTextBox)
End If
End Sub
End Class
This is not a full answer. #WozzeC, you were right about using the canvas - almost.
I have managed to solve this in xaml alone - I want to eventually solve it in vb.net.
<Window x:Class="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>
<DockPanel HorizontalAlignment="Stretch" Name="DockPanel1" VerticalAlignment="Stretch" >
<Menu Height="23" DockPanel.Dock="Top" Name="Menu1" VerticalAlignment="Top" />
<Canvas Name="Canvas1" Background="Aquamarine">
<TextBox Canvas.Left="118" HorizontalScrollBarVisibility="Disabled" Canvas.Top="81" AcceptsReturn="True" Height="auto" Name="TextBox1" Width="68" Text="Herpdiderp" BorderThickness="0" Background="Aquamarine" />
</Canvas>
</DockPanel>
</Grid>
And here is a piece of code that expands the text as needed. I think it's almost totally cool. It expands both to the right and downwards, as if you're actually typing on the form. It adds a little too much on the right, but it's not visible in this version because the background color is the same.
Here is the event code that expands it to the right.
Imports System.Globalization
Class MainWindow
Private Sub TextBox1_TextChanged(sender As System.Object, e As System.Windows.Controls.TextChangedEventArgs) Handles TextBox1.TextChanged
Dim ft As New FormattedText(TextBox1.Text, CultureInfo.GetCultureInfo("en-us"), FlowDirection.LeftToRight, New Typeface("Verdana"), 16, Brushes.Black)
TextBox1.Width = ft.Width
End Sub
End Class
I tried this with my existing solution and the textbox does not appear. I made the DrawingCanvas into a plain Canvas and commented out all the code referring to the DrawingCanvas. And the textbox does appear. The problem is this: I need the functionality in the DrawingCanvas - which derives from Canvas. But because the baseclass methods are Protected, I can't get to them. I can only use them in a derived class, unless there is another way I don't know about.
Any ideas about how to solve this?

WPF - The value specified in System.Windows.Markup.StaticResourceHolder caused an exception

So Once again i came here to get some anwsers to problems i can't resolve them by myself, so my problem is im getting a xamlparse execption each time the button style is loaded, inside the style i have a < rectangle > that should get one color defined by the user from a query on my MVVM. So far there was no problems, the problem is trying to give that color value to the grandientstop inside the LinearGradientBrush of the rectangle. The xaml code im using:
<Rectangle x:Name="rectangle" Fill="{Binding Path=StrColor, Converter={StaticResource FadingBrushConverter}, RelativeSource={RelativeSource AncestorType={x:Type Rectangle}}}" HorizontalAlignment="Right" Height="70" Margin="0,0,0,0" RadiusY="5" RadiusX="5" VerticalAlignment="Bottom" Width="70">
<Rectangle.Effect>
<DropShadowEffect ShadowDepth="1" BlurRadius="8"/>
</Rectangle.Effect>
</Rectangle>
The "StrColor" is a Color property.
On my MVVM i have this converter:
Public Class FadingBrushConverter
Implements IValueConverter
Public Function Convert(value As Object, targetType As System.Type, parameter As Object, culture As System.Globalization.CultureInfo) As Object Implements System.Windows.Data.IValueConverter.Convert
' TODO: Do some type-checking
Dim brush = New LinearGradientBrush()
Dim color = DirectCast(value, Color)
Dim Bcolor As System.Windows.Media.Color
Bcolor.R = 0
Bcolor.G = 0
Bcolor.B = 0
brush.StartPoint = New Point(0.5, 0)
brush.EndPoint = New Point(0.5, 1.27)
brush.GradientStops.Add(New GradientStop(color, 0))
brush.GradientStops.Add(New GradientStop(Bcolor, 1))
Return brush
End Function
Public Function ConvertBack(value As Object, targetType As System.Type, parameter As Object, culture As System.Globalization.CultureInfo) As Object Implements System.Windows.Data.IValueConverter.ConvertBack
Throw New NotSupportedException()
End Function
End Class
I really dont know what am i doing wrong here, i have been looking on the internet but so far i had no luck in fixing this problem!
I also have used DynamicResource but with no success!
Thanks for any help!
I think the problem is with the binding. "Fill" property of the Rectangle is bound to the strColor property of its parent Rectangle (with the "RelativeSource FindAncestor" argument). I don't think it is realistic to assume that a rectangle is placed in another rectangle. Even if is is somehow the case, the built-in Rectangle element doesn't have a strColor property. If you want to get the color from the ViewModel, you should try something in the sort of:
{Binding Path=StrColor, Converter={StaticResource FadingBrushConverter}"
Of course, this is assuming that the DataContext is set correctly.

Resources