Re[7]: Всё-равно не работает
От: Peter Fleischer Германия www.informtoools.de
Дата: 29.12.15 11:04
Оценка: 42 (2) +1
IB>Эффекта нет, не работает.

У меня работает:

XAML:

<Window x:Class="WpfApplication1CS.Window18"
        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:WpfApplication1CS"
        mc:Ignorable="d"
        Title="Window18" Height="300" Width="300">
  <Window.Resources>
    <local:Window18VM x:Key="vm"/>
    <DataTemplate x:Key="dt">
      <Label Content="{Binding Data.Name1, Source={StaticResource vm}}" />
    </DataTemplate>
  </Window.Resources>
  <StackPanel>
    <local:Window18UC1 ItemTemplate="{StaticResource dt}"/>
    <Button ContentTemplate="{StaticResource dt}"/>
  </StackPanel>
</Window>


ViewModel:

using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows;

namespace WpfApplication1CS
{
  public class Window18VM : INotifyPropertyChanged
  {
    public Window18VM()
    {
      this._data = new Window18Data() { Name1 = "Текст на кнопке" };
    }
    private Window18Data _data;
    public Window18Data Data
    {
      get { return _data; }
      set
      {
        _data = value;
        OnPropertyChanged("ItemTemplate");
      }
    }
    #region OnPropertyChanged
    public event PropertyChangedEventHandler PropertyChanged;
    private void OnPropertyChanged([CallerMemberName] string propname = "") =>
      PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propname));
    #endregion
  }
  public class Window18Data
  {
    public string Name1 { get; set; }
  }
}


UserControl-XAML:

<UserControl x:Class="WpfApplication1CS.Window18UC1"
             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:local="clr-namespace:WpfApplication1CS"
             mc:Ignorable="d"
             d:DesignHeight="300" d:DesignWidth="300">
  <StackPanel>
    <Button ContentTemplate="{Binding ItemTemplate, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}}"/>
  </StackPanel>
</UserControl>


UserControl-CodeBehind:

using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows;
using System.Windows.Controls;

namespace WpfApplication1CS
{
  /// <summary>
  /// Interaction logic for Window18UC1.xaml
  /// </summary>
  public partial class Window18UC1 : UserControl
  {
    public Window18UC1()
    {
      InitializeComponent();
    }
    private DataTemplate _itemTemplate;
    public DataTemplate ItemTemplate
    {
      get { return _itemTemplate; }
      set
      {
        _itemTemplate = value;
        OnPropertyChanged("ItemTemplate");
      }
    }

    #region OnPropertyChanged
    public event PropertyChangedEventHandler PropertyChanged;
    private void OnPropertyChanged([CallerMemberName] string propname = "") =>
      PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propname));
    #endregion
  }
}
Re[12]: ElementName и Source, RelativeSource не эквивалентн
От: igor-booch Россия  
Дата: 30.12.15 07:53
Оценка: +1 :)
Понятно что использовать DataContext="{Binding RelativeSource={RelativeSource Self}}" нельзя только в UserControl1. В Window можно использовать.

Хорошо. Замените в предыдущем примере строки:

    <DataTemplate x:Key="dt">
      <Label Content="{Binding Data.Name1, RelativeSource={RelativeSource AncestorType={x:Type Window}}}" />
    </DataTemplate>


на

    <DataTemplate x:Key="dt">
      <Label Content="{Binding Data.Name1, ElementName=window}" />
    </DataTemplate>


Казалось бы они эквивалентны, но после них UserControl1 остается без текста, а Button продолжает работать нормально. Почему?

Мне ответили на msdn. https://social.msdn.microsoft.com/Forums/vstudio/en-US/ca1da6ba-80da-4947-824a-af667961cc4b/datatemplate-property-in-a-custom-usercontrol?forum=wpf

Когда внутри шаблона происходит биндинг к Data.Name1, элемент window еще не инициализирован (либо вне области видимости, неважно). В этот момент window не доступен как инициализированный элемент, но доступен по ссылке. Если вышеуказанные строки переписать так:

    <DataTemplate x:Key="dt">
      <Label Content="{Binding Data.Name1, Source={x:Reference window}}" />      
    </DataTemplate>


То заработает и кнопка и UserControl1.
Подробней об отличиях x:Reference и ElementName: http://stackoverflow.com/questions/19244111/what-is-the-difference-between-xreference-and-elementname

Хотя сначала я не понимал почему не работает UserConrol1, теперь я не понимаю почему работает Button.
http://rsdn.ru/Info/rules.xml
Отредактировано 30.12.2015 8:13 igor-booch . Предыдущая версия . Еще …
Отредактировано 30.12.2015 8:02 igor-booch . Предыдущая версия .
[WPF] DataTemplate в своём UserControl'е
От: igor-booch Россия  
Дата: 28.12.15 15:22
Оценка:
Есть Button, у неё есть свойство ContentTemplate, задаем его и все работает нормально.


Сделал свой UserConrol. У него тоже есть аналогичное свойство ItemTemplate

<UserControl x:Class="WpfApplication3.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" 
             DataContext="{Binding RelativeSource={RelativeSource Self}}"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    <StackPanel>
      <Button ContentTemplate="{Binding ItemTemplate}"></Button>  
    </StackPanel>
</UserControl>


using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows;
using System.Windows.Controls;


namespace WpfApplication3
{
    /// <summary>
    /// Interaction logic for UserControl1.xaml
    /// </summary>
    public partial class UserControl1 : UserControl, INotifyPropertyChanged
    {
        private DataTemplate _itemTemplate;

        public UserControl1()
        {
            InitializeComponent();
        }

        public DataTemplate ItemTemplate
        {
            get { return _itemTemplate; }
            set
            {
                _itemTemplate = value;
                OnPropertyChanged("ItemTemplate");
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            var handler = PropertyChanged;
            if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}



Но он, в отличии от кнопки, не работает:

<Window x:Class="WpfApplication3.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:wpfApplication3="clr-namespace:WpfApplication3"
        Title="MainWindow" Height="350" Width="525"
        DataContext="{Binding RelativeSource={RelativeSource Self}}"
        Name="window">
    <Window.Resources>
            <DataTemplate x:Key="template"> 
                <Label Content="{Binding Item.Name1, ElementName=window}" />                           
            </DataTemplate>    
    </Window.Resources>
    <StackPanel>
       <wpfApplication3:UserControl1 ItemTemplate=   "{StaticResource template}" x:Name="Control2" />      
       <Button ContentTemplate="{StaticResource template}" Name="Button"/>          
    </StackPanel>
</Window>



using System.Windows;
namespace WpfApplication3
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            Item = new Item();
            Item.Name1 = "Текст на кнопке";
            InitializeComponent();
        }

        public Item Item { get; set; }
    }

    public class Item
    {
        public string Name1 { get; set; }
    }
}



https://www.dropbox.com/s/e97yatkd4j4aq8d/wpf.jpg?dl=0
http://rsdn.ru/Info/rules.xml
Re: [WPF] DataTemplate в своём UserControl'е
От: Peter Fleischer Германия www.informtoools.de
Дата: 29.12.15 08:10
Оценка:
Missing DataContext!

using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows;
using System.Windows.Controls;


namespace WpfApplication3
{
    /// <summary>
    /// Interaction logic for UserControl1.xaml
    /// </summary>
    public partial class UserControl1 : UserControl, INotifyPropertyChanged
    {
        private DataTemplate _itemTemplate;

        public UserControl1()
        {
            InitializeComponent();

this.DataContext = this; // !!!!!!!!!!!!!!!!!!!!!!!!!!!

        }

        public DataTemplate ItemTemplate
        {
            get { return _itemTemplate; }
            set
            {
                _itemTemplate = value;
                OnPropertyChanged("ItemTemplate");
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            var handler = PropertyChanged;
            if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}
Re[2]: [WPF] DataTemplate в своём UserControl'е
От: Sinix  
Дата: 29.12.15 08:29
Оценка:
Здравствуйте, Peter Fleischer, Вы писали:

PF>Missing DataContext!


Только не DataContext, а RelativeSource у биндинга тогда уж.
Re[3]: [WPF] DataTemplate в своём UserControl'е
От: Peter Fleischer Германия www.informtoools.de
Дата: 29.12.15 08:58
Оценка:
Ok,

<UserControl x:Class="WpfApplication3.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" 
             DataContext="{Binding RelativeSource={RelativeSource Self}}"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    <StackPanel>
        <Button ContentTemplate="{Binding ItemTemplate, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}}"/>
    </StackPanel>
</UserControl>
Re[4]: Всё-равно не работает
От: igor-booch Россия  
Дата: 29.12.15 09:16
Оценка:
Сделал, как Вы сказали, не работает.
У меня же ставится DataContext на уровне UserControl:

<UserControl x:Class="WpfApplication3.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" 

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

             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    <StackPanel>
      <Button ContentTemplate="{Binding ItemTemplate}"></Button>  
    </StackPanel>
</UserControl>
http://rsdn.ru/Info/rules.xml
Re[5]: Всё-равно не работает
От: Peter Fleischer Германия www.informtoools.de
Дата: 29.12.15 09:56
Оценка:
Смотрите здесь.
Re[6]: Всё-равно не работает
От: igor-booch Россия  
Дата: 29.12.15 10:18
Оценка:
PF>Смотрите здесь.

Хорошо, спасибо, буду иметь ввиду.

Убрал установку DataContext в элементе UserControl. Поставил RelativeSource в Binding:

<UserControl x:Class="WpfApplication3.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" 
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">

    <StackPanel>
      <Button ContentTemplate="{Binding ItemTemplate, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}}"></Button>  
    </StackPanel>
</UserControl>


Эффекта нет, не работает.
http://rsdn.ru/Info/rules.xml
Re[8]: ElementName и Source, RelativeSource не эквивалентны
От: igor-booch Россия  
Дата: 29.12.15 13:48
Оценка:
Наш код отличается тем, что Вы указываете источник биндинга для лэйбла в шаблоне, через Source, а не через ElementName, как я:


 <DataTemplate x:Key="dt">
      <Label Content="{Binding Data.Name1, Source={StaticResource vm}}" />
 </DataTemplate>



Поменял свой код, указываю источник биндинга через RelativeSource (у меня ViewModel не используется, у Вас используется):
      <DataTemplate x:Key="template"> 
          <Label Content="{Binding Item.Name1, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}" />
      </DataTemplate>


Тоже работает.

Теперь вопрос:
Почему для кнопки безразлично как указывается источник биндинга внутри шаблона, через ElementName, Source или RelativeSource
а для UserControl'а работает только Source и RelativeSource?
Я думал, что все три способа задания источника биндинга эквивалентны. Это баг WPF либо есть разумное объяснение (чем принципиально отличается кнопка от моего контрола в этом отношении)?
http://rsdn.ru/Info/rules.xml
Re[9]: ElementName и Source, RelativeSource не эквивалентны
От: Peter Fleischer Германия www.informtoools.de
Дата: 29.12.15 14:15
Оценка:
Здравствуйте, igor-booch, Вы писали:
...
IB>Теперь вопрос:
IB>Почему для кнопки безразлично как указывается источник биндинга внутри шаблона, через ElementName, Source или RelativeSource
IB>а для UserControl'а работает только Source и RelativeSource?
IB>Я думал, что все три способа задания источника биндинга эквивалентны. Это баг WPF либо есть разумное объяснение (чем принципиально отличается кнопка от моего контрола в этом отношении)?

UserControl получает свой DataContext на уровне Window, который в данном примере null, и Self обращается к этому нулевому DataContext.
Re[10]: ElementName и Source, RelativeSource не эквивалентны
От: igor-booch Россия  
Дата: 29.12.15 14:33
Оценка:
Здравствуйте, Peter Fleischer, Вы писали:

PF>Здравствуйте, igor-booch, Вы писали:

PF>...
IB>>Теперь вопрос:
IB>>Почему для кнопки безразлично как указывается источник биндинга внутри шаблона, через ElementName, Source или RelativeSource
IB>>а для UserControl'а работает только Source и RelativeSource?
IB>>Я думал, что все три способа задания источника биндинга эквивалентны. Это баг WPF либо есть разумное объяснение (чем принципиально отличается кнопка от моего контрола в этом отношении)?

PF>UserControl получает свой DataContext на уровне Window, который в данном примере null, и Self обращается к этому нулевому DataContext.


RelativeSource Self я полностью убрал из кода. Дело не в этом.
http://rsdn.ru/Info/rules.xml
Re[11]: ElementName и Source, RelativeSource не эквивалентны
От: Peter Fleischer Германия www.informtoools.de
Дата: 29.12.15 19:22
Оценка:
Здравствуйте, igor-booch, Вы писали:
...
IB>RelativeSource Self я полностью убрал из кода. Дело не в этом.

Для пояснения пример:

UserControl без CodeBehind:

<UserControl x:Class="WpfApplication1CS.Window18UC1"
             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:local="clr-namespace:WpfApplication1CS"
             mc:Ignorable="d"
             d:DesignHeight="300" d:DesignWidth="300">
  <StackPanel>
    <Button ContentTemplate="{Binding ItemTemplateVM}"/>
  </StackPanel>
</UserControl>


XAML-Window:

<Window x:Class="WpfApplication1CS.Window18"
        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:WpfApplication1CS"
        mc:Ignorable="d"
        DataContext="{Binding RelativeSource={RelativeSource Self}}"
        Name="window"
        Title="Window18" Height="300" Width="300">
  <Window.Resources>
    <DataTemplate x:Key="dt">
      <Label Content="{Binding Data.Name1, RelativeSource={RelativeSource AncestorType={x:Type Window}}}" />
    </DataTemplate>
  </Window.Resources>
  <StackPanel>
    <local:Window18UC1/>
    <Button ContentTemplate="{StaticResource dt}" Name="btn"/>
  </StackPanel>
</Window>


CodeBehind-Window:

using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows;

namespace WpfApplication1CS
{
  /// <summary>
  /// Interaction logic for Window18.xaml
  /// </summary>
  public partial class Window18 : Window
  {
    public Window18()
    {
      InitializeComponent();
      this._data = new Window18Data() { Name1 = "Текст на кнопке" };
      this.ItemTemplateVM = btn.ContentTemplate;
    }

    private DataTemplate _itemTemplateVM;
    public DataTemplate ItemTemplateVM
    {
      get { return _itemTemplateVM; }
      set
      {
        _itemTemplateVM = value;
        OnPropertyChanged();
      }
    }
    private Window18Data _data;
    public Window18Data Data
    {
      get { return _data; }
      set
      {
        _data = value;
        OnPropertyChanged();
      }
    }
    #region OnPropertyChanged
    public event PropertyChangedEventHandler PropertyChanged;
    private void OnPropertyChanged([CallerMemberName] string propname = "") =>
      PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propname));
    #endregion
  }
  public class Window18Data
  {
    public string Name1 { get; set; }
  }
}
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.