DependencyProperty and WPF Designer - wpf

class MyLine : Shape {
public static readonly DependencyProperty X11Property;
public static readonly DependencyProperty X22Property;
public static readonly DependencyProperty Y11Property;
public static readonly DependencyProperty Y22Property;
static MyLine() {
X11Property = DependencyProperty.Register("X11", typeof(double), typeof(MyLine), new UIPropertyMetadata(double.NaN));
X22Property = DependencyProperty.Register("X22", typeof(double), typeof(MyLine), new UIPropertyMetadata(double.NaN));
Y11Property = DependencyProperty.Register("Y11", typeof(double), typeof(MyLine), new UIPropertyMetadata(double.NaN));
Y22Property = DependencyProperty.Register("Y22", typeof(double), typeof(MyLine), new UIPropertyMetadata(double.NaN));
}
[TypeConverter(typeof(LengthConverter))]
public double X11 { get { return (double)GetValue(X11Property); } set { SetValue(X11Property, value); } }
[TypeConverter(typeof(LengthConverter))]
public double X22 { get { return (double)GetValue(X22Property); } set { SetValue(X22Property, value); } }
[TypeConverter(typeof(LengthConverter))]
public double Y11 { get { return (double)GetValue(Y11Property); } set { SetValue(Y11Property, value); } }
[TypeConverter(typeof(LengthConverter))]
public double Y22 { get { return (double)GetValue(Y22Property); } set { SetValue(Y22Property, value); } }
protected override System.Windows.Media.Geometry DefiningGeometry {
get {
var geometryGroup = new GeometryGroup();
// Add line
geometryGroup.Children.Add(new LineGeometry(new Point(X11, Y11), new Point(X22, Y22)));
return geometryGroup;
}
}
}
Why when I update the "myLine" coordinates in WPF designer(VS 2010), it does not update it automatically(live)?
When using default "Line" WPF objects, they are automatically updated when the XAML code is changed(edited) in XAML/Design view.

Since these properties affect rendering, you should specify it in the metadata:
X11Property = DependencyProperty.Register("X11", typeof(double), typeof(DirectionLine), new FrameworkPropertyMetadata(double.NaN, FrameworkPropertyMetadataOptions.AffectsRender));
I'm not sure it will be enough for the designer to take it into account, but it's worth a try...

Related

WPF PropertyPath on Custom control

I have a problem, I create a control named Tile (like the Tile on Windows 10).
This tile simulate rotation 3D by using a projection class, like the projection class in Silverlight.
We have a base projection class like this :
abstract public class Projection
: FrameworkElement
{
static public readonly DependencyProperty RotationZProperty = DependencyProperty.Register(
nameof(RotationZ),
typeof(double),
typeof(Projection),
new UIPropertyMetadata(0.0, OnRotationChanged));
static public readonly DependencyProperty RotationYProperty = DependencyProperty.Register(
nameof(RotationY),
typeof(double),
typeof(Projection),
new UIPropertyMetadata(0.0, OnRotationChanged));
static public readonly DependencyProperty RotationXProperty = DependencyProperty.Register(
nameof(RotationX),
typeof(double),
typeof(Projection),
new UIPropertyMetadata(0.0, OnRotationChanged));
public double RotationZ
{
get { return this.GetValue<double>(RotationZProperty); }
set { SetValue(RotationZProperty, value); }
}
public double RotationY
{
get { return this.GetValue<double>(RotationYProperty); }
set { SetValue(RotationYProperty, value); }
}
public double RotationX
{
get { return this.GetValue<double>(RotationXProperty); }
set { SetValue(RotationXProperty, value); }
}
public FrameworkElement Child
{
get;
set;
}
static private void OnRotationChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is Projection pl)
{
pl.OnRotationChanged();
}
}
private void OnRotationChanged()
{
// Some code
}}
After that, we have the PlaneProjectionClass :
[ContentProperty("Child")]
sealed public class PlaneProjection
: Projection
{
}
The Tile class use a dependency property of type Projection :
public class Tile
{
static public readonly DependencyProperty PlaneProjectionProperty = DependencyProperty.Register(
nameof(Projection),
typeof(Projection),
typeof(Tile),
new UIPropertyMetadata());
public Projection Projection
{
get { return (Projection)GetValue(PlaneProjectionProperty); }
private set { SetValue(PlaneProjectionProperty, value); }
}
override public void OnApplyTemplate()
{
Projection = GetTemplateChild("PART_Projection") as Projection;
}
}
So for the XAML, we have this in ControlTemplate :
<controls:PlaneProjection x:Name="PART_PlaneProjection">
<Border>
<Grid>
<!-- Some design -->
</Grid>
</Border>
</controls:PlaneProjection>
Now I would like to animate the planeprojection.
So I create the storyboard and animate the projection with rotationX :
static public void CreateAnimation(Tile tile)
{
Storyboard.SetTarget(anim, tile);
Storyboard.SetTargetProperty(doubleAnim, new PropertyPath("(Tile.Projection).(PlaneProjection.RotationX"));
}
But at debug, I have this error : Cannot resolve all references of the property on the path of the property '(Tile.Projection).(PlaneProjection.RotationX)
I don't understand the mistake :( Any ideas on using PropertyPath on custom control ?
The Projection property in class Tile does not follow the naming conventions for dependency properties.
It should e.g. look like this:
public static readonly DependencyProperty PlaneProjectionProperty =
DependencyProperty.Register(nameof(PlaneProjection), typeof(Projection), typeof(Tile));
public Projection PlaneProjection
{
get { return (Projection)GetValue(PlaneProjectionProperty); }
private set { SetValue(PlaneProjectionProperty, value); }
}
The property path would simply be this:
Storyboard.SetTargetProperty(anim, new PropertyPath("PlaneProjection.RotationX"));
You wouldn't even need a Storyboard. Just call
tile.PlaneProjection.BeginAnimation(Projection.RotationXProperty, anim);
As a note, a private setter does not make the dependency property read-only. See Read-Only Dependency Properties for details.

doing some mathematical calculation on custom dependency property values

I have three dependency property. TestControlHeight, HalfValue1 and HalfValue2. Now, depending on these three value I have to calculate
a third value which will be assigned as the height of the inner control which will also be a dependency property.
height of inner control = TestControlHeight/ (HalfValue1 - HalfValue2);
Where can I write this code to calculate the height of the inner control (which si also a dependency property)
public static readonly DependencyProperty TestControlHeightProperty =
DependencyProperty.Register("TestControlHeight", typeof (double),
typeof (TestControl), new PropertyMetadata(default(double)));
public double TestControlHeight
{
get { return (double) GetValue(TestControlHeightProperty); }
set { SetValue(TestControlHeightProperty, value); }
}
public static readonly DependencyProperty HalfValue1Property =
DependencyProperty.Register("HalfValue1", typeof (double), typeof
(TestControl), new PropertyMetadata(default(double)));
public double HalfValue1
{
get { return (double) GetValue(HalfValue1Property); }
set { SetValue(HalfValue1Property, value); }
}
public static readonly DependencyProperty HalfValue2Property =
DependencyProperty.Register("HalfValue2", typeof (double), typeof
(TestControl), new PropertyMetadata(default(double)));
public double HalfValue2
{
get { return (double) GetValue(HalfValue2Property); }
set { SetValue(HalfValue2Property, value); }
}
Thanks & Regards,
From the WPF Unleashed book:
.NET property wrappers are bypassed at runtime when setting dependency properties
in XAML!
Although the XAML compiler depends on the property wrapper at compile time, WPF calls the underlying GetValue and SetValue methods directly at runtime! Therefore, to maintain parity between setting a property in XAML and procedural code, it’s crucial that property wrappers not contain any logic in addition to the GetValue/SetValue calls.
If you want to add custom logic, that’s what the registered callbacks are for. All of WPF’s built-in property wrappers abide by this rule, so this warning is for anyone writing a custom class with its own dependency properties.
So, your code could look like this (not tested):
public static readonly DependencyProperty TestControlHeightProperty =
DependencyProperty.Register("TestControlHeight", typeof(double), typeof(TestControl),
new PropertyMetadata(false, new PropertyChangedCallback(OnHeightChanged)));
public double TestControlHeight
{
get { return (double)GetValue(TestControlHeightProperty); }
set { SetValue(TestControlHeightProperty, value); }
}
public static readonly DependencyProperty HalfValue1Property =
DependencyProperty.Register("HalfValue1", typeof(double), typeof(TestControl),
new PropertyMetadata(false, new PropertyChangedCallback(OnHeightChanged)));
public double HalfValue1
{
get { return (double)GetValue(HalfValue1Property); }
set { SetValue(HalfValue1Property, value); }
}
public static readonly DependencyProperty HalfValue2Property =
DependencyProperty.Register("HalfValue2", typeof(double), typeof(TestControl),
new PropertyMetadata(false, new PropertyChangedCallback(OnHeightChanged)));
public double HalfValue2
{
get { return (double)GetValue(HalfValue2Property); }
set { SetValue(HalfValue2Property, value); }
}
public double MyInnerControlHeight
{
get { return (double)GetValue(MyInnerControlHeightPropertyProperty); }
set { SetValue(MyInnerControlHeightPropertyProperty, value); }
}
public static readonly DependencyProperty MyInnerControlHeightPropertyProperty =
DependencyProperty.Register("MyInnerControlHeightProperty", typeof(double), typeof(TestControl),
new PropertyMetadata(0));
private static void OnHeightChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var testControl = d as TestControl;
if (testControl != null)
{
testControl.MyInnerControlHeight = testControl.TestControlHeight / (testControl.HalfValue1 - testControl.HalfValue2);
}
}

MVVM - How change backcolor for a single char in a datagrid

I would the rows containing the search value (Search Name), show this value (in datagrid) with a different color.
See the pic below.
Some ideas about this ?
You can do this by creating a new control that extends a standard TextBlock, which uses a series of Run items to display the text, using the appropriate formatting.
public class HighlightTextBlock: TextBlock
{
public string BaseText
{
get { return (string)GetValue(BaseTextProperty); }
set { SetValue(BaseTextProperty, value); }
}
public static readonly DependencyProperty BaseTextProperty =
DependencyProperty.Register("BaseText", typeof(string), typeof(HighlightTextBlock), new PropertyMetadata(null, UpdateDisplay));
public string HighlightText
{
get { return (string)GetValue(HighlightTextProperty); }
set { SetValue(HighlightTextProperty, value); }
}
public static readonly DependencyProperty HighlightTextProperty =
DependencyProperty.Register("HighlightText", typeof(string), typeof(HighlightTextBlock), new PropertyMetadata(null, UpdateDisplay));
public Brush HighlightBrush
{
get { return (Brush)GetValue(HighlightBrushProperty); }
set { SetValue(HighlightBrushProperty, value); }
}
public static readonly DependencyProperty HighlightBrushProperty =
DependencyProperty.Register("HighlightBrush", typeof(Brush), typeof(HighlightTextBlock), new PropertyMetadata(Brushes.Orange, UpdateDisplay));
public bool HighlightCaseSensitive
{
get { return (bool)GetValue(HighlightCaseSensitiveProperty); }
set { SetValue(HighlightCaseSensitiveProperty, value); }
}
public static readonly DependencyProperty HighlightCaseSensitiveProperty =
DependencyProperty.Register("HighlightCaseSensitive", typeof(bool), typeof(HighlightTextBlock), new PropertyMetadata(false, UpdateDisplay));
private static void UpdateDisplay(DependencyObject sender, DependencyPropertyChangedEventArgs args)
{
var hightlightTextBlock = sender as HighlightTextBlock;
if (hightlightTextBlock == null)
return;
hightlightTextBlock.Inlines.Clear();
if (string.IsNullOrEmpty(hightlightTextBlock.BaseText))
return;
if (string.IsNullOrEmpty(hightlightTextBlock.HighlightText))
{
hightlightTextBlock.Inlines.Add(new Run(hightlightTextBlock.BaseText));
return;
}
var textItems = Regex.Split(hightlightTextBlock.BaseText,
"(" + hightlightTextBlock.HighlightText + ")",
hightlightTextBlock.HighlightCaseSensitive ? RegexOptions.None : RegexOptions.IgnoreCase);
foreach (var item in textItems)
{
var run = new Run(item);
var highlight = hightlightTextBlock.HighlightCaseSensitive
? string.Compare(item, hightlightTextBlock.HighlightText, StringComparison.InvariantCulture) == 0
: string.Compare(item, hightlightTextBlock.HighlightText, StringComparison.InvariantCultureIgnoreCase) == 0;
if (highlight)
run.Background = hightlightTextBlock.HighlightBrush;
hightlightTextBlock.Inlines.Add(run);
}
}
}
The brackets around the HighlightText value tells Regex.Split to include the matched text in the returned list of items.
This control can then be used as part of an item template in your datagrid column definition. See here for an example of how to do that.

WPF Binding Expression and Dependency property

I am trying to bind a text box to a dependency property to change its width. The following code is not working. Any help?
public class ToolbarManager : DependencyObject
{
public static readonly DependencyProperty toolbarButtonWidth = DependencyProperty.Register("toolbarButtonWidth", typeof(Double), typeof(ToolbarManager), new FrameworkPropertyMetadata(32.0, FrameworkPropertyMetadataOptions.AffectsMeasure ));
public static readonly DependencyProperty toolbarButtonHeight = DependencyProperty.Register("toolbarButtonHeight", typeof(Double), typeof(ToolbarManager), new FrameworkPropertyMetadata(32.0, FrameworkPropertyMetadataOptions.AffectsMeasure));
public double ButtonWidth
{
get { return (double)GetValue(toolbarButtonWidth); }
set { SetValue(toolbarButtonWidth, value); }
}
public double ButtonHeight
{
get { return (double)GetValue(toolbarButtonHeight); }
set { SetValue(toolbarButtonHeight, value); }
}
public static ToolbarManager Instance { get; private set; }
static ToolbarManager()
{
Instance = new ToolbarManager();
}
}
Here is the markup code:
<TextBox Width="{Binding Source={x:Static local:ToolbarManager.Instance}, Path=ButtonWidth, Mode=OneWay}" />
The default value works, but if I modify the value in code nothing happens ?!!!
rename your dependency property should solve your problem
public class ToolbarManager : DependencyObject
{
public static readonly DependencyProperty ButtonWidthProperty =
DependencyProperty.Register("ButtonWidth", typeof(Double), typeof(ToolbarManager), new FrameworkPropertyMetadata(32.0, FrameworkPropertyMetadataOptions.AffectsMeasure ));
public static readonly DependencyProperty ButtonHeightProperty =
DependencyProperty.Register("ButtonHeight", typeof(Double), typeof(ToolbarManager), new FrameworkPropertyMetadata(32.0, FrameworkPropertyMetadataOptions.AffectsMeasure));
public double ButtonWidth
{
get { return (double)GetValue(ButtonWidthProperty); }
set { SetValue(ButtonWidthProperty, value); }
}
public double ButtonHeight
{
get { return (double)GetValue(ButtonHeightProperty); }
set { SetValue(ButtonHeightProperty, value); }
}
public static ToolbarManager Instance { get; private set; }
static ToolbarManager()
{
Instance = new ToolbarManager();
}
}
hope this helps

Silverlight Dependancy Property Change Event Problem

I have a custom control that has a Dependancy Property...it has a few but let us say Dragable is my problem. The property is a boolean and I want to execute a piece of code each time it changes...a toggle.
I have two options, both shown below
[Category("Modal Options")]
public bool Dragable
{
get { return (bool)GetValue(DragableProperty); }
set { SetValue(DragableProperty, value); toggleDragable(); }
}
// Using a DependencyProperty as the backing store for Dragable. This enables animation, styling, binding, etc...
public static readonly DependencyProperty DragableProperty =
DependencyProperty.Register("Dragable", typeof(bool),
typeof(PlussWindow), new PropertyMetadata(false));
private void MakeDragable()
{
this.dragBehavior.Attach(this.LayoutRoot);
}
private void MakeUnDragable()
{
this.dragBehavior.Detach();
}
public virtual void toggleDragable()
{
if (this.Dragable)
{
MakeUnDragable();
}
else
{
MakeDragable();
}
}
or
[Category("Modal Options")]
public bool Dragable
{
get { return (bool)GetValue(DragableProperty); }
set { SetValue(DragableProperty, value); }
}
// Using a DependencyProperty as the backing store for Dragable. This enables animation, styling, binding, etc...
public static readonly DependencyProperty DragableProperty =
DependencyProperty.Register("Dragable", typeof(bool),
typeof(PlussWindow), new PropertyMetadata(false, (o, e) => { (o as PlussWindow).toggleDragable(); }
));
private void MakeDragable()
{
this.dragBehavior.Attach(this.LayoutRoot);
}
private void MakeUnDragable()
{
this.dragBehavior.Detach();
}
public virtual void toggleDragable()
{
if (this.Dragable)
{
MakeUnDragable();
}
else
{
MakeDragable();
}
}
Each method results in a 'Object reference not set to an instance of an object'
I usually use binding to get over this problem, e.g Visibility or Text are easily done, but for custom functionality I need to enable this in code.
How do I do this, noting that the propertychanged method is static?
Try this:
public bool Dragable
{
get { return (bool)GetValue(DragableProperty); }
set { SetValue(DragableProperty, value); }
}
public static readonly DependencyProperty DragableProperty =
DependencyProperty.Register("Dragable", typeof(bool), typeof(PlussWindow), new PropertyMetadata(false, new PropertyChangedCallback(onDragableChange)));
private static void onDragableChange(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
bool validate = (bool)e.NewValue;
PlussWindow win = (PlussWindow) d;
if (validate)
{
win.dragBehavior.Attach(this.LayoutRoot);
}
else
{
win.dragBehavior.Detach();
}
}

Resources