Re[7]: Всё-равно не работает
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 не эквивалентн
Понятно что использовать 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.
[WPF] DataTemplate в своём UserControl'е
Есть
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
Re: [WPF] DataTemplate в своём UserControl'е
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'е
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]: Всё-равно не работает
Сделал, как Вы сказали, не работает.
У меня же ставится 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>
Re[5]: Всё-равно не работает
Re[6]: Всё-равно не работает
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>
Эффекта нет, не работает.
Re[8]: ElementName и Source, RelativeSource не эквивалентны
Наш код отличается тем, что Вы указываете источник биндинга для лэйбла в шаблоне, через 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 либо есть разумное объяснение (чем принципиально отличается кнопка от моего контрола в этом отношении)?
Re[9]: ElementName и Source, RelativeSource не эквивалентны
Здравствуйте, igor-booch, Вы писали:
...
IB>Теперь вопрос:
IB>Почему для кнопки безразлично как указывается источник биндинга внутри шаблона, через ElementName, Source или RelativeSource
IB>а для UserControl'а работает только Source и RelativeSource?
IB>Я думал, что все три способа задания источника биндинга эквивалентны. Это баг WPF либо есть разумное объяснение (чем принципиально отличается кнопка от моего контрола в этом отношении)?
UserControl получает свой DataContext на уровне Window, который в данном примере null, и Self обращается к этому нулевому DataContext.
Re[10]: ElementName и Source, RelativeSource не эквивалентны
Здравствуйте, 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 я полностью убрал из кода. Дело не в этом.
Re[11]: ElementName и Source, RelativeSource не эквивалентны
Здравствуйте, 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 ; }
}
}
Пока на собственное сообщение не было ответов, его можно удалить.
Удалить