Всем привет. Создаю userControl В нем - ContentPresenter Создаю DependencyProperty для ContentPresenter.Content В MainPage вставляю userControl В его DependencyProperty вставляю TextBlock и даю ему имя При запуске приложения вижу, что в объекте MainPage есть поле с названием TextBlock, но оно null Хотя на экране все ок Ниже код. Я ставлю в дебаггере точку останова на операции в методе Button_Click четко видно что this.MyLabel равно null. Вылетает ArgumentNullException Если присвоить имя созданному userControl или любому другому контролу - все ок. Я думаю, что проблема где-то в реализации DependencyProperty - реализация необычная и дает много возможностей (по сути дает в Silverlight возможности WPF DependencyProperty) Либо же это баг Silverlight Вот здесь лежит архив с кодом проекта и сниппетом для DependencyProperty: iFolderПомогите пожалуйста разобраться с проблемой Код | <UserControl x:Class="TestApp.SomeContainer" 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="White"> <ContentPresenter x:Name="MyCP"/> </Grid> </UserControl>
|
Код | using System; using System.Windows; using System.Windows.Controls;
namespace TestApp { public partial class SomeContainer : UserControl { public SomeContainer() { InitializeComponent();
MyContentChanged += new RoutedPropertyChangedEventHandler<FrameworkElement>(SomeContainer_MyContentChanged);
//apply default values to the View this.SomeContainer_MyContentChanged(null, null); }
#region Event handlers //bridge between two objects - DependencyProperty and ContentPresenter //This EH used when dependencyProperty changed from code void SomeContainer_MyContentChanged(object sender, RoutedPropertyChangedEventArgs<FrameworkElement> e) { this.MyCP.Content = this.MyContent; } #endregion Event handlers
#region public FrameworkElement MyContent /// <summary> /// Gets or sets the value of MyContent dependency property. /// </summary> public FrameworkElement MyContent { get { return (FrameworkElement)GetValue(MyContentProperty); } set { SetValue(MyContentProperty, value); } } /// <summary> /// Identifies the MyContent dependency property. /// </summary> public static readonly DependencyProperty MyContentProperty = DependencyProperty.Register( "MyContent", typeof(FrameworkElement), typeof(SomeContainer), new PropertyMetadata(null, OnMyContentPropertyChanged)); /// <summary> /// MyContentProperty property changed handler. /// </summary> /// <param name="d">SomeContainer that changed its MyContent.</param> /// <param name="e">Event arguments.</param> private static void OnMyContentPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { SomeContainer source = (SomeContainer)d; FrameworkElement newValue = (FrameworkElement)e.NewValue; FrameworkElement oldValue = (FrameworkElement)e.OldValue;
// validate newValue if (!IsValidMyContent(source, oldValue, newValue)) { // revert back to e.OldValue source._nestLevelMyContent++; source.SetValue(e.Property, e.OldValue); source._nestLevelMyContent--;
// throw ArgumentException throw new ArgumentException("Invalid MyContentProperty value", "e"); }
if (source._nestLevelMyContent == 0) { // remember initial state source._initialMyContent = oldValue; source._requestedMyContent = newValue; }
source._nestLevelMyContent++;
// coerce newValue FrameworkElement coercedValue = (FrameworkElement)CoerceMyContent(d, e.NewValue); if (newValue != coercedValue) { // always set MyContentProperty to coerced value source.MyContent = coercedValue; }
source._nestLevelMyContent--;
if (source._nestLevelMyContent == 0 && source.MyContent != source._initialMyContent) { // fire changed event only at root level and when there is indeed a change source.OnMyContentChanged(oldValue, source.MyContent); } } /// <summary> /// MyContentProperty validation handler. /// </summary> /// <param name="value">New value of MyContentProperty.</param> /// <returns> /// Returns true if value is valid for MyContentProperty, false otherwise. /// </returns> private static bool IsValidMyContent(SomeContainer source, FrameworkElement oldValue, FrameworkElement newValue) { //place here your code for validating new value (if you need)
//return false if newValue equals oldValue if (newValue.Equals(oldValue)) { return false; }
return true; } /// <summary> /// MyContentProperty coercion handler. /// </summary> /// <param name="d">SomeContainer that changed its MyContent.</param> /// <param name="value">Event arguments.</param> /// <returns> /// Coerced effective value of MyContentProperty from input parameter value. /// </returns> private static object CoerceMyContent(DependencyObject d, object value) { SomeContainer source = (SomeContainer)d; FrameworkElement newValue = (FrameworkElement)value;
//place here your code (if you need)
return newValue; } /// <summary> /// MyContentProperty changed event. /// </summary> public event RoutedPropertyChangedEventHandler<FrameworkElement> MyContentChanged;
/// <summary> /// Called by OnMyContentPropertyChanged static method to fire MyContentChanged event. /// </summary> /// <param name="oldValue">The old value of MyContent.</param> /// <param name="newValue">The new value of MyContent.</param> protected virtual void OnMyContentChanged(FrameworkElement oldValue, FrameworkElement newValue) { //place here your code (if you need)
RoutedPropertyChangedEventArgs<FrameworkElement> e = new RoutedPropertyChangedEventArgs<FrameworkElement>(oldValue, newValue); if (MyContentChanged != null) { MyContentChanged(this, e); } }
/// <summary> /// Cached previous value of MyContentProperty. /// </summary> private FrameworkElement _initialMyContent = null; /// <summary> /// Cached originally requested value of MyContentProperty by user. /// </summary> private FrameworkElement _requestedMyContent; /// <summary> /// level of recursive calls of PropertyChangedCallback, for implementing validation & coercion, /// and preventing internal transitions from visible to client by not firing bogus changed notifications /// </summary> private int _nestLevelMyContent; #endregion public FrameworkElement MyContent
} }
|
Код | <UserControl x:Class="TestApp.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" xmlns:local="clr-namespace:TestApp" mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="400">
<Grid x:Name="LayoutRoot" Background="White"> <StackPanel Width="300"> <Button Content="click it!" Click="Button_Click" Height="30" /> <local:SomeContainer> <local:SomeContainer.MyContent> <TextBlock x:Name="MyLabel" Text="Any text" /> </local:SomeContainer.MyContent> </local:SomeContainer> </StackPanel> </Grid> </UserControl>
|
Код | using System.Windows; using System.Windows.Controls;
namespace TestApp { public partial class MainPage : UserControl { public MainPage() { InitializeComponent(); }
private void Button_Click(object sender, RoutedEventArgs e) { this.MyLabel.Text = "hellow from code"; } } }
|
Это сообщение отредактировал(а) makaka - 1.8.2011, 23:02
|