DataBinding Problem In ContentTemplate of a TabControl - wpf

I am in a trouble with databinding of the tabControl's Content Template.
I have that class
public class MainWindowViewModel : INotifyPropertyChanged
{
string _text1 = "text1";
string _text2 = "text2";
string _text3 = "text3";
public string Text1
{
get
{
return _text1;
}
set
{
_text1 = value;
}
}
public string Text2
{
get
{
return _text2;
}
set
{
_text2 = value;
}
}
public string Text3
{
get
{
return _text3;
}
set
{
_text3 = value;
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
And I have that xaml :
<Window x:Class="LazyBindingTabControl.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:LazyBindingTabControl"
Title="MainWindow" Height="350" Width="525">
<Grid>
<TabControl Height="299" Margin="0,12,0,0" Name="tabControl1" VerticalAlignment="Top">
<TabItem Header="tabItem1" Name="tabItem1">
<TabItem.ContentTemplate>
<DataTemplate>
<TextBlock Name="Text1" Text="{Binding Path=DataContext.Text1}" />
</DataTemplate>
</TabItem.ContentTemplate>
</TabItem>
<TabItem Header="tabItem2" Name="tabItem2">
<TabItem.ContentTemplate>
<DataTemplate>
<TextBlock Name="Text2" Text="{Binding Path=DataContext.Text2}" />
</DataTemplate>
</TabItem.ContentTemplate>
</TabItem>
<TabItem Header="tabItem3" Name="tabItem3">
<TabItem.ContentTemplate>
<DataTemplate>
<TextBlock Name="Text3" Text="{Binding Path=DataContext.Text3}" />
</DataTemplate>
</TabItem.ContentTemplate>
</TabItem>
</TabControl>
</Grid>
</Window>
And also I set dataContext in code-behinf of mainWindow.xaml
namespace LazyBindingTabControl
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.DataContext = new MainWindowViewModel();
}
}
}
But binding is not successful. How can I successfuly bind Text1, Text2 and Text3 properties properly.
Thanks.

Bind the tabitem content to Text1, Text2, Text3 Properties
then in the TextBlock part, bind the Text like this
Text={Binding}
so the code would be like this
<TabItem Header="tabItem1" Name="tabItem1" Content="{Binding Text1}">
<TabItem.ContentTemplate>
<DataTemplate>
<TextBlock Name="Text1" Text="{Binding}" />
</DataTemplate>
</TabItem.ContentTemplate>
</TabItem>
that should work

I changed your xaml and ViewModel to what it should be to work
ViewModel:
When the property is set the NotifyPropertyChanged must be called. I Added 1 example of a property, do it with all 3
public string Text1
{
get
{
return _text1;
}
set
{
_text1 = value;
NotifyPropertyChanged("Text1");
}
}
xaml:
Change the databinding to:
Text="{Binding Path=Text1}"
After these changes it should work.

Related

How to bind UserControl to ViewModel

I'm having a bit of a trouble connecting both components:
View:
<UserControl x:Class="CoolPlaces.Views.ListItem"
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"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
d:DesignHeight="480" d:DesignWidth="480">
<ListBox ItemsSource="{Binding ListViewModel}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Path=Name, Mode=OneWay}" />
<TextBox Text="{Binding Path=Description, Mode=OneWay}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</UserControl>
Part of Main Page View: in which I include above user control:
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<views:ListItem Height="300" />
</Grid>
ViewModel:
namespace CoolPlaces.ViewModels
{
public class ListViewModel : INotifyPropertyChanged
{
private ObservableCollection<BasicModel> _places;
public ObservableCollection<BasicModel> Places {
get {
return _places;
}
set {
_places = value;
RaisePropertyChanged("Places");
}
}
public ListViewModel() {
Places = new ObservableCollection<BasicModel>(_loadPlaces());
}
private IEnumerable<BasicModel> _loadPlaces() {
return //some hard coded objects
}
}
}
MainPage
namespace CoolPlaces
{
public partial class MainPage : PhoneApplicationPage
{
private ListViewModel vm;
// Constructor
public MainPage()
{
InitializeComponent();
vm = new ListViewModel();
}
}
}
You're close. You need to set the DataContext equal to your ViewModel.
public partial class MainPage : PhoneApplicationPage
{
private ListViewModel vm;
// Constructor
public MainPage()
{
InitializeComponent();
DataContext = vm = new ListViewModel();
}
}
Then your ListBox doesn't need to be bound to it. Instead, bind it to your Places property on your ViewModel:
<ListBox ItemsSource="{Binding Places}">

How to bind TextBoxes to an ObservableCollection in an ItemsControl with UniformGrid

If in WPF I have this code:
using System.Collections.ObjectModel;
...
...
public partial class MainWindow : Window
{
public ObservableCollection<String> myMatrixData = new ObservableCollection<String>();
public MainWindow()
{
InitializeComponent();
int i;
for (i = 0; i < 100; i++)
myMatrixData.Add("Test");
myMatrix.ItemsSource = myMatrixData;
}
private void Button_Click_1(object sender, RoutedEventArgs e)
{
Cell00.Text = myMatrixData[0];
}
}
XAML:
xmlns:sys="clr-namespace:System;assembly=mscorlib"
...
...
<Grid>
<StackPanel>
<ItemsControl x:Name="myMatrix">
<ItemsControl.Resources>
</ItemsControl.Resources>
<ItemsControl.ItemsPanel>
<!-- specify the panel that is the container for the items -->
<ItemsPanelTemplate>
<UniformGrid Rows="10" Columns="10" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<!-- specify the template used to render each item -->
<ItemsControl.ItemTemplate>
<DataTemplate DataType="{x:Type sys:String[]}">
<TextBox Text="{Binding Path=., UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<Button Content="Read cell 0/0" Click="Button_Click_1"/>
<TextBlock x:Name="Cell00"/>
</StackPanel>
</Grid>
I just want to reflect the elements in the ObservableCollection myMatrixData to be reflected in a UniformGrid-style ItemsControl named myMatrix. Changing the text in the first cell and pressing the button reveals that this doesn't work.
What am I missing?
ObservableCollection<string> does not update changes to the string because string itself does not implement INotifypropertyChanged
try createing a simple model for your collection
Example:
private ObservableCollection<Matrix> _myMatrix = new ObservableCollection<Matrix>();
public MainWindow()
{
InitializeComponent();
this.DataContext = this;
for (int i = 0; i < 100; i++)
{
MyMatrix.Add(new Matrix { Value = "Test" + i });
}
}
public ObservableCollection<Matrix> MyMatrix
{
get { return _myMatrix; }
set { _myMatrix = value; }
}
.......
public class Matrix : INotifyPropertyChanged
{
private string _value;
public string Value
{
get { return _value; }
set { _value = value; NotifyPropertyChanged("Value"); }
}
public event PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChanged(string property)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(property));
}
}
}
Xaml:
<Window x:Class="WpfApplication9.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication9"
Title="MainWindow" Height="350" Width="525" Name="UI">
<StackPanel>
<ItemsControl x:Name="myMatrix" ItemsSource="{Binding MyMatrix}" >
<ItemsControl.ItemsPanel>
<!-- specify the panel that is the container for the items -->
<ItemsPanelTemplate>
<UniformGrid Rows="10" Columns="10" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<!-- specify the template used to render each item -->
<ItemsControl.ItemTemplate>
<DataTemplate DataType="{x:Type local:Matrix}">
<TextBox Text="{Binding Path=Value, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<Button Content="Read cell 0/0" Click="Button_Click_1" />
<TextBlock x:Name="Cell00" />
</StackPanel>
</Window>
I found this pretty useful with making the binding work with NotifyPropertyChanged and also commands
wpf-mvvm-inotifypropertychanged
Implementing the MVVM Pattern
WPF/MVVM Quick Start Tutorial --- Super Handy This One

Error Template Design

It seems like I read another question / answer on this site about this issue but I cannot recall what the answer was and now I cannot find the original post.
I am not a fan of the default error template in WPF. I understand how to change this error template. However, if I add some content to the end of, say, a textbox, the size of the textbox does not change and the added content will (potentially) get clipped. How do I alter the textbox (I believe the correct termonology is adorned element) in this scenario so that nothing gets clipped?
Here is the XAML for the error template:
<Style TargetType="{x:Type TextBox}">
<Setter Property="Validation.ErrorTemplate">
<Setter.Value>
<ControlTemplate>
<StackPanel>
<AdornedElementPlaceholder />
<TextBlock Foreground="Red" Text="Error..." />
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Here is the XAML for a couple of textboxes in the form:
<StackPanel>
<TextBox Text="{Binding...}" />
<TextBox />
</StackPanel>
Here's a solution adapted from Josh Smith's article on Binding to (Validation.Errors)[0] without Creating Debug Spew.
The trick is to define a DataTemplate to render the ValidationError object and then use a ContentPresenterto display the error message. If there is no error, then the ContentPresenter will not be displayed.
Below, I have shared the code of the sample app that I created.
Here is the XAML:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
SizeToContent="WidthAndHeight"
Title="MainWindow">
<StackPanel Margin="5">
<StackPanel.Resources>
<DataTemplate DataType="{x:Type ValidationError}">
<TextBlock Text="{Binding ErrorContent}" Foreground="White" Background="Red" VerticalAlignment="Center" FontWeight="Bold"/>
</DataTemplate>
</StackPanel.Resources>
<TextBox Name="TextBox1" Text="{Binding Text1, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}"/>
<ContentPresenter Content="{Binding ElementName= TextBox1, Path=(Validation.Errors).CurrentItem}" HorizontalAlignment="Left"/>
<TextBox Name="TextBox2" Text="{Binding Text2, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}"/>
<ContentPresenter Content="{Binding ElementName= TextBox2, Path=(Validation.Errors).CurrentItem}" HorizontalAlignment="Left"/>
<Button Content="Validate" Click="Button_Click"/>
</StackPanel>
</Window>
The code behind file:
namespace WpfApplication1
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private ViewModel _ViewModel = null;
public MainWindow()
{
InitializeComponent();
_ViewModel = new ViewModel();
DataContext = _ViewModel;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
_ViewModel.Validate = true;
_ViewModel.OnPropertyChanged("Text1");
_ViewModel.OnPropertyChanged("Text2");
}
}
}
The ViewModel:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
namespace WpfApplication1
{
public class ViewModel : INotifyPropertyChanged, IDataErrorInfo
{
private string _Text1;
public string Text1
{
get { return _Text1; }
set
{
_Text1 = value;
OnPropertyChanged("Text1");
}
}
private string _Text2;
public string Text2
{
get { return _Text2; }
set
{
_Text2 = value;
OnPropertyChanged("Text2");
}
}
public bool Validate { get; set; }
#region INotifyPropertyChanged Implemenation
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
#region IDataErrorInfo Implementation
public string Error
{
get { return null; }
}
public string this[string columnName]
{
get
{
string errorMessage = string.Empty;
if (Validate)
{
switch (columnName)
{
case "Text1":
if (Text1 == null)
errorMessage = "Text1 is mandatory.";
else if (Text1.Trim() == string.Empty)
errorMessage = "Text1 is not valid.";
break;
case "Text2":
if (Text2 == null)
errorMessage = "Text2 is mandatory.";
else if (Text2.Trim() == string.Empty)
errorMessage = "Text2 is not valid.";
break;
}
}
return errorMessage;
}
}
#endregion
}
}

How to tie a some controls on one view model

I have a view model with some fields, i.e.
type ViewModel =
member x.a = [1;2;3]
member x.b = [4;5;6]
member x.c = [7]
and in WPF application places some views, as:
<Control.Resources>
<DataTemplate x:Key="ItemTempl">
<TextBlock Text="{Binding}" />
</DataTemplate>
<DataTemplate x:Key="SomeTempl">
<ListBox ItemsSource="{Binding}"
ItemTemplate="{StaticResource ItemTempl}" />
</DataTemplate>
</Control.Resources>
<StackPanel>
<TabControl x:Name="ListBoxViewPresenter">
<TabItem Header="vm.a" Content="{Binding vm.a}"
ContentTemplate="{StaticResource SomeTempl}"/>
<TabItem Header="vm.b" Content="{Binding vm.b}"
ContentTemplate="{StaticResource SomeTempl}"/>
<TabItem Header="vm.c" Content="{Binding vm.c}"
ContentTemplate="{StaticResource SomeTempl}"/>
</TabControl>
<ListBox x:Name="ListBoxViewPresenter">
<ListBoxItem Content="{Binding vm.a}"
ContentTemplate="{StaticResource SomeTempl}" />
<ListBoxItem Content="{Binding vm.b}"
ContentTemplate="{StaticResource SomeTempl}" />
<ListBoxItem Content="{Binding vm.c}"
ContentTemplate="{StaticResource SomeTempl}" />
</ListBox>
</StackPanel>
What should I do to achieve such behavior:
when you clicked on some element in vm.a/b/c in ListBoxViewPresenter so same element in ListBoxViewPresenter is must selected in corresponding TabItem.
UPD:
Specifically my real problem, changing from origin topic.
I have ViewModel with fields: onelines, twolines... and a field with name selected_scheme.
In xaml:
<TreeViewItem Header="{Binding Path=name}" x:Name="ProjectArea">
<TreeViewItem Header="Однониточные планы" Style="{StaticResource MyTreeViewItem}">
<ContentPresenter Content="{Binding onelines}" ContentTemplate="{StaticResource SchemeWrapperTemplate}" />
</TreeViewItem>
<TreeViewItem Header="Двухниточные планы" Style="{StaticResource MyTreeViewItem}">
<ContentPresenter Content="{Binding twolines}" ContentTemplate="{StaticResource SchemeWrapperTemplate}" />
</TreeViewItem>
And data template:
<DataTemplate x:Key="SchemeWrapperTemplate">
<ListBox ItemsSource="{Binding schemes}"
ItemTemplate="{StaticResource SchemeTemplate}"
SelectedItem="{Binding selected_scheme}">
<ListBox.Style>
In other place of the program:
<Grid Grid.Row="1">
<TextBlock Text="{Binding selected_scheme.path}" />
</Grid>
And when you click on some ListBoxes then selected item not changing if you click on a yet SelectedItems.
First of all you should define the ItemsSource of your TabItem and ListBox in the ViewModel they are bound too.
Then you can bind their SelectedItem to a property in your ViewModel.
Here is a code sample (I was too lazy to create a seperate ViewModel class, hence it is mixed with my main window class, but you get the idea...) :
Codebehind :
namespace WpfApplication13
{
public partial class MainWindow : Window, INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private object _currentlySelectedItem;
public object CurrentlySelectedItem
{
get { return _currentlySelectedItem; }
set
{
_currentlySelectedItem = value;
if (this.PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs("CurrentlySelectedItem"));
}
}
}
public class MyClass
{
public string MyString { get; set; }
public MyClass(string myString)
{
this.MyString = myString;
}
}
private List<MyClass> _myItemsSource = new List<MyClass>
{
new MyClass("toto"),
new MyClass("tata")
};
public List<MyClass> MyItemsSource
{
get { return _myItemsSource; }
set { _myItemsSource = value; }
}
public object A
{
get { return "toto"; }
}
public object B
{
get { return "tata"; }
}
public MainWindow()
{
InitializeComponent();
this.DataContext = this;
}
}
}
xaml :
<Window x:Class="WpfApplication13.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">
<Grid>
<StackPanel>
<TabControl x:Name="ListBoxViewPresenter"
SelectedItem="{Binding CurrentlySelectedItem}"
ItemsSource="{Binding MyItemsSource}" />
<ListBox x:Name="ListBoxViewPresenter2"
SelectedItem="{Binding CurrentlySelectedItem}"
ItemsSource="{Binding MyItemsSource}" />
</StackPanel>
</Grid>
</Window>
New answer after you edited :
It does not make much sense to bind the same object to the SelectedItem property of two different lists that contain different elements. You have to redesign your application or you may be confronted to many problems due to this strange design in the futur.
Still, you can achieve want you want to do with a little codebehing. When the user clicks on one of your ListBox, you set the selected item of your other listbox to null. Then you will be notified when you re-click on the first listbox since the selection goes from null to something.
xaml:
<Window x:Class="WpfApplication13.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">
<Grid>
<StackPanel>
<ListBox x:Name="ListBoxViewPresenter"
SelectedItem="{Binding CurrentlySelectedItem}"
ItemsSource="{Binding MyItemsSource}" />
<ListBox x:Name="ListBoxViewPresenter2"
SelectedItem="{Binding CurrentlySelectedItem}"
ItemsSource="{Binding MyItemsSource2}" />
</StackPanel>
</Grid>
</Window>
codebehind:
using System.Collections.Generic;
using System.Windows;
using System.Windows.Input;
using System.ComponentModel;
namespace WpfApplication13
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window, INotifyPropertyChanged
{
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
#endregion
private object _currentlySelectedItem;
public object CurrentlySelectedItem
{
get { return _currentlySelectedItem; }
set
{
_currentlySelectedItem = value;
if (this.PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs("CurrentlySelectedItem"));
}
}
}
private List<int> _myItemsSource = new List<int> { 1, 2 };
private List<int> _myItemsSource2 = new List<int> { 3, 4 };
public List<int> MyItemsSource
{
get { return _myItemsSource; }
set { _myItemsSource = value; }
}
public List<int> MyItemsSource2
{
get { return _myItemsSource2; }
set { _myItemsSource2 = value; }
}
public MainWindow()
{
InitializeComponent();
this.DataContext = this;
ListBoxViewPresenter.PreviewMouseDown += ListBoxViewPresenter_PreviewMouseDown;
ListBoxViewPresenter2.PreviewMouseDown += ListBoxViewPresenter2_PreviewMouseDown;
}
void ListBoxViewPresenter_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
ListBoxViewPresenter2.SelectedItem = null;
}
void ListBoxViewPresenter2_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
ListBoxViewPresenter.SelectedItem = null;
}
}
}

Data Binding : Child accessing AncestorType property

Bellow is the code behind and the Xaml for a demo app to review databing and wpf.
The problem is binding Store.ImagePath property to the person node is not working. That is the image is not showing.
<Image Source="{Binding Path=Store.ImagePath, RelativeSource={RelativeSource AncestorType={x:Type local:Store}}}" />
Here is the code-behind
namespace TreeViewDemo
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
Customers customers = new Customers();
customers.Users = new List<Person>
{
new Person { Name = "John"},
new Person { Name = "Adam"},
new Person { Name = "Smith"}
};
Store store = new Store();
store.AllCustomers.Add(customers);
this.DataContext = store;
}
}
public class Store : INotifyPropertyChanged
{
string imagePath = "imageone.png";
public Store()
{
AllCustomers = new ObservableCollection<Customers>();
}
public string StoreName
{
get
{
return "ABC Store";
}
}
public ObservableCollection<Customers> AllCustomers
{
get;
set;
}
public string ImagePath
{
get
{
return imagePath;
}
set
{
if (value == imagePath) return;
imagePath = value;
this.OnPropertyChanged("ImagePath");
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
if (this.PropertyChanged != null)
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public class Customers
{
public string Label
{
get
{
return string.Format("People({0})", Users.Count());
}
}
public List<Person> Users
{
get;
set;
}
}
public class Person : INotifyPropertyChanged
{
public string Name
{
get;
set;
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
if (this.PropertyChanged != null)
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
and here is the Xaml.
<Window x:Class="TreeViewDemo.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:TreeViewDemo"
Title="MainWindow" Height="350" Width="525">
<Window.Resources >
<DataTemplate DataType="{x:Type local:Person}" x:Key="personKey" >
<StackPanel Orientation="Horizontal" >
<Image Source="{Binding Path=Store.ImagePath, RelativeSource={RelativeSource AncestorType={x:Type local:Store}}}" />
<TextBlock Text="{Binding Name}" />
</StackPanel>
</DataTemplate>
<HierarchicalDataTemplate x:Key="customerKey" ItemsSource="{Binding Users}" ItemTemplate="{StaticResource personKey }" >
<TextBlock Text="{Binding Label}" FontWeight="Bold"/>
</HierarchicalDataTemplate>
</Window.Resources>
<Grid>
<Canvas>
<Button HorizontalAlignment="Left" DockPanel.Dock="Top" Height="29" Width="112" Canvas.Left="123" Canvas.Top="5">Image one</Button> <Button HorizontalAlignment="Left" VerticalAlignment="Top" DockPanel.Dock="Top" Height="28" Width="119" Canvas.Left="249" Canvas.Top="7">Image two</Button>
<TreeView HorizontalAlignment="Stretch" Name="treeView1" VerticalAlignment="Stretch"
ItemsSource="{Binding .}" Height="260" Width="363" Canvas.Left="81" Canvas.Top="45">
<TreeViewItem ItemsSource="{Binding AllCustomers}" ItemTemplate="{StaticResource customerKey}" Header="{Binding StoreName}"></TreeViewItem>
</TreeView>
</Canvas>
</Grid>
</Window>
All files are in the same directory.
Thanks
A relative source is used to look up an object in the visual tree. You're asking it to find the nearest Store in the visual tree. Since a Store cannot even be in the visual tree, the lookup will fail and yield null. What you actually want is the DataContext of the root Window, since that is where your Store is held:
<Image Source="{Binding DataContext.ImagePath, RelativeSource={RelativeSource AncestorType={x:Type Window}}}" />

Resources