Reputation: 637
I've created my usercontrol with a dependencyproperty. I noted that if the dependency property has the same name regitered of property, when I insert the control inside in a windows and write via xaml code the value , this control not show the labels, I need insert in codebehind the value and when start the application the control show the labels.
If I change the registered name of dependancypropety the controll Show the labels without pass the value via code behind, and show the lable each time I modify the value via xaml or via codebehind.
this is my usercontrol. xaml:
<UserControl x:Class="My.Controls.MyUserControl1"
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">
<Grid x:Name="GridRoot">
</Grid>
and this is code behind:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.ComponentModel;
namespace My.Controls
{
/// <summary>
/// Interaction logic for Plate.xaml
/// </summary>
public partial class MyUserControl1 : UserControl, INotifyPropertyChanged
{
private Point pointOfOrigin;
private Double labelsRad;
//private Byte numOfChucks;
private List<Label> labelNumber = new List<Label>();
private List<Canvas> label = new List<Canvas>();
#region - Dependency Properties mandatory for Binding -
public static readonly DependencyProperty NumOfLabelsProperty =
DependencyProperty.Register("NumOfLabels", typeof(byte), typeof(MyUserControl1), new PropertyMetadata(byte.MinValue));
#endregion - Dependency Properties for Binding -
[DefaultValue(byte.MinValue)]
public byte NumOfLabels
{
get { return (byte)GetValue(MyUserControl1.NumOfLabelsProperty); }
set
{
if (this.NumOfLabels != value)
{
SetValue(MyUserControl1.NumOfLabelsProperty, value);
LabelsRender();
OnPropertyChanged("NumOfLabels");
}
}
}
public MyUserControl1()
{
InitializeComponent();
this.DataContext = this;
//just to show when the control is designer mode
pointOfOrigin = new Point(this.ActualWidth / 2, this.ActualHeight / 2);
labelsRad = this.Width / 2;
}
private void PosLabels()
{
var indexLabel = Byte.MinValue;
var pointLabel = new Point();
for (; indexLabel < this.NumOfLabels; indexLabel++)
{
pointLabel = new Point((this.ActualWidth + (indexLabel * 50) )/2,(this.ActualHeight + (indexLabel *50))/2) ;
Canvas.SetLeft(labelNumber[indexLabel], pointLabel.X);
Canvas.SetTop(labelNumber[indexLabel], pointLabel.Y);
}
}
private void RemoveLabels()
{
var indexLabel = Byte.MinValue;
for (; indexLabel < labelNumber.Count; indexLabel++)
{
this.label[indexLabel].Children.Remove(labelNumber[indexLabel]);
this.GridRoot.Children.Remove(label[indexLabel]);
}
//clean up
labelNumber.Clear();
labelNumber.Clear();
GC.Collect();
}
private void AddLabels()
{
var indexLabel = Byte.MinValue;
for (; indexLabel < this.NumOfLabels; indexLabel++)
{
labelNumber.Add(
new Label()
{
Content = (indexLabel + 1).ToString("D2"),
Height = 23,
Width = 23,
Name = "labelNumber" + indexLabel,
});
label.Add(
new Canvas()
{
Name = "Label" + indexLabel,
Height = 23,
Width = 23,
});
label[indexLabel].Children.Add(labelNumber[indexLabel]);
this.GridRoot.Children.Add(label[indexLabel]);
}
}
private void LabelsRender()
{
RemoveLabels();
AddLabels();
PosLabels();
}
#region - INotifyPropertyChanged implementation -
// Basically, the UI thread subscribes to this event and update the binding if the received Property Name correspond to the Binding Path element
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyName));
}
#endregion - INotifyPropertyChanged implementation -
}
this is the windowtest xaml:
<UserControl x:Class="My.Controls.MyUserControl1"
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">
<Grid x:Name="GridRoot">
</Grid>
</UserControl>
this is codeBehind:
enter cousing System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
namespace XTesting
{
/// <summary>
/// Interaction logic for WindowTest.xaml
/// </summary>
public partial class WindowTest : Window
{
public WindowTest()
{
InitializeComponent();
this.MyUserControl.NumOfLabels = 7;
}
}
}
if you want to try please delete the line after Initialize component and change de property dependency name in this form
public static readonly DependencyProperty NumOfLabelsProperty=DependencyProperty.Register("NumOfLabelsP",typeof(byte),typeof(MyUserControl1), new PropertyMetadata(byte.MinValue));
Upvotes: 0
Views: 154
Reputation: 128013
Your NumOfLabels
property should be declared like this:
public static readonly DependencyProperty NumOfLabelsProperty =
DependencyProperty.Register(
"NumOfLabels", typeof(int), typeof(MyUserControl1),
new PropertyMetadata(0, NumOfLabelsPropertyChanged));
public int NumOfLabels
{
get { return (int)GetValue(NumOfLabelsProperty); }
set { SetValue(NumOfLabelsProperty, value); }
}
private static void NumOfLabelsPropertyChanged(
DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
((MyUserControl1)obj).LabelsRender();
}
Note that you should not call anything else than GetValue
and SetValue
in the CLR wrapper of a dependency property, as explained in Checklist for Defining a Dependency Property:
Implementing the "Wrapper"
... In all but exceptional circumstances, your wrapper implementations should perform only the GetValue and SetValue actions, respectively. The reason for this is discussed in the topic XAML Loading and Dependency Properties.
You'll have to register a PropertyChangedCallback
to react on property value changes.
Besides that it is not necessary to implement INotifyPropertyChanged
for dependency properties, because they implement their own change notification mechanism.
Upvotes: 1
Reputation: 157
your xaml is bad. In fact the GridRoot used in your windows is different from the one used in your userControl. For a better behavior, your need to insert you usercontrol in a new windows and then set your property. your xaml should look something like this
<x:Windows>
<local :MyUserControl1 NumOfLabels = 7/>
</x:Windows>
Upvotes: -1
Reputation: 273169
and write via xaml code the value , this control not show the labels, I need insert in codebehind the value
This is the correct, documented behaviour.
Your public byte NumOfLabels { get ... set ... }
property is ony the 'front door' for code behind, the databindings won't use it.
Find another solution for the logic in set { }
. You can add callbacks in the Register method for that.
And please, don't use byte
here. It's a number, use int
.
Upvotes: 2