none
WPF. DependencyProperty. UserControl RRS feed

  • Вопрос

  • Хочу разобраться с работой DependencyProperty. Создал простой начальный пример (по образу и подобию, грешен). Но не работает.

    XAML:

    <UserControl x:Class="DP_Text.UserControl1"
                 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"
                 xmlns:uc="DP_Text"
                 mc:Ignorable="d" 
                 d:DesignHeight="300" d:DesignWidth="300">
        <Grid>
            <TextBox Text="{Binding Eklmn}"/>
        </Grid>
    </UserControl>


    C#

    using System;
    using System.Windows;
    using System.Windows.Controls;
    
    namespace DP_Text
    {
    
        public partial class UserControl1 : UserControl
        {
            public static DependencyProperty EklmnProperty = 
                DependencyProperty.Register("Eklmn", typeof(string), typeof(UserControl1), new UIPropertyMetadata(String.Empty));
    
            public string Eklmn
            {
                get { return (string)GetValue(EklmnProperty); }
                set
                {
                    SetValue(EklmnProperty, value);
                }
            }
            
            public UserControl1()
            {
                InitializeComponent();
            }
        }
    }
    

    UserControl вставляю в Window

    <Window x:Class="DP_Text.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="MainWindow" Height="350" Width="525"
            DataContext="{Binding RelativeSource={RelativeSource Self}}" 
            xmlns:uc="clr-namespace:DP_Text">
        <StackPanel Name="MyStackPanel">
            <uc:UserControl1 Eklmn="Text goes here" />
        </StackPanel>
    </Window>
    
    По идее, в TextBox должен отобразиться текст из Property Eklmn. Но что-то идёт не так.
    25 марта 2013 г. 10:22

Ответы

  • Насколько я понял из всего,создание нового свойства, не характерного для элемента возможно только через обёртку ввиде usercontrol`а?

    Нет, есть еще наследование. Например, добавляю в WPF проект новый класс:

    public class SelectableLabel : Label
    {
        public SelectableLabel() : base()
        {
            this.Background = new SolidColorBrush(Colors.Red);
        }
    
        public bool IsSelected
        {
            get { return (bool)GetValue(IsSelectedProperty); }
            set { SetValue(IsSelectedProperty, value); }
        }
    
        // Using a DependencyProperty as the backing store for IsSelected.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty IsSelectedProperty =
            DependencyProperty.Register("IsSelected", typeof(bool), typeof(SelectableLabel), new UIPropertyMetadata(false, IsSelectedChanged));
    
        private static void IsSelectedChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            SelectableLabel label = sender as SelectableLabel;
            if (label != null)
            {
                if (label.IsSelected)
                {
                    label.Background = new SolidColorBrush(Colors.Green);
                }
                else
                {
                    label.Background = new SolidColorBrush(Colors.Red);
                }
    
            }
        }
    }

    Меняем разметку главной формы:

    <Window xmlns:my="clr-namespace:WpfApplication34"  x:Class="WpfApplication34.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="MainWindow" Height="350" Width="525">
        <StackPanel>
            <my:SelectableLabel Content="Привет" IsSelected="True" />
            <my:SelectableLabel Content="Пока" IsSelected="False" />
        </StackPanel>
    </Window>

    Запускаем:

    Как видите, я обошелся и без UserControl

    • Помечено в качестве ответа rz3rr 26 марта 2013 г. 6:35
    25 марта 2013 г. 17:57
    Отвечающий

Все ответы

  • Попробуйте поменять определение свойства на:

    public static DependencyProperty EklmnProperty = DependencyProperty.Register("Eklmn", typeof(string), typeof(UserControl1), new UIPropertyMetadata(String.Empty, textChanged));

    private static void textChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
            {
                var c = sender as UserControl1;

                if (c != null)
                {
                    c.textBlock1.text = e.NewValue;
                }
            }

    а в XAML разметке добавить имя для текстового блока установить имя textBlock1

    • Помечено в качестве ответа rz3rr 25 марта 2013 г. 11:09
    • Снята пометка об ответе rz3rr 25 марта 2013 г. 11:48
    25 марта 2013 г. 11:00
  • добавил

    DataContext="{Binding RelativeSource={RelativeSource Self}}"

    в "шапке" UserControl - всё заработало

    Ради интереса сейчас опробую Ваш вариант (без DataContext).

    25 марта 2013 г. 11:03
  • Brash_Oб работает и Ваш вариант с маленькой корректировкой

    . . . . . .
    
     c.textBlock1.Text = (string)e.NewValue;
    
    . . . . . .


    Спасибо.
    • Изменено rz3rr 25 марта 2013 г. 11:09
    25 марта 2013 г. 11:08
  • А как программно обратиться к Property Eklmn? И из usercontrol и из window?

    Ну, например UserControl.Eklmn ?


    • Изменено rz3rr 25 марта 2013 г. 11:49
    25 марта 2013 г. 11:47
  • А как программно обратиться к Property Eklmn? И из usercontrol и из window?

    Тему рано закрыл ))

    Из UserControl просто Eklmn. Он найдет. А из окна куда вы поставили UserControl - ИмяУзерКонтролла.Eklmn

    Женат на WPF. Тайно встречаюсь с WinRT. Не сложилось с C#!

    25 марта 2013 г. 11:50
    Отвечающий
  • Чуть не так выразился. Объясню. Добавил ещё

    public static DependencyProperty IsSelectedProperty = DependencyProperty.Register("IsSelected", typeof(bool), typeof(Label), new UIPropertyMetadata(String.Empty, IsSelectedChanged));
    
            public bool IsSelected
            {
                get { return (bool) GetValue(IsSelectedProperty); }
                set{SetValue(IsSelectedProperty,value);}
            }
    
            private static void IsSelectedChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
            {
                 var c = sender as Label; 
                 if (c != null) { 
                     MessageBox.Show("Сoстояние изменено на " + e.NewValue);
                 }
            }

    в XAML usercontrol`a добавил

    <Label Name="Label1"/>
    <Button Click="button_click"/>

    а тут хочу

    private void button_click(object sender, RoutedEventArgs e)
            {
                Label1.IsSelected = true;
            }

    но ругается на IsSelected, что нет такого определения.


    • Изменено rz3rr 25 марта 2013 г. 12:06
    25 марта 2013 г. 12:02
  • IsSelected не является частью Label. Он является свойством вашего UserControl. Label же это запчасти внутри UserControl, так сказать представление внештатного вида.

    достаточно просто IsSelected = true;

    но не уверен, что вы хотите именно это. Вообще для более лучшего понимания DependencyProperty и UserControl в целом советую почитать книгу Мэтью МакДонольда "WPF для профессионалов с примерами на C#"


    Женат на WPF. Тайно встречаюсь с WinRT. Не сложилось с C#!

    25 марта 2013 г. 12:23
    Отвечающий
  • Есть такая книга в pdf. Сейчас взгляну. Спасибо. Тему пока не закрываю.

    25 марта 2013 г. 12:26
  • Насколько я понял из всего,создание нового свойства, не характерного для элемента возможно только через обёртку ввиде usercontrol`а?

    25 марта 2013 г. 16:01
  • Насколько я понял из всего,создание нового свойства, не характерного для элемента возможно только через обёртку ввиде usercontrol`а?

    В целом да. Об этом кстати говорили тут.

    Женат на WPF. Тайно встречаюсь с WinRT. Не сложилось с C#!

    25 марта 2013 г. 16:07
    Отвечающий
  • Насколько я понял из всего,создание нового свойства, не характерного для элемента возможно только через обёртку ввиде usercontrol`а?

    Нет, есть еще наследование. Например, добавляю в WPF проект новый класс:

    public class SelectableLabel : Label
    {
        public SelectableLabel() : base()
        {
            this.Background = new SolidColorBrush(Colors.Red);
        }
    
        public bool IsSelected
        {
            get { return (bool)GetValue(IsSelectedProperty); }
            set { SetValue(IsSelectedProperty, value); }
        }
    
        // Using a DependencyProperty as the backing store for IsSelected.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty IsSelectedProperty =
            DependencyProperty.Register("IsSelected", typeof(bool), typeof(SelectableLabel), new UIPropertyMetadata(false, IsSelectedChanged));
    
        private static void IsSelectedChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            SelectableLabel label = sender as SelectableLabel;
            if (label != null)
            {
                if (label.IsSelected)
                {
                    label.Background = new SolidColorBrush(Colors.Green);
                }
                else
                {
                    label.Background = new SolidColorBrush(Colors.Red);
                }
    
            }
        }
    }

    Меняем разметку главной формы:

    <Window xmlns:my="clr-namespace:WpfApplication34"  x:Class="WpfApplication34.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="MainWindow" Height="350" Width="525">
        <StackPanel>
            <my:SelectableLabel Content="Привет" IsSelected="True" />
            <my:SelectableLabel Content="Пока" IsSelected="False" />
        </StackPanel>
    </Window>

    Запускаем:

    Как видите, я обошелся и без UserControl

    • Помечено в качестве ответа rz3rr 26 марта 2013 г. 6:35
    25 марта 2013 г. 17:57
    Отвечающий
  • Спасибо... Сегодня нет возможности опробовать, но почти то, что нужно.

    25 марта 2013 г. 18:49
  • тут ещё надо, видимо, добавить ссылку на класс

    xmlns:my="clr-namespace:WpfApplication34"

    26 марта 2013 г. 6:29
  • Очень похоже на реализацию UserControl`ом, но без XAML.

    Всё работает. Всем спасибо.

    26 марта 2013 г. 6:35
  • тут ещё надо, видимо, добавить ссылку на класс

    xmlns:my="clr-namespace:WpfApplication34"


    Она там есть, просто в первой строке...
    26 марта 2013 г. 7:55
    Отвечающий
  • сорь... не заметил )

    26 марта 2013 г. 8:11