How to set fill between two parallel lines WPF? - wpf

My apologies for such a basic question, if it is.
The issue is I am supposed to draw two parallel lines or two parallel curves on a canvas. I want to set a color between those two non-intersecting lines. I am using two Polylines to draw them.
Any help is appreciated. Thanks in advance.
Code:
<Canvas.LayoutTransform>
<ScaleTransform CenterX="0" CenterY="0" ScaleY="-1" ScaleX="1"/>
</Canvas.LayoutTransform>
<Polyline Name="MyLine1" Points="{Binding BindPoints1,Mode=TwoWay}" Stroke="Black" StrokeThickness="4" Grid.Row="0" />
<Polyline Name="MyLine2" Points="{Binding BindPoints2,Mode=TwoWay}" Stroke="Black" StrokeThickness="4" Grid.Row="0" />
And C#
public class ViewModel : ViewModelBase
{
private ImageSource m_CreatedImage;
public PointCollection BindPoints1 { get; set; }
public PointCollection BindPoints2 { get; set; }
public ViewModel()
{
BindPoints1 = new PointCollection();
BindPoints2 = new PointCollection();
for (int i = 0; i < 1000; i++)
{
double val = (i * i) - 5;
var point = new Point(i, i+20);
BindPoints1.Add(point);
}
BindPoints2 = new PointCollection();
for (int i = 0; i < 1000; i++)
{
double val = (i * i) + 5;
var point = new Point(i, i-20);
BindPoints2.Add(point);
}
}
}

The best thing is to define a grid and divide it into 4-5 rows first.
In the first and last row add the line. Span the middle 2-3 rows and add a shape there say rectangle or ellipse as per your requirement, and just fill it with the required color.
Check the sample below.
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApplication1"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525"
>
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Polyline Name="MyLine1" Grid.Row="0" Points="{Binding BindPoints1,Mode=TwoWay}" Stroke="Black" StrokeThickness="4" />
<Polyline Name="MyLine2" Grid.Row="4" Points="{Binding BindPoints2,Mode=TwoWay}" Stroke="Black" StrokeThickness="4" />
<Rectangle Grid.Row="1" Grid.RowSpan="3" Fill="Red" />
</Grid>
</Window>

Create a third point collection that contains all the points of the first line and all the points of the second line. The points in the second line need to be reversed. Think of it like walking to the end of a street down one side, crossing, then returning down the other side.
Bind a new Line to this third set of points and set Fill instead of the Stroke and draw it before drawing your other lines/arcs.
<Polyline Name="FillLine" Points="{Binding BindPoints3,Mode=TwoWay}" Fill="Green" Grid.Row="0"/>
<Polyline Name="MyLine1" Points="{Binding BindPoints1,Mode=TwoWay}" Stroke="Black" StrokeThickness="4" Grid.Row="0" />
<Polyline Name="MyLine2" Points="{Binding BindPoints2,Mode=TwoWay}" Stroke="Black" StrokeThickness="4" Grid.Row="0" />
view model:
public class ViewModel : ViewModelBase
{
private ImageSource m_CreatedImage;
public PointCollection BindPoints1 { get; set; }
public PointCollection BindPoints2 { get; set; }
public PointCollection BindPoints3 { get; set; }
public ViewModel()
{
BindPoints1 = new PointCollection();
BindPoints2 = new PointCollection();
for (int i = 0; i < 1000; i++)
{
double val = (i * i) - 5;
var point = new Point(i, i + 20);
BindPoints1.Add(point);
}
BindPoints2 = new PointCollection();
for (int i = 0; i < 1000; i++)
{
double val = (i * i) + 5;
var point = new Point(i, i - 20);
BindPoints2.Add(point);
}
BindPoints3 = new PointCollection(BindPoints1.OfType<Point>().Concat(BindPoints2.OfType<Point>().Reverse()));
}
}

Related

WPF and MVVM: Use RotateTransform and DoubleAnimation to move an object along circular path

I'm relatively new to WPF animations. I would like to have an object (a simple circle for example) move around a circular path in 10 degree increments. The following example is tantalizingly close: WPF circular moving object See the answer by Clemens who uses a RotateTransform in XAML and a DoubleAnimation in code-behind. I am however, using MVVM and it's not clear to me how to accomplish this. I believe I would need to access the RotateTransform which is in the View from my ViewModel, so I can call BeginAnimation, but how?
Any examples or ideas? I have searched without luck.
Thanks
UPDATE: I can now be more specific in my question by showing what I've already tried. Based on the above mentioned reference AND Twoway-bind view's DependencyProperty to viewmodel's property? (answer by #Michael Schnerring), I have the following simple code (below). My ellipse is not rotating. No binding errors, or any other errors, just no rotation. And my methods are hit (I debugged into it) I'm guessing my PerformAnimation function is incorrect, specifically the SetTargetProperty part. I did try to play with it by adding two animations (one for Rotation, one for Transform) but without luck.
Can someone give me an idea what I'm doing wrong?
XAML:
<Canvas Grid.Row="0" Grid.Column="0">
<Ellipse Height="100" Width="100" Fill="Aqua" Name="MyEllipse"
Canvas.Left="200" Canvas.Top="200"
RenderTransformOrigin="0.5,0.5">
<Ellipse.RenderTransform>
<TransformGroup>
<TranslateTransform Y="-100"/>
<RotateTransform />
</TransformGroup>
</Ellipse.RenderTransform>
</Ellipse>
</Canvas>
<Button Grid.Row="0" Grid.Column="1" VerticalAlignment="Center" HorizontalAlignment="Center" Command="{Binding Path=RotateCommand}">Press Me!</Button>
Code-behind
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
var nameOfPropertyInVm = "AngleProperty";
var binding = new Binding(nameOfPropertyInVm) { Mode = BindingMode.TwoWay };
this.SetBinding(AngleProperty, binding);
}
public double Angle
{
get { return (double)GetValue(AngleProperty); }
set { SetValue(AngleProperty, value); }
}
// Using a DependencyProperty as the backing store for Angle. This enables animation, styling, binding, etc...
public static readonly DependencyProperty AngleProperty = DependencyProperty.Register("Angle", typeof(double), typeof(MainWindow), new UIPropertyMetadata(0.0, new PropertyChangedCallback(AngleChanged)));
private static void AngleChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
MainWindow control = (MainWindow)sender;
control.PerformAnimation((double)e.OldValue, (double)e.NewValue);
}
private void PerformAnimation(double oldValue, double newValue)
{
Storyboard s = new Storyboard();
DoubleAnimation animation = new DoubleAnimation();
animation.From = oldValue;
animation.To = newValue;
animation.Duration = new Duration(TimeSpan.FromSeconds(1));
s.Children.Add(animation);
Storyboard.SetTarget(animation, MyEllipse);
Storyboard.SetTargetProperty(animation, new PropertyPath("(Ellipse.RenderTransform).(RotateTransform.Angle)"));
s.Begin();
}
And ViewModel
public class MyViewModel : ViewModelBase
{
private ICommand _rotateCommand = null;
private double _angleProperty = 10;
public MyViewModel()
{
}
public double AngleProperty
{
get
{
return _angleProperty;
}
set
{
_angleProperty = value;
OnPropertyChanged("AngleProperty");
}
}
public ICommand RotateCommand
{
get
{
if (_rotateCommand == null)
{
_rotateCommand = new RelayCommand(param => RotateCommandImplementation());
}
return _rotateCommand;
}
}
private void RotateCommandImplementation()
{
AngleProperty = AngleProperty + 10;
}
}
Here's my solution, based on a lot of help from #Clemens (see comments and WPF circular moving object)
VIEW
<Window x:Class="AnimationBindingPlay.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:AnimationBindingPlay"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Canvas Grid.Row="0" Grid.Column="0">
<Ellipse Height="100" Width="100" Fill="Aqua" Name="MyEllipse"
Canvas.Left="200" Canvas.Top="200"
RenderTransformOrigin="0.5,0.5">
<Ellipse.RenderTransform>
<TransformGroup>
<TranslateTransform Y="-100"/>
<RotateTransform x:Name="rotateTransform"/>
</TransformGroup>
</Ellipse.RenderTransform>
</Ellipse>
</Canvas>
<Button Grid.Row="0" Grid.Column="1" VerticalAlignment="Center" HorizontalAlignment="Center" Command="{Binding Path=RotateCommand}">Press Me!</Button>
</Grid>
Code behind
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
var nameOfPropertyInVm = "AngleProperty";
var binding = new Binding(nameOfPropertyInVm) { Mode = BindingMode.TwoWay };
this.SetBinding(AngleProperty, binding);
}
public double Angle
{
get { return (double)GetValue(AngleProperty); }
set { SetValue(AngleProperty, value); }
}
// Using a DependencyProperty as the backing store for Angle. This enables animation, styling, binding, etc...
public static readonly DependencyProperty AngleProperty = DependencyProperty.Register("Angle", typeof(double), typeof(MainWindow), new UIPropertyMetadata(0.0, new PropertyChangedCallback(AngleChanged)));
private static void AngleChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
MainWindow control = (MainWindow)sender;
control.PerformAnimation((double)e.OldValue, (double)e.NewValue);
}
private void PerformAnimation(double oldValue, double newValue)
{
var rotationAnimation = new DoubleAnimation(oldValue, newValue, TimeSpan.FromSeconds(1));
rotateTransform.BeginAnimation(RotateTransform.AngleProperty, rotationAnimation);
}
}
ViewModel
Same as in question!

How to render (redrawn) usercontrol when binding property source changed in windows phone

I build a control in Windows Phone (same WPF) draw a vertical chart by timeline.
In Xaml:
<UserControl x:Class="MiO2.CustomControls.VerticalChart"
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"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
d:DesignHeight="480" d:DesignWidth="480"
xmlns:blockPivot="clr-namespace:MiO2.Framework"
x:Name="uc">
<UserControl.Resources>
<Storyboard x:Name="animateOpacityPointer">
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="pointer">
<EasingDoubleKeyFrame KeyTime="0" Value="1">
<EasingDoubleKeyFrame.EasingFunction>
<CircleEase EasingMode="EaseOut"/>
</EasingDoubleKeyFrame.EasingFunction>
</EasingDoubleKeyFrame>
<EasingDoubleKeyFrame KeyTime="0:0:0.7" Value="0"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</UserControl.Resources>
<Grid x:Name="LayoutRoot" blockPivot:BlocksPan.IsEnabled="True" Background="{Binding Background, ElementName=uc}">
<Grid.RowDefinitions>
<RowDefinition Height="1*" />
<RowDefinition Height="2*" />
</Grid.RowDefinitions>
<Grid x:Name="renderLayer" Grid.Row="1">
<Canvas x:Name="canvasRender">
</Canvas>
</Grid>
<Grid Grid.Row="0" Grid.RowSpan="10" x:Name="touchLayer" Visibility="Visible">
<Canvas x:Name="pointerLayer" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" >
<Grid Width="52" x:Name="pointer" HorizontalAlignment="Left" VerticalAlignment="Top" Canvas.Top="0" Canvas.Left="0">
<StackPanel Orientation="Vertical">
<TextBlock x:Name="tbTime" Height="40" Margin="0,0,0,0" Foreground="Black" />
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Top">
<Grid HorizontalAlignment="Left" VerticalAlignment="Top">
<Ellipse Fill="#FF8BE0FB" Height="40" Width="40" HorizontalAlignment="Center" VerticalAlignment="Center" />
<Ellipse Fill="#FF01ADF5" Height="20" Width="20" HorizontalAlignment="Center" VerticalAlignment="Center" />
</Grid>
<Line x:Name="line" Stroke="Black" StrokeDashArray="4 2" Y2="0" VerticalAlignment="Top" HorizontalAlignment="Center"/>
</StackPanel>
</StackPanel>
</Grid>
</Canvas>
<TextBlock x:Name="tbUnit" Text="1" VerticalAlignment="Top" HorizontalAlignment="Right" Foreground="Black" />
<Slider blockPivot:BlocksPan.IsEnabled="True" ManipulationCompleted="touchLayer_ManipulationCompleted" ManipulationStarted="touchLayer_ManipulationStarted" Background="Transparent" ManipulationDelta="touchLayer_ManipulationDelta" Foreground="Transparent" Style="{StaticResource SliderStyle1}">
</Slider>
</Grid>
</Grid>
In code behide:
public partial class VerticalChart : UserControl
{
public VerticalChart()
{
InitializeComponent();
this.Loaded += VerticalChart_Loaded;
}
void VerticalChart_Loaded(object sender, RoutedEventArgs e)
{
InitializeChart();
}
public static readonly DependencyProperty ItemSourceProperty =
DependencyProperty.Register("ItemSource", typeof(IEnumerable<ITimelineData>), typeof(VerticalChart),
new PropertyMetadata(null, ItemSourcePropertyChangedCallback));
private static void ItemSourcePropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
}
public IEnumerable<ITimelineData> ItemSource
{
get { return base.GetValue(ItemSourceProperty) as IEnumerable<ITimelineData>; }
set { base.SetValue(ItemSourceProperty, value); }
}
Random ran = new Random();
double unit = 0;
double leftStart = 0;
public void InitializeChart()
{
if (ItemSource.Count() == 0) return;
TimeSpan period = ItemSource.Last().TimeEnd - ItemSource.First().TimeStart;
double width = this.ActualWidth - pointer.ActualWidth / 2;
double height = renderLayer.ActualHeight;
double minutes = period.TotalMinutes;
leftStart = pointer.ActualWidth / 2;
double divide = (width / minutes);
if (divide >= 2) unit = 2;
else if (divide >= 1) unit = 1;
else if (divide >= 0.5) unit = 0.5;
else if (divide >= 0.25) unit = 0.25;
else unit = 0.1;
tbUnit.Text = unit.ToString();
foreach (ITimelineData used in ItemSource)
{
double min = (used.TimeEnd - used.TimeStart).TotalMinutes;
int borderWidth = (int)(unit * min);
double left = (used.TimeStart - ItemSource.First().TimeStart).TotalMinutes * unit + leftStart;
Border border = new Border();
border.Width = borderWidth;
border.Height = ran.Next(100, 250);
Binding binding = new Binding("Foreground");
binding.Source = this;
border.SetBinding(Border.BackgroundProperty, binding);
double top = height - border.Height;
Canvas.SetLeft(border, left);
Canvas.SetTop(border, top);
canvasRender.Children.Add(border);
}
}
}
And use in Mainpage.xaml
<myControl:VerticalChart ItemSource="{Binding ActivitiesToday}" />
And when property ActivitiesToday changed means ItemSource property updated. And I want, when ItemSource updated new or change number collection Cavas: renderLayer redrawn number of Border inside. How to do that? I want to redrawn Border in Canvas when ItemSource updated.
For code draw list Border:
Border border = new Border();
border.Width = borderWidth;
border.Height = ran.Next(100, 250);
Binding binding = new Binding("Foreground");
binding.Source = this;
border.SetBinding(Border.BackgroundProperty, binding);
double top = height - border.Height;
Canvas.SetLeft(border, left);
Canvas.SetTop(border, top);
canvasRender.Children.Add(border);
How to do that? Thanks!
Create a custom event in your usercontrol
private event ItemsSourceChanged;
Add all the required code to support event change
Now trigger the event on property change.
public IEnumerable<ITimelineData> ItemSource
{
get { return base.GetValue(ItemSourceProperty) as IEnumerable<ITimelineData>; }
set { base.SetValue(ItemSourceProperty, value); OnItemSourcePropertyChange(); }
}
In xaml, map the event to code-behind and do your changes.
<myControl:VerticalChart ItemSource="{Binding ActivitiesToday}" ItemSourceChanged="doSomething" />

BarChart Values not updating

I am trying to develop a application where-in I a want to generate a random number after every three seconds, insert that number into a listBox and using DataTemplate display the ListBox as a rectangle.
This is for reference.
Now the problem is that I have used a DispatcherTimer which 'ticks' after 3 seconds but the rectangle is not updated.
I am posting my XAML and .cs code. Any hints ?
namespace ListBarGraph
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
DispatcherTimer dt = new DispatcherTimer();
DataFactory df = new DataFactory();
public MainWindow()
{
InitializeComponent();
dt.Tick += new EventHandler(dt_Tick);
dt.Interval = new TimeSpan(0, 0, 3);
dt.Start();
this.PreviewKeyDown += new KeyEventHandler(MainWindow_PreviewKeyDown);
}
void dt_Tick(object sender, EventArgs e)
{
df.GetData();
}
}
public class DataFactory
{
int number = 0;
public IEnumerable<int> GetData()
{
Random random = new Random();
number = random.Next(0, 100);
return new int[] { 0, number };
}
}
}
<Window x:Class="ListBarGraph.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:ListBarGraph"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<ObjectDataProvider x:Key="someData" ObjectType="{x:Type local:DataFactory}" MethodName="GetData" />
<DataTemplate x:Key="BarChartItemsTemplate">
<Border Width="300" Height="50">
<Grid>
<Rectangle Fill="Red" StrokeThickness="2" Height="40" Width="{Binding}" HorizontalAlignment="Right" VerticalAlignment="Bottom">
<Rectangle.LayoutTransform>
<ScaleTransform ScaleX="1.5"/>
</Rectangle.LayoutTransform>
</Rectangle>
</Grid>
</Border>
</DataTemplate>
<ItemsPanelTemplate x:Key="BarChartItemsPanel">
<VirtualizingStackPanel IsItemsHost="True">
<VirtualizingStackPanel.LayoutTransform>
<TransformGroup>
<RotateTransform Angle="90"/>
<ScaleTransform ScaleX="-1" ScaleY="1"/>
</TransformGroup>
</VirtualizingStackPanel.LayoutTransform>
</VirtualizingStackPanel>
</ItemsPanelTemplate>
</Window.Resources>
<Grid>
<ListBox ItemsSource="{Binding Source={StaticResource someData}}" ItemTemplate="{DynamicResource BarChartItemsTemplate}" ItemsPanel="{DynamicResource BarChartItemsPanel}"/>
</Grid>
</Window>
Your XAML is bound to one instance of DataFactory as created by the ObjectProvider, whilst your code-behind creates another instance altogether, to which the UI is not bound.
Try this to get you started. In your XAML, remove the ObjectProvider and change your ListBox to:
<ListBox ItemsSource="{Binding}" ...
Inside dt_Tick, do this:
this.DataContext = df.GetData();

wp7 slider hangs up

I am trying to use a slider control. It's just the simple control. Nothing fancy. But I run into an issue that is confusing me.
If I put the control on a test page (blank with nothing else) and navigate to it immediately after the app launches , I can slide it around perfectly. But if I navigate to another page first and then to the test page. I get a very weird behavior. The slider control moves in steps. It seems as if it hangs up or is losing focus.
I'm using wp7.1 and I've tested in the emulator and on the phone. Both give me the same result. I don't even know where to start solving this, but i definitely need a slider and for it to move smoothly.
Any ideas?
revised to include xaml:
<phone:PhoneApplicationPage
x:Class="WP7ListBoxSelectedItemStyle.TestPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="480" d:DesignHeight="768"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="Portrait" Orientation="Portrait"
xmlns:local="clr-namespace:WP7ListBoxSelectedItemStyle"
xmlns:my="clr-namespace:colordata_controls;assembly=colordata_controls"
shell:SystemTray.IsVisible="True" xmlns:toolkit="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls.Toolkit">
<!--LayoutRoot is the root grid where all page content is placed-->
<Grid x:Name="LayoutRoot" Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!--TitlePanel contains the name of the application and page title-->
<StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
<TextBlock x:Name="ApplicationTitle" Text="IPO" Style="{StaticResource PhoneTextNormalStyle}"/>
<TextBlock x:Name="PageTitle" Text="Test" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
</StackPanel>
<!--ContentPanel - place additional content here-->
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="8,17,16,-17">
<Slider Height="84" HorizontalAlignment="Left" Margin="10,10,0,0" Name="slider1" VerticalAlignment="Top" Width="460" />
</Grid>
</Grid>
here is a link to a video of it in action in the emulator. https://vimeo.com/36428677
so, I still don't know why the slider sticks that way, but in order to keep moving forward I created my own slider. Hopefully this code helps someone else.
xaml:
<UserControl
x:Name="userControl"
x:Class="controls.pSlider"
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"
d:DesignWidth="76" d:DesignHeight="400" Background="Gray" Foreground="White">
<Grid x:Name="LayoutRoot" Background="Transparent" MouseMove="LayoutRoot_MouseMove" MouseLeftButtonDown="LayoutRoot_MouseLeftButtonDown">
<Grid.RowDefinitions>
<RowDefinition Height="10"/>
<RowDefinition/>
<RowDefinition Height="10"/>
</Grid.RowDefinitions>
<Rectangle x:Name="colorBar" Margin="20,6" Width="10" Fill="{Binding Background, ElementName=userControl}" Grid.Row="1"/>
<Grid x:Name="g_container" Grid.Row="1" Margin="0,1,0,13">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition Height="0"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid x:Name="g_thumb" Height="0" VerticalAlignment="Top" Grid.Row="1">
<Canvas Height="0" VerticalAlignment="Top">
<Path Data="M0,0 L1,0 L1.2,0.5 L1,1 L0,1 z" Margin="0" Stretch="Fill" UseLayoutRounding="False" Width="33" RenderTransformOrigin="0.5,0.5" StrokeThickness="0" Fill="{Binding Foreground, ElementName=userControl}" Height="12" d:LayoutOverrides="VerticalAlignment"/>
<Path Data="M0.3,0.5 L0.5,0 L1.5,0 L1.5,1 L0.5,1 z" Margin="0" Stretch="Fill" UseLayoutRounding="False" Width="33" RenderTransformOrigin="0.5,0.5" StrokeThickness="0" Fill="{Binding Foreground, ElementName=userControl}" Height="12" Canvas.Left="43" d:LayoutOverrides="VerticalAlignment"/>
</Canvas>
</Grid>
<Rectangle x:Name="r_lifter" Margin="0" Grid.Row="2" Height="188" StrokeThickness="0"/>
</Grid>
</Grid>
code:
namespace controls {
public partial class pSlider : UserControl {
public event RoutedEventHandler ValueChanged;
public static readonly DependencyProperty MaxProperty =
DependencyProperty.Register("Maximum", typeof(double), typeof(pSlider), new PropertyMetadata(100.0));
public double Maximum {
get { return (double)GetValue(MaxProperty); }
set { SetValue(MaxProperty, value); }
}
public static readonly DependencyProperty MinProperty =
DependencyProperty.Register("Minimum", typeof(double), typeof(pSlider), new PropertyMetadata(0.0));
public double Minimum {
get { return (double)GetValue(MinProperty); }
set { SetValue(MinProperty, value); }
}
public static readonly DependencyProperty ValueProperty =
DependencyProperty.Register("Value", typeof(double), typeof(pSlider), new PropertyMetadata(50.0));
public double Value {
get { return (double)GetValue(ValueProperty); }
set { SetValue(ValueProperty, value); }
}
public pSlider() {
InitializeComponent();
Loaded += new RoutedEventHandler(pSlider_Loaded);
}
void pSlider_Loaded(object sender, RoutedEventArgs e) {
if (Value > Maximum)
Value = Maximum;
else if (Value < Minimum)
Value = Minimum;
double min = 0;
double max = g_container.ActualHeight;
r_lifter.Height = Value / (Maximum - Minimum) * (max - min);
}
private Point Position;
private void LayoutRoot_MouseMove(object sender, MouseEventArgs e) {
Point newPosition = e.GetPosition((UIElement)sender);
double delta = newPosition.Y - Position.Y;
double temp = r_lifter.Height - delta;
if (temp > g_container.ActualHeight)
r_lifter.Height = g_container.ActualHeight;
else if (temp < 0)
r_lifter.Height = 0;
else
r_lifter.Height = temp;
double min = 0;
double max = g_container.ActualHeight;
Value = r_lifter.Height / (max - min) * (Maximum - Minimum);
Value = Math.Floor(Value);
RoutedEventHandler handler = ValueChanged;
if (handler != null)
handler(this, e);
Position = e.GetPosition((UIElement)sender);
}
private void LayoutRoot_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) {
Position = e.GetPosition((UIElement)sender);
}
}
}

RenderTransform flickering

See the following code,
After I clicked the button, the listbox render several times.
How can I prevent Listbox flickering?
Is it possible to tell a control stop update/render?
<UserControl x:Class="SilverlightApplication52.MainPage"
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"
d:DesignHeight="300"
d:DesignWidth="400">
<Grid x:Name="LayoutRoot"
Background="Gray"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch">
<ListBox x:Name="listbox"
Background="White"
Margin="100">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<Canvas />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<Rectangle Width="{Binding Width}"
Height="{Binding Height}"
Fill="{Binding Background}"
RenderTransformOrigin="0.5,0.5">
<Rectangle.RenderTransform>
<TransformGroup>
<ScaleTransform ScaleX="{Binding Scale}"
ScaleY="{Binding Scale}" />
<RotateTransform Angle="{Binding Angle}" />
<TranslateTransform X="{Binding Left}"
Y="{Binding Top}" />
</TransformGroup>
</Rectangle.RenderTransform>
</Rectangle>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<Button Content="test"
Width="50"
Height="50"
Click="Button_Click" />
</Grid>
public partial class MainPage : UserControl
{
public class ItemInfo
{
public double Left { get; set; }
public double Top { get; set; }
public double Width { get; set; }
public double Height { get; set; }
public double Angle { get; set; }
public double Scale { get; set; }
public Brush Background { get; set; }
}
ObservableCollection<ItemInfo> _items = new ObservableCollection<ItemInfo>();
public MainPage()
{
InitializeComponent();
listbox.ItemsSource = _items;
}
Random random = new Random();
private void Button_Click(object sender, RoutedEventArgs e)
{
_items.Clear();
for (int i = 0; i < 2000; i++)
{
byte r = (byte)(random.NextDouble()*255);
byte g = (byte)(random.NextDouble()*255);
byte b = (byte)(random.NextDouble()*255);
_items.Add(
new ItemInfo
{
Left = random.NextDouble() * 500,
Top = random.NextDouble() * 500,
Width = random.NextDouble() * 1000,
Height = random.NextDouble() * 1000,
Angle = random.NextDouble() * 359,
Scale = random.NextDouble() * 1,
Background = new SolidColorBrush(Color.FromArgb(255,r,g,b)),
}
);
}
}
}
Try adding to a separate ObservableCollection in that loop (that is not referenced/bound to the listbox). Then when the loop is done assign the listbox ItemsSource to the new observablecollection.

Resources