I would try to create a user control in a windows app. I tried to enter this code:
public double Minimum
{
get { return (double)GetValue(MinimumProperty); }
set { SetValue(MinimumProperty, value); }
}
public static readonly DependencyProperty MinimumProperty =
DependencyProperty.Register("Minimum", typeof(double), typeof(RangeSlider), new UIPropertyMetadata(0d));
public double LowerValue
{
get { return (double)GetValue(LowerValueProperty); }
set { SetValue(LowerValueProperty, value); }
}
public static readonly DependencyProperty LowerValueProperty =
DependencyProperty.Register("LowerValue", typeof(double), typeof(RangeSlider), new UIPropertyMetadata(0d));
public double UpperValue
{
get { return (double)GetValue(UpperValueProperty); }
set { SetValue(UpperValueProperty, value); }
}
public static readonly DependencyProperty UpperValueProperty =
DependencyProperty.Register("UpperValue", typeof(double), typeof(RangeSlider), new UIPropertyMetadata(0d));
public double Maximum
{
get { return (double)GetValue(MaximumProperty); }
set { SetValue(MaximumProperty, value); }
}
public static readonly DependencyProperty MaximumProperty =
DependencyProperty.Register("Maximum", typeof(double), typeof(RangeSlider), new UIPropertyMetadata(1d));
Then I plugged in xaml control so:
<UserControl
x:Class="Doppio_Cursore.MyUserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Doppio_Cursore"
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"
x:name= "root">
<Grid>
<Slider x:Name="LowerSlider"
Minimum="{Binding ElementName=root, Path=Minimum}"
Maximum="{Binding ElementName=root, Path=Maximum}"
Value="{Binding ElementName=root, Path=LowerValue}" />
<Slider x:Name="UpperSlider"
Minimum="{Binding ElementName=root, Path=Minimum}"
Maximum="{Binding ElementName=root, Path=Maximum}"
Value="{Binding ElementName=root, Path=UpperValue}" />
</Grid>
</UserControl>
I believe that with this code if I'm not mistaken, I should see a slider-slider, no?
Instead I get a simple slider with a single slider. Where am I wrong?
Related
I have got an usercontrol with some dependency property. One of them (ValueProperty) has got a PropertyChangedCallback but it never run.
namespace test
{
public partial class IndicatorLigth : UserControl
{
public IndicatorLigth()
{
InitializeComponent();
DataContext = this;
CurrentBrush = new SolidColorBrush(InactiveColor);
lIndicator.Background = CurrentBrush;
TurnOnValue = true;
Value = true;
}
public static readonly DependencyProperty ActiveColorProperty =
DependencyProperty.Register("ActiveColor", typeof(Color), typeof(IndicatorLigth), new UIPropertyMetadata(Colors.Green));
public Color ActiveColor
{
get { return (Color)GetValue(ActiveColorProperty); }
set { SetValue(ActiveColorProperty, value); }
}
public static readonly DependencyProperty InactiveColorProperty =
DependencyProperty.Register("InactiveColor", typeof(Color), typeof(IndicatorLigth), new UIPropertyMetadata(Colors.Red));
public Color InactiveColor
{
get { return (Color)GetValue(InactiveColorProperty); }
set { SetValue(InactiveColorProperty, value); }
}
private SolidColorBrush _currentBrush;
public SolidColorBrush CurrentBrush
{
get { return _currentBrush; }
set { _currentBrush = value; }
}
public static readonly DependencyProperty TurnOnValueProperty =
DependencyProperty.Register("TurnOnValue", typeof(bool), typeof(IndicatorLigth), new UIPropertyMetadata(true));
public bool TurnOnValue
{
get { return (bool)GetValue(TurnOnValueProperty); }
set { SetValue(TurnOnValueProperty, value); }
}
public static readonly DependencyProperty ValueProperty =
DependencyProperty.Register("Value", typeof(bool), typeof(IndicatorLigth),
new FrameworkPropertyMetadata(true,
FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnSetColorChanged));
public bool Value
{
get { return (bool)GetValue(ValueProperty); }
set
{
SetValue(ValueProperty, value);
}
}
private void CheckStatus(bool sign)
{
if (sign == TurnOnValue)
CurrentBrush = new SolidColorBrush(ActiveColor);
else CurrentBrush = new SolidColorBrush(InactiveColor);
}
private static void OnSetColorChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
IndicatorLigth mycontrol = d as IndicatorLigth;
mycontrol.callmyInstanceMethod(e);
}
private void callmyInstanceMethod(DependencyPropertyChangedEventArgs e)
{
CheckStatus((bool)e.NewValue);
lIndicator.Background = CurrentBrush;
}
}
}
And XAML where I use my usercontrol (I use it in another UserControl):
<UserControl
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:local="clr-namespace:test"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" >
...
<StackPanel Orientation="Vertical">
<Label Content="{Binding RelativeSource={RelativeSource AncestorType=UserControl, Mode=FindAncestor}, Path=DataContext.Sign}"/>
<StackPanel>
<local:IndicatorLigth ActiveColor="Thistle" Value="{Binding RelativeSource={RelativeSource AncestorType=UserControl, Mode=FindAncestor}, Path=DataContext.Sign}"/>
</StackPanel>
</StackPanel>
The Sign parameter belongs to an IsEnabled bindable property of a ComboBox which not in the XAML code. The label content is correct, it changes when I change combobox enabled status, but my UserControl setter of Value, OnSetColorChanged and callmyInstanceMethod don't fire. Could you tell me what wrong in my code? Thank you very much.
Update: So I was wrong. The code mentioned above is correct. The problem will be occures when I push the stackpanel into a devexpress LayoutGroup HeaderTemplate:
<dxlc:LayoutGroup Orientation="Vertical" VerticalAlignment="Top">
<dxlc:LayoutGroup.HeaderTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical">
<Label Content="{Binding RelativeSource={RelativeSource AncestorType=UserControl, Mode=FindAncestor}, Path=DataContext.Sign}"/>
<StackPanel>
<local:IndicatorLigth ActiveColor="Thistle" Value="{Binding RelativeSource={RelativeSource AncestorType=UserControl, Mode=FindAncestor}, Path=DataContext.Sign}"/>
</StackPanel>
</StackPanel>
</DataTemplate>
</dxlc:LayoutGroup.HeaderTemplate>
</dxlc:LayoutGroup>
Sorry for disturbing you and thank you for advices. I have found the cause of problem. I needn't use <HeaderTemplate><DataTemplate>, I have to use simple <Header> block :)
I have a UserControl with DependecyProperty:
public static readonly DependencyProperty OpenCommandProperty =
DependencyProperty.Register(
"OpenCommand",
typeof(ICommand),
typeof(BaseRouteFlatView),
new UIPropertyMetadata(null));
public ICommand OpenCommand
{
get { return (ICommand)GetValue(OpenCommandProperty); }
set { SetValue(OpenCommandProperty, value); }
}
In Xaml:
<UserControl x:Name="myUserControl">
<StackPanel>
<Button x:Name="first" Command="{Binding OpenCommand, ElementName=myUserControl}"/> <!--Command works-->
<controls:DropDownButtonControl>
<controls:DropDownButtonControl.DropDownContent>
<Button x:Name="second" Command="{Binding OpenCommand, ElementName=myUserControl}"/> <!--Command doesn't work-->
</controls:DropDownButtonControl.DropDownContent>
</controls:DropDownButtonControl>
</StackPanel>
</abstractions:UserControlBase>
What source I have to specify for working command in second button?
Try the following:
public UserControl()
{
InitializeComponent();
NameScope.SetNameScope(second, NameScope.GetNameScope(this));
}
I am trying to create a basic colour change UserControl utilising my custom slider control, LabelSlider. I can get the colour to be set via code, however if I move the slider or enter text into the TextBox, it doesn't update the colour.
LabelSlider XAML:
<Slider x:Name="ucSlider" x:FieldModifier="private" Margin="{Binding SliderSpacing, FallbackValue=5, Converter={StaticResource DoubleToMargin}}" VerticalAlignment="Center" Grid.Column="1" Width="{Binding SliderWidth}" MaxWidth="{Binding SliderWidth}" FontFamily="Segoe UI" Value="{Binding Value, Mode=TwoWay}" SmallChange="1" Maximum="255"/>
<TextBox x:Name="ucTextBox" x:FieldModifier="private" Text="{Binding Value, TargetNullValue=0, Mode=TwoWay}" Margin="{Binding TextBoxSpacing, FallbackValue=5, Converter={StaticResource DoubleToMargin}}" Grid.Column="2" PreviewKeyDown="LabelSlider_PreviewKeyDown" PreviewTextInput="LabelSlider_PreviewTextInput" MaxLength="3" Width="30" MaxWidth="30" FontFamily="Segoe UI" TextChanged="LabelSlider_TextChanged"/>
LabelSlider Code Behind:
public int Value
{
get { return (int)GetValue(ValueProperty); }
set { SetValue(ValueProperty, value); }
}
public static readonly DependencyProperty ValueProperty = DependencyProperty.Register
(
"Value",
typeof(int),
typeof(LabelSlider),
new PropertyMetadata(null)
);
ColourSelection XAML:
<UserControl x:Class="Homuli.UserControls.ColourSelection"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Homuli.UserControls"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300" x:Name="colourSelection">
<StackPanel Margin="5,0,0,0" DataContext="{Binding ElementName=colourSelection}">
<local:LabelSlider Label="R" SliderSpacing="6" SliderWidth="100" Value="{Binding R, FallbackValue=255, TargetNullValue=0}" Foreground="White" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="0,-4"/>
<local:LabelSlider Label="G" SliderSpacing="5" SliderWidth="100" Value="{Binding G, FallbackValue=0, TargetNullValue=0}" Foreground="White" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="0,-4"/>
<local:LabelSlider Label="B" SliderSpacing="6" SliderWidth="100" Value="{Binding B, FallbackValue=0, TargetNullValue=0}" Foreground="White" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="0,-4"/>
<StackPanel Orientation="Horizontal">
<local:LabelTextBox Label="Hex" Spacing="15" TextBoxWidth="50" Text="{Binding Hex}" MaxLength="6" Foreground="White" HorizontalAlignment="Left" VerticalAlignment="Center"/>
<Rectangle Fill="{Binding Colour}" Height="26" Width="26" Margin="26,0,0,0" Stroke="Black" />
</StackPanel>
</StackPanel>
ColourSelection Code Behind:
public partial class ColourSelection : UserControl
{
public ColourSelection()
{
InitializeComponent();
}
public SolidColorBrush Colour
{
get { return (SolidColorBrush)GetValue(ColourProperty); }
set { SetValue(ColourProperty, value); }
}
public static readonly DependencyProperty ColourProperty = DependencyProperty.Register
(
"Colour",
typeof(SolidColorBrush),
typeof(ColourSelection),
new PropertyMetadata(null)
);
public int R
{
get { return (int)GetValue(RProperty); }
set
{
if (value <= 255 && value >= 0)
{
SetValue(RProperty, value);
UpdateColour();
}
}
}
public static readonly DependencyProperty RProperty = DependencyProperty.Register
(
"R",
typeof(int),
typeof(ColourSelection),
new PropertyMetadata()
);
public int G
{
get { return (int)GetValue(GProperty); }
set
{
if (value <= 255 && value >= 0)
{
SetValue(GProperty, value);
UpdateColour();
}
}
}
public static readonly DependencyProperty GProperty = DependencyProperty.Register
(
"G",
typeof(int),
typeof(ColourSelection),
new PropertyMetadata(null)
);
public int B
{
get { return (int)GetValue(BProperty); }
set
{
if (value <= 255 && value >= 0)
{
SetValue(BProperty, value);
UpdateColour();
}
}
}
public static readonly DependencyProperty BProperty = DependencyProperty.Register
(
"B",
typeof(int),
typeof(ColourSelection),
new PropertyMetadata(null)
);
void UpdateColour()
{
Colour = new SolidColorBrush(Color.FromRgb((byte)R, (byte)G, (byte)B));
}
}
Any help will be greatly appreciated.
when DP is changing, it happens via static object BProperty. Code in setter
if (value <= 255 && value >= 0)
{
SetValue(RProperty, value);
UpdateColour();
}
is not executed.
you need to add property change callback (for R,G,B properties):
public int B
{
get { return (int)GetValue(BProperty); }
set { SetValue(BProperty, value); }
}
public static readonly DependencyProperty BProperty = DependencyProperty.Register
(
"B",
typeof(int),
typeof(ColourSelection),
new PropertyMetadata(0, PropertyChangedCallback)
);
private static void PropertyChangedCallback(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
if ((int) e.NewValue <= 255 && (int) e.NewValue >= 0)
((ColourSelection) obj).UpdateColour();
}
also I wouldn't recommend to replace dataContext in userControl like this DataContext="{Binding ElementName=colourSelection}". Instead use ElementName in bindings:
<local:LabelSlider Label="R" SliderSpacing="6" SliderWidth="100"
Value="{Binding R, ElementName=colourSelection, FallbackValue=255, TargetNullValue=0}"
In WPF I am trying to draw graph lines in a UserControl. I will need to scale the X and Y values by different amounts.
I have a sample project I will include below. The problem is that when I use RenderTransform to scale the graph line, the LineThickness is also scaled. This would normally not be a problem because I could descale the line thickness by the inverse of the scaled value:
LineThickness = desiredLineThickness * (1/scaledValue)
Unfortunately, in this application I will need to scale the X and Y dimensions by very different values, and LineThickness is not separated into X and Y values.
In my example below I am drawing a sine wave that is scaled to the size of the drawing surface of the user control. You can see that the peaks and valleys extend beyond the drawing surface. This is because the original data goes from 1.0 to -1.0 and is scaled to the height of the drawing surface and translated to the middle of the drawing surface.
To demonstrate it more clearly, I also draw a blue line from 0,0 to 90,90 and then from 90,90 horizontally to the right. This line is also scaled to the height of the drawing surface. You can see the horizontal line is very thick.
I need a way to descale these lines in the Y axis separately from the X axis which is not scaled in this case.
I have tried several approaches including making a contained object of lines. I was thinking I could put the endpoints of the lines in the scaled position and then when drawing the actual lines, I would use a render transform to descale the Y values, but I could never get that to work because of the whole binding proxy problem.
Anyone have any ideas or have been faced with this before? I can't be the first with this problem.
Here is the code:
UserControl1.xaml.cs:
namespace WpfExampleControlLibrary
{
/// <summary>
/// Interaction logic for UserControl1.xaml
/// </summary>
public partial class UserControl1 : UserControl
{
#region Constructor
public UserControl1()
{
InitializeComponent();
GraphPens = new ObservableCollection<GraphPen>();
}
#endregion Constructor
#region Public Methods
#endregion Public Methods
#region Dependency Properties
// Pens
public static PropertyMetadata GraphPenMetadata = new PropertyMetadata(null);
public static DependencyProperty GraphPensProperty
= DependencyProperty.Register(
"GraphPens",
typeof(ObservableCollection<GraphPen>),
typeof(UserControl1),
GraphPenMetadata);
public ObservableCollection<GraphPen> GraphPens
{
get { return (ObservableCollection<GraphPen>)GetValue(GraphPensProperty); }
set { SetValue(GraphPensProperty, value); }
}
// Debug Text
public static PropertyMetadata DebugTextMetadata = new PropertyMetadata(null);
public static DependencyProperty DebugTextProperty
= DependencyProperty.Register(
"DebugText",
typeof(string),
typeof(UserControl1),
DebugTextMetadata);
public string DebugText
{
get { return (string)GetValue(DebugTextProperty); }
set { SetValue(DebugTextProperty, value); }
}
#endregion Dependency Properties
private void DrawingSurface_SizeChanged(object sender, SizeChangedEventArgs e)
{
foreach (GraphPen graphPen in GraphPens)
{
graphPen.SetDrawingDimensions(e.NewSize.Height, e.NewSize.Width);
}
}
}
}
UserControl.xaml:
<UserControl Name="ExampleControl"
x:Class="WpfExampleControlLibrary.UserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:WpfExampleControlLibrary"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<UserControl.Resources>
<local:BindingProxy
x:Key="UserControlBindingProxy"
Data="{Binding RelativeSource={RelativeSource AncestorType=UserControl}}"/>
<DataTemplate DataType="{x:Type local:GraphPen}">
<ItemsControl>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas>
<Canvas.RenderTransform>
<TransformGroup>
<TransformGroup.Children>
<ScaleTransform
CenterX="0.0"
CenterY="0.0"
ScaleX="1.0"
ScaleY="{Binding ScaleHeight}"/>
<TranslateTransform
X="0.0"
Y="{Binding TranslateHeight}"/>
</TransformGroup.Children>
</TransformGroup>
</Canvas.RenderTransform>
</Canvas>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemsSource>
<CompositeCollection>
<Path
Data="{Binding PenGeometry}"
StrokeThickness="{Binding PenLineThickness}"
Stroke="{Binding
PenLineColor,
PresentationTraceSources.TraceLevel=None}"
/>
</CompositeCollection>
</ItemsControl.ItemsSource>
</ItemsControl>
</DataTemplate>
</UserControl.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition Height="40"/>
</Grid.RowDefinitions>
<ItemsControl x:Name="DrawingSurface" Grid.Column="0" Grid.Row="0" SizeChanged="DrawingSurface_SizeChanged">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas Background="Aquamarine">
<Canvas.LayoutTransform>
<ScaleTransform ScaleX="1" ScaleY="-1" CenterX=".5" CenterY=".5"/>
</Canvas.LayoutTransform>
</Canvas>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemsSource>
<CompositeCollection>
<CollectionContainer
Collection="{Binding
Source={StaticResource UserControlBindingProxy},
Path=Data.GraphPens,
Mode=OneWay}"/>
<Line X1="10" Y1="0" X2="200" Y2="180" Stroke="DarkRed" StrokeThickness="2"/>
</CompositeCollection>
</ItemsControl.ItemsSource>
</ItemsControl>
<TextBox
x:Name="debug"
Grid.Column="0" Grid.Row="1"
Text="{Binding
Source={StaticResource UserControlBindingProxy},
Path=Data.DebugText,
Mode=OneWay}"/>
</Grid>
</UserControl>
GraphPen.cs:
namespace WpfExampleControlLibrary
{
public class GraphPen : DependencyObject
{
private double _drawingSurfaceHeight = 100;
#region Constructor
public GraphPen()
{
PenGeometry = new PathGeometry();
PenGeometry.Figures.Add(new PathFigure());
}
#endregion Constructor
#region Dependency Properties
// LineColor
public static PropertyMetadata PenLineColorPropertyMetadata
= new PropertyMetadata(null);
public static DependencyProperty PenLineColorProperty
= DependencyProperty.Register(
"PenLineColor",
typeof(Brush),
typeof(GraphPen),
PenLineColorPropertyMetadata);
public Brush PenLineColor
{
get { return (Brush)GetValue(PenLineColorProperty); }
set { SetValue(PenLineColorProperty, value); }
}
// LineThickness
public static PropertyMetadata PenLineThicknessPropertyMetadata
= new PropertyMetadata(null);
public static DependencyProperty PenLineThicknessProperty
= DependencyProperty.Register(
"PenLineThickness",
typeof(Int32),
typeof(GraphPen),
PenLineThicknessPropertyMetadata);
public Int32 PenLineThickness
{
get { return (Int32)GetValue(PenLineThicknessProperty); }
set { SetValue(PenLineThicknessProperty, value); }
}
// PenYMin
public static PropertyMetadata PenYMinPropertyMetadata
= new PropertyMetadata(null);
public static DependencyProperty PenYMinProperty
= DependencyProperty.Register(
"PenYMin",
typeof(Double),
typeof(GraphPen),
PenYMinPropertyMetadata);
public double PenYMin
{
get { return (double)GetValue(PenYMinProperty); }
set { SetValue(PenYMinProperty, value); }
}
// PenYMax
public static PropertyMetadata PenYMaxPropertyMetadata
= new PropertyMetadata(null);
public static DependencyProperty PenYMaxProperty
= DependencyProperty.Register(
"PenYMax",
typeof(Double),
typeof(GraphPen),
PenYMaxPropertyMetadata);
public double PenYMax
{
get { return (double)GetValue(PenYMaxProperty); }
set { SetValue(PenYMaxProperty, value); }
}
// ScaleHeight
public static PropertyMetadata ScaleHeightPropertyMetadata
= new PropertyMetadata(null);
public static DependencyProperty ScaleHeightProperty
= DependencyProperty.Register(
"ScaleHeight",
typeof(Double),
typeof(GraphPen),
ScaleHeightPropertyMetadata);
public double ScaleHeight
{
get { return (double)GetValue(ScaleHeightProperty); }
set { SetValue(ScaleHeightProperty, value); }
}
// TranslateHeight
public static PropertyMetadata TranslateHeightPropertyMetadata
= new PropertyMetadata(null);
public static DependencyProperty TranslateHeightProperty
= DependencyProperty.Register(
"TranslateHeight",
typeof(Double),
typeof(GraphPen),
TranslateHeightPropertyMetadata);
public double TranslateHeight
{
get { return (double)GetValue(TranslateHeightProperty); }
set { SetValue(TranslateHeightProperty, value); }
}
// Pen Geometry
public static PropertyMetadata PenGeometryMetadata = new PropertyMetadata(null);
public static DependencyProperty PenGeometryProperty
= DependencyProperty.Register(
"PenGeometry",
typeof(PathGeometry),
typeof(GraphPen),
PenGeometryMetadata);
public PathGeometry PenGeometry
{
get { return (PathGeometry)GetValue(PenGeometryProperty); }
set { SetValue(PenGeometryProperty, value); }
}
#endregion Dependency Properties
public void SetDrawingDimensions(double height, double width)
{
double dataHeight;
_drawingSurfaceHeight = height;
dataHeight = PenYMax - PenYMin;
ScaleHeight = _drawingSurfaceHeight / dataHeight;
TranslateHeight = ScaleHeight * -PenYMin;
}
}
}
MainWindow.xaml:
<Window x:Class="POC_WPF_UserControlExample.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:Exmpl="clr-namespace:WpfExampleControlLibrary;assembly=WpfExampleControlLibrary"
xmlns:local="clr-namespace:POC_WPF_UserControlExample"
mc:Ignorable="d"
Title="MainWindow" Height="550" Width="550">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100"/>
<ColumnDefinition />
<ColumnDefinition Width="100"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="100" />
<RowDefinition />
<RowDefinition Height="100" />
</Grid.RowDefinitions>
<Exmpl:UserControl1 Grid.Column="1" Grid.Row="1" x:Name="myExample"/>
</Grid>
</Window>
MainWindow.xaml.cs:
namespace POC_WPF_UserControlExample
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private DispatcherTimer _timer = null;
private GraphPen _graphPen0 = null;
private GraphPen _graphPen1 = null;
private Int32 _pos = 0;
private bool _firstTime = true;
public MainWindow()
{
InitializeComponent();
_graphPen0 = new GraphPen();
_graphPen0.PenLineColor = Brushes.DarkGoldenrod;
_graphPen0.PenLineThickness = 1;
_graphPen0.PenYMax = 1.0;
_graphPen0.PenYMin = -1.0;
myExample.GraphPens.Add(_graphPen0);
_graphPen1 = new GraphPen();
_graphPen1.PenLineColor = Brushes.DarkBlue;
_graphPen1.PenLineThickness = 1;
_graphPen1.PenYMax = 10.0;
_graphPen1.PenYMin = 0.0;
myExample.GraphPens.Add(_graphPen1);
_timer = new DispatcherTimer();
_timer.Tick += Timer_Tick;
_timer.Interval = new TimeSpan(0, 0, 0, 0, 100);
_timer.Start();
}
private void Timer_Tick(object sender, EventArgs e)
{
_pos++;
Point penPoint0 = new Point(_pos, Math.Sin(_pos % 360));
Point penPoint1 = new Point(0,0);
if (_pos <= 9) penPoint1 = new Point(_pos, _pos);
if (_pos > 9) penPoint1 = new Point(_pos, 9);
if (_firstTime)
{
myExample.GraphPens[0].PenGeometry.Figures[0].StartPoint = penPoint0;
myExample.GraphPens[1].PenGeometry.Figures[0].StartPoint = penPoint1;
_firstTime = false;
}
else
{
LineSegment segment0 = new LineSegment(penPoint0, true);
myExample.GraphPens[0].PenGeometry.Figures[0].Segments.Add(segment0);
LineSegment segment1 = new LineSegment(penPoint1, true);
myExample.GraphPens[1].PenGeometry.Figures[0].Segments.Add(segment1);
}
myExample.DebugText = _pos.ToString();
}
}
}
EDIT by poster
I forgot to show BindingProcy.cs
namespace WpfExampleControlLibrary
{
public class BindingProxy : Freezable
{
#region Override Freezable Abstract Parts
protected override Freezable CreateInstanceCore()
{
return new BindingProxy();
}
#endregion Override Freezable Abstract Parts
#region Dependency Properties
// Using a DependencyProperty as the backing store for Data.
// This enables animation, styling, binding, etc...
public static PropertyMetadata DataMetadata = new PropertyMetadata(null);
public static readonly DependencyProperty DataProperty
= DependencyProperty.Register(
"Data",
typeof(object),
typeof(BindingProxy),
DataMetadata);
public object Data
{
get { return (object)GetValue(DataProperty); }
set { SetValue(DataProperty, value); }
}
#endregion Dependency Properties
}
}
EDIT by poster
Here is a screen shot:
I have code below inside Grid:
<Grid.RenderTransform>
<TranslateTransform
X="{Binding X, Converter={StaticResource HorizontalPositionConverter}}"
Y="{Binding Y, Converter={StaticResource VerticalPositionConverter}}"
/>
</Grid.RenderTransform>
How can I get binding of TranslateTransform.X or TranslateTransform.Y in code behind? I found this question but solution works for non-nested dependency properties. What to do when they are? I cannot consider binding to entire RenderTransform. I am developing winrt app, so multibinding is out of the game.
Here is the code behind binding. I didn't use a converter because my X and Y are defined double. In order to make a correct binding you have to use dependecy property or another notification mechanism (like INotifyPropertyChanged implementation). Here is code behind binding solution (not MVVM). I've added the button to test the moving.
1. XAML code:
<Window x:Class="TransformBindingSoHelpAttempt.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" x:Name="This">
<Grid HorizontalAlignment="Center" VerticalAlignment="Center">
<Grid.RenderTransform>
<TranslateTransform
X="{Binding ElementName=This, Path=X, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
Y="{Binding ElementName=This, Path=Y, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"/>
</Grid.RenderTransform>
<Button Content="Click" Width="100" Height="100" Click="ButtonBase_OnClick"></Button>
</Grid>
2. Code behind :
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
public static readonly DependencyProperty XProperty = DependencyProperty.Register(
"X", typeof (double), typeof (MainWindow), new PropertyMetadata(default(double)));
public double X
{
get { return (double) GetValue(XProperty); }
set { SetValue(XProperty, value); }
}
public static readonly DependencyProperty YProperty = DependencyProperty.Register(
"Y", typeof (double), typeof (MainWindow), new PropertyMetadata(default(double)));
private static double _position;
public double Y
{
get { return (double) GetValue(YProperty); }
set { SetValue(YProperty, value); }
}
private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
X = ++_position;
Y = _position;
}
}
Update 1:
Here is code-behind based solution, there is no binding in XAML:
3. Code behind:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
public static readonly DependencyProperty XProperty = DependencyProperty.Register(
"X", typeof (double), typeof (MainWindow), new PropertyMetadata(default(double)));
public double X
{
get { return (double) GetValue(XProperty); }
set { SetValue(XProperty, value); }
}
public static readonly DependencyProperty YProperty = DependencyProperty.Register(
"Y", typeof (double), typeof (MainWindow), new PropertyMetadata(default(double)));
private static double _position;
public double Y
{
get { return (double) GetValue(YProperty); }
set { SetValue(YProperty, value); }
}
private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
X = ++_position;
Y = _position;
}
private void FrameworkElement_OnLoaded(object sender, RoutedEventArgs e)
{
var grid = sender as Grid;
if(grid == null) return;
var transform = grid.RenderTransform as TranslateTransform;
if (transform == null)
{
transform = InitTransformBinding();
grid.RenderTransform = transform;
}
else
{
InitTransformBinding(transform);
}
}
private TranslateTransform InitTransformBinding(TranslateTransform t = null)
{
var transform = t ?? new TranslateTransform();
var xBinding = new Binding();
xBinding.Source = this;
xBinding.Path = new PropertyPath("X");
xBinding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
xBinding.Mode = BindingMode.TwoWay;
BindingOperations.SetBinding(transform, TranslateTransform.XProperty, xBinding);
var yBinding = new Binding();
yBinding.Source = this;
yBinding.Path = new PropertyPath("Y");
yBinding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
yBinding.Mode = BindingMode.TwoWay;
BindingOperations.SetBinding(transform, TranslateTransform.YProperty, yBinding);
return transform;
}
}
4. XAML code:
<Window x:Class="TransformBindingSoHelpAttempt.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" x:Name="This">
<Grid HorizontalAlignment="Center" VerticalAlignment="Center" Loaded="FrameworkElement_OnLoaded">
<Button Content="Click" Width="100" Height="100" Click="ButtonBase_OnClick"></Button>
</Grid>
Update 2, here on each button click you will scale the grid.
5. Xaml code:
Window x:Class="TransformBindingSoHelpAttempt.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:transformBindingSoHelpAttempt="clr-namespace:TransformBindingSoHelpAttempt"
Title="MainWindow" Height="350" Width="525" x:Name="This">
<Window.DataContext>
<transformBindingSoHelpAttempt:MainViewModel/>
</Window.DataContext>
<Grid HorizontalAlignment="Center" VerticalAlignment="Center">
<ListView ItemsSource="{Binding Items}">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate DataType="{x:Type transformBindingSoHelpAttempt:ItemDataContext}">
<Grid>
<Grid.RenderTransform>
<ScaleTransform
ScaleX="{Binding X, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
ScaleY="{Binding Y, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
</Grid.RenderTransform>
<Button Content="{Binding ButtonContent}" Command="{Binding ButtonCommand}"/>
</Grid>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</ListView.ItemContainerStyle>
</ListView>
</Grid>
6. View models:
public class MainViewModel:BaseObservableObject
{
public MainViewModel()
{
Items = new ObservableCollection<ItemDataContext>(new List<ItemDataContext>
{
new ItemDataContext{ButtonContent = "A", X = 1.0, Y = 1.0},
new ItemDataContext{ButtonContent = "B", X = 1.0, Y = 1.0},
new ItemDataContext{ButtonContent = "C", X = 1.0, Y = 1.0},
new ItemDataContext{ButtonContent = "D", X = 1.0, Y = 1.0},
});
}
public ObservableCollection<ItemDataContext> Items { get; set; }
}
public class ItemDataContext:BaseObservableObject
{
private ICommand _buttonCommand;
private object _buttonContent;
private double _x;
private double _y;
public double X
{
get { return _x; }
set
{
_x = value;
OnPropertyChanged();
}
}
public double Y
{
get { return _y; }
set
{
_y = value;
OnPropertyChanged();
}
}
public ICommand ButtonCommand
{
get { return _buttonCommand ?? (_buttonCommand = new DelegateCommand(Target)); }
}
public object ButtonContent
{
get { return _buttonContent; }
set
{
_buttonContent = value;
OnPropertyChanged();
}
}
private void Target(object obj)
{
X += 0.2;
Y += 0.2;
}
}
7. How it is looks like:
Please keep in mind that the last update solution is based on LayouTransform and re-build the view on each button click (makes it to be scaled).
Regards,