I'm trying to draw a set of lines between Ellipses on a canvas. I do this in two steps:
The first section in the XAML below with the ItemsControl bound to 'SingleCL' visualizes the lines using the nested ItemsControl, bound to 'Points'.
The second section, bound tot he same collections, visualizes the ellipses.
'SingleCL' and 'Points' are both ObservableCollection< T >
The Point-class have four properties: VisualHorPos, VisualVerPos, CenterHorPos and CenterVerPos and implements INotifyPropertyChanged. The properties represents X,Y, with the 'Visual'-properties adjusted to represent the upper left corner of the view when placed on a canvas so that when moved around with the mouse, the center is placed where the mouse pointer is.
The points are sorted by their Y-values in their respective collection so that the lines are drawn from bottom to top.
To avoid (hide) the first line that would be drawn from 0,0 to x2,y2 for the very first point in the Point-collection, I'm using a PriorityBinding so that it gets a length of 0, thus in practice hiding it.
The result is the red zig-zag line shown in this image
Adding points below (image wise) - first in the collection - only the ellipses appears, see the blue dots in the image above. If I save the data and reload it from scratch, the lines appear as expected.
Adding points above (image wise) - after another point in the collection - lines are drawn correctly, but the existing lines are not updated to take the new point into account.
I have verified that the points are correctly sorted, both when adding new and when they are moved along the Y-axis.
Perhaps I am asking too much from WPF, but I expected it to draw the lines from point to point, based on the order of the items in the ObservableCollection< T > 'Points' when adding new points, not just the when the binding happens. Also, when moving the points, I expected the lines to refresh so that they always are drawn from bottom to top based on the order in the collection.
The way I see it, the problem is that once the Lines have been created, they are not rebound when objects are moved or added in the collection. Is there a way to make the ItemsControl reevaluate all its items on each Moved/Added/Removed action in the underlying ObservableCollection< T > ?
The "drawing code"
<ItemsControl ItemsSource="{Binding SingleCL}">
<ItemsControl.LayoutTransform>
<TransformGroup>
<ScaleTransform ScaleX="{Binding ElementName=imageZoom, Path=Value}" ScaleY="{Binding ElementName=imageZoom, Path=Value}"/>
</TransformGroup>
</ItemsControl.LayoutTransform>
<ItemsControl.ItemTemplate>
<DataTemplate>
<ItemsControl ItemsSource="{Binding Points}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Line X2="{Binding CenterHorPos, Mode=OneWay}" Y2="{Binding CenterVerPos, Mode=OneWay}" Stroke="{Binding Color}" StrokeThickness="2">
<!-- Bind X1,Y1 to the previous point, or if not available (as for the first data item) to the same as X2,Y2 -->
<Line.X1>
<PriorityBinding>
<Binding Path="CenterHorPos" RelativeSource="{RelativeSource PreviousData}"/>
<!-- This is the value used of the first binding doesn't work -->
<Binding Path="CenterHorPos"/>
</PriorityBinding>
</Line.X1>
<Line.Y1>
<PriorityBinding>
<Binding Path="CenterVerPos" RelativeSource="{RelativeSource PreviousData}"/>
<!-- This is the value used of the first binding doesn't work -->
<Binding Path="CenterVerPos"/>
</PriorityBinding>
</Line.Y1>
</Line>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<!-- Display markers for all centerlines -->
<ItemsControl ItemsSource="{Binding SingleCL}">
<ItemsControl.LayoutTransform>
<TransformGroup>
<ScaleTransform ScaleX="{Binding ElementName=imageZoom, Path=Value}" ScaleY="{Binding ElementName=imageZoom, Path=Value}"/>
</TransformGroup>
</ItemsControl.LayoutTransform>
<ItemsControl.ItemTemplate>
<DataTemplate>
<ItemsControl ItemsSource="{Binding Points}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemContainerStyle>
<Style>
<Setter Property="Canvas.Left" Value="{Binding VisualHorPos}" />
<Setter Property="Canvas.Top" Value="{Binding VisualVerPos}" />
</Style>
</ItemsControl.ItemContainerStyle>
</ItemsControl>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
And the code for the ellipses:
<UserControl x:Class="SMT.View.AutoCalibration.AutoCalibrationMarkerView"
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="300" d:DesignWidth="300" MouseDown="MarkerMouseDown"
MouseUp="MarkerMouseUp"
MouseMove="MarkerMouseMove" Width="10" Height="10"
Background="Transparent">
<Grid Background="Transparent">
<Line X1="0" Y1="5" X2="10" Y2="5" Fill="{Binding Color}" Stroke="{Binding Color}" StrokeThickness="0.5"/>
<Line X1="5" Y1="0" X2="5" Y2="10" Fill="{Binding Color}" Stroke="{Binding Color}" StrokeThickness="0.5"/>
<Ellipse Width="10" Height="10" Stroke="{Binding Color}" StrokeThickness="0.5" Fill="Transparent"/>
</Grid>
Workaround/Solution
As also proposed by #Juan Pablo Garcia Coello in the comments, I ended up with to different collections for the ellipses and lines, the latter one being cleared and refilled as needed.
I am trying to setup a system in a WPF app where the user can select a different theme and the UI updates. To achieve this I am removing one resource dictionary and merging in another one.
Everything is working fine except one scenario.
I have some pages that define a datatemplate. In the datatemplate is a rectangle that is bound to a string property on the viewmodel (using Caliburn.Micro) and I have a converter that converts the string into a drawingbrush (it finds it from the resources).
The problem is that the dynamicresource in the drawingbrush (the color) will not update.
Every other instance of rectangle I have bound the same way (not in a datatemplate) the color of the drawing brush updates perfectly. Only when inside the datatemplate does this problem occur.
Here is a sample of the data template on a view
<DataTemplate x:Key="ListBoxItemTemplate">
<Border Style="{DynamicResource EntitySelectListBox}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Rectangle Grid.Column="0" Fill="{Binding IconName, Converter={converters:StringToResourceConverter}}" Width="50" Height="50" Margin="5" ToolTip="{Binding ToolTip}" />
<TextBlock FontFamily="Segoe WP"
FontWeight="Light"
FontSize="22"
Grid.Column="1"
VerticalAlignment="Center"
HorizontalAlignment="Center"
Text="{Binding ButtonText}" />
</Grid>
</Border>
</DataTemplate>
Here is an example of a drawing brush that has a dynamicresource for the color:
<DrawingBrush x:Key="BankIcon" Viewbox="0,0,442,442" ViewboxUnits="Absolute">
<DrawingBrush.Drawing>
<DrawingGroup>
<DrawingGroup.Transform>
<MatrixTransform Matrix="9.20833333333333,0,0,9.20833333333333,0,0"/>
</DrawingGroup.Transform>
<DrawingGroup>
<DrawingGroup.Transform>
<MatrixTransform Matrix="1,0,0,1,0,2.04885336170188"/>
</DrawingGroup.Transform>
<GeometryDrawing Brush="{DynamicResource SecondaryText}" Geometry="M32.015748,33.342608 L46.283901,33.342608 C47.231779,33.342608 48,34.111116 48,35.061416 L48,40.968297 29.109026,40.968297 C31.057581,39.645195 32.207827,37.567466 32.207827,35.105579 32.207827,34.463728 32.135616,33.879828 32.015748,33.342608 z M1.7188548,33.342608 L21.193252,33.342608 C21.734045,33.580305 22.220392,33.759667 22.584643,33.892346 24.90359,34.727827 24.90359,35.253493 24.90359,35.449457 24.90359,35.986481 23.92294,36.182345 23.261798,36.182345 21.415607,36.182345 19.949486,35.468384 19.243114,35.041909 L17.321123,33.889921 15.507445,40.263165 16.585441,40.951892 0,40.968297 0,35.061416 C8.7927075E-13,34.111116 0.76985754,33.342608 1.7188548,33.342608 z M22.790523,18.230994 L25.366021,18.230994 25.366021,21.121156 C27.345029,21.183175 28.700861,21.687368 29.703128,22.191564 L28.856339,25.079107 C28.100782,24.702539 26.716707,23.982205 24.582318,23.982205 22.381153,23.982205 21.594926,25.110746 21.594926,26.179891 21.594926,27.467599 22.72608,28.221998 25.431822,29.259503 28.949705,30.578852 30.489161,32.27603 30.489161,35.105438 30.489161,37.771993 28.636319,40.099727 25.209281,40.667104 L25.209281,43.902294 22.602338,43.902294 22.602338,40.855485 C20.623328,40.792207 18.644319,40.22619 17.510837,39.502072 L18.362478,36.519611 C19.618635,37.270223 21.344919,37.898937 23.261813,37.898937 25.271298,37.898937 26.620819,36.927818 26.620819,35.449302 26.620819,34.003588 25.522762,33.125251 23.167186,32.27603 19.901545,31.081883 17.733186,29.541929 17.733186,26.651183 17.733186,23.9494 19.618635,21.844013 22.790523,21.279064 z M40.239403,16.937238 L44.995147,16.937238 44.995147,31.067614 40.239403,31.067614 z M32.794241,16.937238 L37.545128,16.937238 37.545128,31.067614 32.794241,31.067614 z M10.453898,16.937238 L15.205758,16.937238 15.205758,31.067614 10.453898,31.067614 z M3.0077641,16.937238 L7.7625359,16.937238 7.7625359,31.067614 3.0077641,31.067614 z M23.952052,0 L24.047946,0.0024883747 C24.709093,0.017653378 25.175256,0.11243361 26.113014,0.68999864 L48,14.939825 24.047946,14.939825 23.952052,14.939825 0,14.939825 21.885821,0.68999864 C22.824745,0.11243361 23.292458,0.017653378 23.952052,0.0024883747 z"/>
</DrawingGroup>
</DrawingGroup>
</DrawingBrush.Drawing>
</DrawingBrush>
Here is a resource dictionary that imports a couple other resource dictionarys. One for styles and one for the vectoricons (they are shared between the skins).
ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="SixtenLabs.CashFlow.Client.Skins.Monochrome">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/Resources/CommonStyles.xaml"/>
<ResourceDictionary Source="/Resources/VectorIcons.xaml"/>
I have tried moving various parts around to different places (app.xaml, window.resources) to no avail. Any ideas would be appreciated.
Thanks.
Try turning off virtualization in your ListBox as you may be recycling containers and the containers wont allways honour changes in DynamicResource bindings.
<ListBox VirtualizingStackPanel.IsVirtualizing="False"
VirtualizingStackPanel.VirtualizationMode="Standard" />
i have no idea to solve the problem with follwing code:
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Window.Resources>
<XmlDataProvider x:Key="InternalData" XPath="/Workspace">
<x:XData>
<Workspace Name="Workspace" xmlns="">
<Project Name="Project 1"/>
<Project Name="Project 2"/>
<Project Name="Project 3"/>
</Workspace>
</x:XData>
</XmlDataProvider>
</Window.Resources>
<StackPanel DataContext="{StaticResource InternalData}">
<ListBox ItemsSource="{Binding XPath=//Workspace/Project}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding XPath=#Name}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<TextBox Text="{Binding XPath=//Workspace/Project[1]/#Name, Mode=TwoWay}"/>
</StackPanel>
</Window>
As you can see, i can change the Name of the first Project in the Workspace with the TextBox.
By changing the data, i want to start an animation to fade out the old value, change the value and start an animation to fade in the new value (e.g. opacity of "Project 1" from 1 to 0, change data and opacity of "" from 0 to 1)
If possible, i wanted to implement the solution only in XAML. But no idea. Maybe something with DataTrigger and EnterAction and ExitAction or stuff like that?
Kind regards
Shounborugh
You might want to try looking in to WPF storyboards. This is a common practice if you want to start an animation using only XAML. This is the best place to start about storyboards in WPF
http://msdn.microsoft.com/en-us/library/ms742868.aspx
This is how you can start the storyboard upon changing the text in the textbox
<TextBox Height="23" HorizontalAlignment="Left" Margin="90,44,0,0" Name="textBox1" VerticalAlignment="Top" Width="120">
<TextBox.Triggers>
<EventTrigger RoutedEvent="TextBox.TextChanged">
<BeginStoryboard>
<Storyboard>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</TextBox.Triggers>
</TextBox>
I created a full-screen WPF Canvas, representing a time line. Only the visible part of the time line is composed, so (practically) no UI elements lie outside of the visible range.
I'm trying to add perspective to this time line using a Viewport3D. The result at the moment looks as follows:
You can scroll the time line left and right by dragging. Performance in the 2D version is great. However, once the canvas is placed inside a Viewport3D using Viewport2DVisual3D, performance drops drastically.
It's not like I'm rendering a complex mesh, where is this performance decrease coming from, and can I prevent it?
To give you an idea of how the 3D perspective was realized I'll add the XAML code here, unfortunately it doesn't work on its own.
<Grid Background="{StaticResource BackgroundBrush}">
<Viewport3D ClipToBounds="False">
<Viewport3D.Camera>
<PerspectiveCamera
Position="0 0 5"
LookDirection="0.4 0 -1"
UpDirection="0 1 0" />
</Viewport3D.Camera>
<ContainerUIElement3D>
<ModelUIElement3D>
<AmbientLight Color="White" />
</ModelUIElement3D>
</ContainerUIElement3D>
<Viewport2DVisual3D>
<Viewport2DVisual3D.Geometry>
<MeshGeometry3D
TriangleIndices="0,1,2 2,3,0"
TextureCoordinates="0 0, 0 1, 1 1, 1 0">
<MeshGeometry3D.Positions>
<MultiBinding Converter="{StaticResource AspectRatioToPositions}">
<Binding ElementName="TimeLineContainer" Path="Width" />
<Binding ElementName="TimeLineContainer" Path="Height" />
</MultiBinding>
</MeshGeometry3D.Positions>
</MeshGeometry3D>
</Viewport2DVisual3D.Geometry>
<Viewport2DVisual3D.Material>
<DiffuseMaterial
Viewport2DVisual3D.IsVisualHostMaterial="True"
Brush="White" />
</Viewport2DVisual3D.Material>
<Grid
x:Name="TimeLineContainer"
Width="1650" Height="600"
ClipToBounds="True"
Background="{StaticResource TimeLineBrush}"
Behaviors:MouseBehavior.LeftClickDragCommand="ActivityOverview:ActivityOverviewWindow.MouseDragged"
MouseWheel="OnMouseWheel"
MouseMove="OnMouseMoved">
<ActivityOverview:TimeLineControl x:Name="TimeLine" Focusable="True">
<ActivityOverview:TimeLineControl.CommandBindings>
<CommandBinding
Command="ActivityOverview:ActivityOverviewWindow.MouseDragged"
Executed="MoveTimeLine" />
</ActivityOverview:TimeLineControl.CommandBindings>
</ActivityOverview:TimeLineControl>
</Grid>
</Viewport2DVisual3D>
</Viewport3D>
</Grid>
When using Viewport2DVisual3D performance can be slow when you attempt to display content that is time-consuming to render. This seemed to be the case in my example.
For this reason, you can set the CacheMode of Viewport2DVisual3D.
<Viewport2DVisual3D>
<Viewport2DVisual3D.CacheMode>
<BitmapCache />
</Viewport2DVisual3D.CacheMode>
...
</Viewport2DVisual3D>
Starting from Windows Vista, anti-aliasing is enabled by default. Disabling this also helps in improving performance. It's weird this would have a big impact with such a simple mesh (two triangles), but on my PC, it does!
<Viewport3D ClipToBounds="False" RenderOptions.EdgeMode="Aliased">
Combining these two settings, I got great improvements.
Hi guys you can use <OrthographicCamera Position="0 0 5" LookDirection="0.4 0 -1" UpDirection="0 1 0" /> . Please check my code below
<Grid Background="{StaticResource BackgroundBrush}">
<Viewport3D ClipToBounds="False">
<Viewport3D.Camera>
<OrthographicCamera
Position="0 0 5"
LookDirection="0.4 0 -1"
UpDirection="0 1 0" />
</Viewport3D.Camera>
<ContainerUIElement3D>
<ModelUIElement3D>
<AmbientLight Color="White" />
</ModelUIElement3D>
</ContainerUIElement3D>
<Viewport2DVisual3D>
<Viewport2DVisual3D.Geometry>
<MeshGeometry3D
TriangleIndices="0,1,2 2,3,0"
TextureCoordinates="0 0, 0 1, 1 1, 1 0">
<MeshGeometry3D.Positions>
<MultiBinding Converter="{StaticResource AspectRatioToPositions}">
<Binding ElementName="TimeLineContainer" Path="Width" />
<Binding ElementName="TimeLineContainer" Path="Height" />
</MultiBinding>
</MeshGeometry3D.Positions>
</MeshGeometry3D>
</Viewport2DVisual3D.Geometry>
<Viewport2DVisual3D.Material>
<DiffuseMaterial
Viewport2DVisual3D.IsVisualHostMaterial="True"
Brush="White" />
</Viewport2DVisual3D.Material>
<Grid
x:Name="TimeLineContainer"
Width="1650" Height="600"
ClipToBounds="True"
Background="{StaticResource TimeLineBrush}"
Behaviors:MouseBehavior.LeftClickDragCommand="ActivityOverview:ActivityOverviewWindow.MouseDragged"
MouseWheel="OnMouseWheel"
MouseMove="OnMouseMoved">
<ActivityOverview:TimeLineControl x:Name="TimeLine" Focusable="True">
<ActivityOverview:TimeLineControl.CommandBindings>
<CommandBinding
Command="ActivityOverview:ActivityOverviewWindow.MouseDragged"
Executed="MoveTimeLine" />
</ActivityOverview:TimeLineControl.CommandBindings>
</ActivityOverview:TimeLineControl>
</Grid>
</Viewport2DVisual3D>
</Viewport3D>
I am looking for a way to set a gradientbrush as the background for a listbox item. I have a DataTemplate defined and have specified a gradient brush but it always appears as the listbox background (i.e. it never shows as a gradient brush).
I have been able to set the background of the listbox itself, and I can set the listboxitem's background to a standard color using the "setter" object....but none of these are what I am after.
I really want the background on each list item to be a gradient brush.
Below is the datatemplate that I have constructed.
<ListBox Name="MyListBox" Margin="12,67,12,169">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid Height="51" VerticalAlignment="Bottom">
<Grid.Background>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FFC9F4D0"/>
<GradientStop Color="#FF2AC12A" Offset="0.333"/>
<GradientStop Color="#FF35DE35" Offset="1"/>
</LinearGradientBrush>
</Grid.Background>
<Canvas >
<dataInput:Label Width="227" Foreground="Yellow" Canvas.Left="158" Canvas.Top="8" Content="{Binding Place}"/>
<dataInput:Label Width="146" Foreground="Yellow" Canvas.Left="8" Canvas.Top="8" Content="{Binding Date}"/>
<dataInput:Label Content="{Binding People}" Width="346" FontSize="9.333" Foreground="Black" Canvas.Left="166" Canvas.Top="28"/>
<!-- <dataInput:Label Width="45" Content="Accept" Foreground="White" Canvas.Left="8" Canvas.Top="28"/>
<dataInput:Label Width="45" Content="Decline" Foreground="White" Canvas.Left="57" Canvas.Top="28"/> -->
<dataInput:Label Content="SomeText" Width="101" FontSize="9.333" Foreground="White" Canvas.Left="389" Canvas.Top="10"/>
<Image Height="21" Width="21" Canvas.Left="500" Canvas.Top="8" Source="Green Button.png"/>
</Canvas>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Any Thoughts?
What is happening in your data template:
The background of the grid is being set to the color you need. However on top of this Grid, your Canvas is getting painted. Hence the linear gradient background is invisible.
How to correct this?
Set Canvas.Background={Binding}
For which ever control within the canvas that you wish to inherit the Grid.Background to, set that control's Background={Binding}
Sample Code:
</Grid.ColumnDefinitions>-->
<Canvas Background="{Binding}">
<TextBox Width="227" Canvas.Left="158" Canvas.Top="8" Foreground="Yellow" Text="{Binding Name}" Background="{Binding}"/>
<TextBox Width="146" Canvas.Left="8" Canvas.Top="8" Foreground="Yellow" Text="{Binding Language}" Background="{Binding}"/>
</Canvas>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Hope this helps!
What you are doing is correct its doesn't sets the background of your listbox, it sets the background of your listboxitem only. I think you couldn't figure it out.
To figure it out just give the margin to u r grid 5 and then see.What you are doing is correct its doesn't sets the background of your listbox, it sets the background of your listboxitem only. I think you couldn't figure it out.
To figure it out just give the margin to u r grid 5 and then see.