2016-04-25 4 views
0

Я создал свой usercontrol с зависимостью. Я заметил, что если свойство зависимостей имеет то же имя, что и свойство, возвращаемое в свойство, когда я вставляю элемент управления внутри в окна и записываю через код xaml значение, этот элемент управления не отображает метки, мне нужно вставить код в значение и при запуске приложение управляет отображением меток.Зависимость от странного поведения

Если я изменяю зарегистрированное имя dependancypropety, то controll. Покажите метки без передачи значения через код позади и покажите lable каждый раз, когда я изменяю значение через xaml или через codebehind.

это мой пользовательский контроль. 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> 

и это код позади:

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 - 
} 

это 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> 

это 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; 
    } 
} 
} 

если вы хотите попробовать, пожалуйста, удалите строку после имени свойства зависимостей компонентов и изменения де Initialize в этой форме

public static readonly DependencyProperty NumOfLabelsProperty=DependencyProperty.Register("NumOfLabelsP",typeof(byte),typeof(MyUserControl1), new PropertyMetadata(byte.MinValue)); 

ответ

2

и писать с помощью XAML коды значения, этот элемент управления не показывать этикетки, Мне нужно вставить код в код

Это правильное документированное поведение.

Свойство public byte NumOfLabels { get ... set ... } - это «входная дверь» для кода позади, привязка данных не будет использовать его.

Найти другое решение для логики в set { }. Вы можете добавить обратные вызовы в метод Register для этого.

И, пожалуйста, не используйте byte здесь. Это номер, используйте int.

-1

ваш xaml плохой. Фактически GridRoot, используемый в ваших окнах, отличается от используемого в вашем userControl. Для лучшего поведения вам необходимо вставить пользовательский контроль в новые окна, а затем установить свое свойство.ваш XAML должен выглядеть примерно так

<x:Windows> 
    <local :MyUserControl1 NumOfLabels = 7/> 
</x:Windows> 
1

Ваше NumOfLabels собственность должна быть объявлена ​​как это:

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(); 
} 

Обратите внимание, что вы не должны ничего другого назвать чем GetValue и SetValue в CLR обертку свойства зависимостей , как описано в Checklist for Defining a Dependency Property:

Реализация "Wrapper"

... Во всех исключительных случаях реализации вашей оболочки должны выполнять только действия GetValue и SetValue соответственно. Причина этого - , обсуждаемая в теме XAML Loading and Dependency Properties.

Вам необходимо зарегистрировать PropertyChangedCallback, чтобы реагировать на изменения стоимости имущества.

Кроме того, нет необходимости реализовывать INotifyPropertyChanged для свойств зависимостей, поскольку они реализуют собственный механизм уведомления об изменениях.