Как работать со свойствами элемента шаблона - PullRequest
0 голосов
/ 18 сентября 2011

Прежде всего, я прошу прощения за следующий подробный вопрос. Поскольку я новичок в WPF, я решил объяснить больше, чтобы получить больше советов!


У меня есть UserControl вроде:

<UserControl x:Class="MyNamespace.MyUserControl2"...
             xmlns:local="clr-namespace:MyNamespace"
             Style="{DynamicResource ResourceKey=style1}">
    <UserControl.Resources>
        <Style x:Key="style1" TargetType="{x:Type UserControl}">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type UserControl}">
                        ...
                        <local:MyUserControl1 x:Name="myUserControl1" .../>
                        ...
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </UserControl.Resources>
</UserControl>

Чтобы получить доступ к myUserControl1 из кода, я использовал свойство.

private MyUserControl1 _myUserControl1;
private MyUserControl1 myUserControl1
{
    get
    {
        if (_myUserControl1 == null)
            _myUserControl1 = this.Template.FindName("myUserControl1", this) as MyUserControl1;

        return _myUserControl1;
    }
}

(Это хороший подход для доступа к элементу шаблона?)

С другой стороны, в классе MyUserControl2 есть свойство зависимости (скажем, DP1), которое отвечает за изменение одного из myUserControl1 свойств зависимости. (Скажем SomeProperty)

private static void IsDP1PropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    var instance = d as MyUserControl2;
    if (instance != null)
    {
        instance.myUserControl1.SomeProperty = function(e.NewValue);
    }
}

Когда я попытался запустить приведенный выше код, я заметил, что instance.myUserControl1 имеет значение null. Так я и отнесся к этому так:

if (instance != null && instance.myUserControl1 != null)
{
    instance.myUserControl1.SomeProperty = function(e.NewValue);
}

Хотя этот подход решил проблему, он заставляет myUserControl1.SomeProperty оставаться неинициализированным. Итак, я поместил следующий фрагмент кода в событие загружено , чтобы разрешить его:

private void MyUserControl2_Loaded(object sender, RoutedEventArgs e)
{
    this.myUserControl1.SomeProperty = function(DP1);
}

После этого я столкнулся с другой проблемой!

Когда я установил какое-то значение на DP1 с использованием атрибута стиля setter , я получил исключение null reference , которое говорит, что свойство myUserControl1 все еще равно нулю в загружено событие. Как я могу обойти это? -Спасибо.

1 Ответ

1 голос
/ 18 сентября 2011

Полагаю, у вас до сих пор нет четкого представления о WPF.

Вы сталкиваетесь с таким количеством неприятностей, потому что ваш подход больше похож на winforms, чем на функционал.WPF усложняет вашу жизнь, если вы настаиваете на его обязательном использовании.

Прежде всего, шаблон представляет собой функцию, которая инструктирует движок WPF о том, как создать фактическое визуальное дерево во время выполнения.Вы должны использовать имя в качестве ссылки в шаблоне ONLY внутри элемента управления хостингом (т.е. MyUserControl2) и получать ссылку на экземпляр из метода OnApplyTemplate.Больше нигде.

Пример:

private MyUserControl1 _myUserControl1;

public override void OnApplyTemplate()
{
  this._myUserControl1 = this.GetTemplateChild("myUserControl1") as MyUserControl1;
  //here you should check whether the instance is actually set
}

Ссылка на любой элемент управления должна храниться как частная: никакая защищенная / внутренняя / открытая экспозиция какого-либо из размещенных элементов управления.

Второй пункт: как связать два свойства вместе.

Ваша цель - «связать» свойство элемента управления с другим, предоставляемым размещенным.Эта задача абсолютно нормальная, и это одна из лучших функций, предлагаемых WPF.

Предположим, что два свойства имеют один и тот же тип, поэтому могут быть связаны напрямую.В вашем xaml:

    <ControlTemplate TargetType="{x:Type UserControl}">
         ...
       <local:MyUserControl1 x:Name="myUserControl1" 
   SomeProperty="{Binding Path=DP1, RelativeSource={RelativeSource Mode=TemplatedParent}}"
   .../>
         ...
    </ControlTemplate>

Обратите внимание, что: (1) SomeProperty должно быть DependencyProperty, (2) должно быть доступно для записи, (3) DP1 должно быть также DP, или, по крайней мере, уведомлять о любых измененияхчерез шаблон INotifyPropertyChanged.

Изображенный синтаксис обычно связывается: SomeProperty = DP1, но не наоборот.Если вам нужно двунаправленное отображение, вы должны добавить «Mode = TwoWay» внутри предложения «Binding».

Если вы хотите настроить функцию, которая отображает два свойства, просто определите свой собственный конвертер через интерфейс IValueConverter, затем объявите это в xaml.

Здесь вы найдете несколько полезных сведений: http://msdn.microsoft.com/en-us/library/ms752347.aspx

Cheers

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...