How to bind a property in the view model of a usercontrol to a property in another usercontrol - c#

I am currently working within a WPF user control using MVVM. My MainWindow.xaml looks like below.
MainWindow.xaml
<Window.Resources>
<ObjectDataProvider x:Key="TabsList" ObjectType="{x:Type local:MainWindowModel}" MethodName="GetTabs"/>
</Window.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<ListBox Grid.Column="0" ItemsSource="{Binding Source={StaticResource TabsList}}" IsSynchronizedWithCurrentItem="True">
<ListBox.ItemTemplate>
<DataTemplate>
<Label Content="{Binding Path=TabName}" Margin="10"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<ContentControl Grid.Column="1" Content="{Binding Source={StaticResource TabsList}, Path=MyUserControl}"/>
</Grid>
Data provider class is as below
public class MainWindowModel
{
public List<TabInfo> GetTabs()
{
return new List<TabInfo>()
{
new TabInfo() { TabName="Tab1", MyUserControl = new UserControl1()},
new TabInfo() { TabName="Tab2", MyUserControl = new UserControl2()}
};
}
}
public class TabInfo
{
public string TabName { get; set; }
public UserControl MyUserControl { get; set; }
}
And now I have two usercontrols UserControl1 and UserControl2 each has a text box control. I would like to update the Text property of the textbox control in the UserControl1 whenever the Text property of the Textbox control in the UserControl2 is updated. To do this, I tried as below.
UserControl1
<UserControl x:Class="MoreOnBinding2.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">
<Grid>
<TextBox Width="200" Height="20" Text="{Binding Path=UserControl1Text}"/>
</Grid>
UserControl1ViewModel
public class UserControl1VM : ViewModelBase
{
public UserControl1VM()
{
this.UserControl1Text = "10";
}
private string userControl1Text;
public string UserControl1Text
{
get { return userControl1Text; }
set
{
if (userControl1Text != value)
{
userControl1Text = value;
RaisePropertyChanged(() => UserControl1Text);
}
}
}
}
UserControl2
<UserControl x:Class="MoreOnBinding2.UserControl2"
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:MoreOnBinding2"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<TextBox Width="200" Height="20"
Text="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type local:UserControl1}},
UpdateSourceTrigger=PropertyChanged, Path=UserControl1Text}" />
</Grid>
But it is not working. It seems there is a problem in the RelativeSource tag in the UserControl2. Can someone help on this.

You could use a Dependency Property on your user controls this would give you a bind able property. see link
EDIT 1
Just had another look at your class setup. If you are following the MVVM approach I don't think you should have a reference to your user control in your view model
View Model should be more Like
public Class
{
ObservableCollection<TabInfo> _Tabs = new ObservableCollection<TabInfo>();
public ObservableCollection<TabInfo> Tabs
{
get{return _Tabs;}
set {_Tabs = value;}//Need to implement INotifyPropertyChanged [Link][2]
}
public TabInfo SelectedTab {get;set;}
}
public class TabInfo
{
public string TabName { get; set; }
public UserControlViewModel MyUserControlViewModel{ get; set; }
}
Then in your View
<Window.DataContext>
<vm:MainWindowModel />
</Window.DataContext>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<ListBox Grid.Column="0" ItemsSource="{Binding Tabs}" IsSynchronizedWithCurrentItem="True" SelectedValue="{Binding SelectedTab}">
<ListBox.ItemTemplate>
<DataTemplate>
<Label Content="{Binding Path=TabName}" Margin="10"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<ContentControl Grid.Column="1" Content="{Binding SelectedTab.MyUserControlViewModel"/>
</Grid>
This should give you a list of Tabs and then when one is selected it will set the content of the ContentControl to the MyUserControlViewModel.
You would then need to use some sort of template selector to control the ContentTemplate to load different UserControls into the ContentControl
I haven't tested the code works and you would need to implement the INotifyPropertyChanged on all the public properties so the bindings update as the properties value is changed.
Hope that helps a bit.

Related

In WPF MVVM, i have a usercontrol with a check box, how do i connect a command to the viewmodel

I am still new to WPF and MVVM and am trying to keep the seperation between View and View Model.
i have an app, essentially a projects task list app, in this i create projects and within each project i can create a set of tasks. Most is working well, but essentially i cannot get a command binding on a checkbox in a user control to work using DP, inherited datacontext etc. i always ge a binding failed error when running the app. i am trying to bing to a command in the viewmodel of the view which contains the user controls.
i created a user control to pull the task data together in the view, the command is on the checkbox
<UserControl x:Class="TaskProjectApp.Controls.TaskControl"
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:TaskProjectApp.Controls"
mc:Ignorable="d"
d:DesignHeight="100" d:DesignWidth="300">
<Grid Background="LightBlue">
<StackPanel Margin="5,5,5,5">
<TextBlock x:Name="titleTB"
Text="title"
FontSize="20"
FontWeight="Bold"/>
<TextBlock x:Name="DescriptionTB"
Text="description.."
FontSize="15"
Foreground="DodgerBlue"/>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="auto"/>
</Grid.ColumnDefinitions>
<TextBlock x:Name="priority"
Text="0"
FontSize="15"
FontStyle="Italic"/>
<CheckBox Grid.Column="1"
x:Name="iscomplete"
Command="{Binding SetComplete}"/>
</Grid>
</StackPanel>
</Grid>
</UserControl>
in the user control code behind i have set the DP and the set text function is working
namespace TaskProjectApp.Controls
{
/// <summary>
/// Interaction logic for TaskControl.xaml
/// </summary>
public partial class TaskControl : UserControl
{
public UserTask Task
{
get { return (UserTask)GetValue(TaskProperty); }
set { SetValue(TaskProperty, value); }
}
// Using a DependencyProperty as the backing store for Task. This enables animation, styling, binding, etc...
public static readonly DependencyProperty TaskProperty =
DependencyProperty.Register("Task", typeof(UserTask), typeof(TaskControl), new PropertyMetadata(new UserTask()
{
Title = "title",
Description = "none",
Comments = "none"
}, SetText));
private static void SetText(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
TaskControl task = d as TaskControl;
if (task != null)
{
task.titleTB.Text = (e.NewValue as UserTask).Title;
task.DescriptionTB.Text = (e.NewValue as UserTask).Description;
task.priority.Text = (e.NewValue as UserTask).Priority.ToString();
task.iscomplete.IsChecked = (e.NewValue as UserTask).IsComplete;
}
}
public TaskControl()
{
InitializeComponent();
}
}
}
now to make this work i set the binding of the user control in the window as so, the listview takes the usercontrols and implements the observable collection of tasks.
<Window x:Class="TaskProjectApp.Views.ProjectsView"
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:TaskProjectApp.Views"
xmlns:uc="clr-namespace:TaskProjectApp.Controls"
mc:Ignorable="d"
Title="ProjectsView" Height="450" Width="800">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<uc:ProjectControl Project="{Binding UserProject}" />
<StackPanel Grid.Row="1">
<TextBlock Text="Task List"/>
<ListView ItemsSource="{Binding Tasks}"
SelectedItem="{Binding SelectedTask}">
<ListView.ItemTemplate>
<DataTemplate>
<uc:TaskControl Task="{Binding}"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<Button Content="Add Task"
Command="{Binding NewProjectTask}"/>
<Button Content="Delete Task"
Command="{Binding DeleteProjectTask}"/>
</StackPanel>
</Grid>
</Window>
this seems to completely stop me using the command, i set the datacontext in the code behind, to the whole window
public partial class ProjectsView : Window
{
public ProjectViewModel ProjectViewModel { get; set; }
public ProjectsView()
{
InitializeComponent();
}
public ProjectsView(UserProject userProject)
{
InitializeComponent();
ProjectViewModel = new ProjectViewModel(userProject);
DataContext = ProjectViewModel;
}
}
and reading trying to solve this has shown that the usercontrol should inherit the datacontext of the parent window.
i have seen solutions using relative paths and DPs for the commands as well as people saying these are not needed just let the inherited datacontext handle it.
but i have tried all three an neither works.
the interface shows me a message box saying no datacontext found, although i notice this is the case when you set the datacontext in code behind and not the xaml.
the SetCommand is created in the projects view model and its a property not a field as i have seen this fail for that reason too.
namespace TaskProjectApp.ViewModels
{
public class ProjectViewModel
{
public UserProject UserProject { get; set; }
public ProjectViewModel(UserProject userProject)
{
UserProject = userProject;
Tasks = new ObservableCollection<UserTask>();
NewProjectTask = new NewProjectTaskCommand(this);
DeleteProjectTask = new DeleteProjectTaskCommand(this);
SetComplete = new SetCompleteCommand();
ReadTaskDatabase();
}
public ObservableCollection<UserTask> Tasks { get; set; }
public NewProjectTaskCommand NewProjectTask { get; set; }
public DeleteProjectTaskCommand DeleteProjectTask { get; set; }
public SetCompleteCommand SetComplete { get; set; }
public UserTask SelectedTask { get; set; }
public void ReadTaskDatabase()
{
List<UserTask> list = new List<UserTask>();
using (SQLiteConnection newConnection = new SQLiteConnection(App.databasePath))
{
newConnection.CreateTable<UserTask>();
list = newConnection.Table<UserTask>().ToList().OrderBy(c => c.Title).ToList();
}
Tasks.Clear();
foreach (UserTask ut in list)
{
if (ut.ProjectId == UserProject.Id)
{
Tasks.Add(ut);
}
}
}
}
}
if anyone can point out where i am going wrong tat will be great as i fear i am now not seeing the wood for the trees.
I found the solution thanks to Ash link Binding to Window.DataContext.ViewModelCommand inside a ItemsControl not sure how i missed it, maybe wrong key words. anyway because the datacontext of the usercontrol is being made into my data class in the observable list Tasks
<StackPanel Grid.Row="1">
<TextBlock Text="Task List"/>
<ListView ItemsSource="{Binding Tasks}"
SelectedItem="{Binding SelectedTask}">
<ListView.ItemTemplate>
<DataTemplate>
<uc:TaskControl Task="{Binding}"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<Button Content="Add Task"
Command="{Binding NewProjectTask}"/>
<Button Content="Delete Task"
Command="{Binding DeleteProjectTask}"/>
</StackPanel>
you need to use a relative path inside the user control to look up past the ItemTemplate to the ListView itself as this uses the viewmodel data context to bind to, so has access to the right level
<UserControl x:Class="TaskProjectApp.Controls.TaskControl"
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:TaskProjectApp.Controls"
mc:Ignorable="d"
d:DesignHeight="100" d:DesignWidth="300">
<Grid Background="LightBlue">
<StackPanel Margin="5,5,5,5">
<TextBlock x:Name="titleTB"
Text="title"
FontSize="20"
FontWeight="Bold"/>
<TextBlock x:Name="DescriptionTB"
Text="description.."
FontSize="15"
Foreground="DodgerBlue"/>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="auto"/>
</Grid.ColumnDefinitions>
<TextBlock x:Name="priority"
Text="0"
FontSize="15"
FontStyle="Italic"/>
<CheckBox Grid.Column="1"
x:Name="iscomplete"
Command="{Binding DataContext.SetComplete, RelativeSource={RelativeSource AncestorType=ListView}}"/>
</Grid>
</StackPanel>
</Grid>
</UserControl>
this might be limiting in future as it measn the usercontrol will look for a listview to bind the command, but it solves the immediate issue.

WPF - Command in datacontext of the window and commandparameter from listview in user control

I am having a little trouble getting the bindings of a command working in my WPF-application, following the MVVM pattern.
What I currently have:
MainWindow with DataContext MainWindowViewModel.
SecondPage (user control) with DataContext SecondPageViewmodel.
The user control only simply contains a listview called StudentListView binding to an observable collection in SecondPageViewModel.
The main window has a textbox where pressing the enter key will trigger my command, called ReturnPressCommand which is located in the MainWindowViewModel. The main window also contains an instance of the SecondPage user control.
What I would like to do is be able to use the StudentListView from the user control as my command parameter for the command ReturnPressCommand in my Main window.
How do I accomplish this?
The main window:
<Window x:Class="MVVMTEST.Views.MainWindow"
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:MVVMTEST.ViewModels"
xmlns:control="clr-namespace:MVVMTEST.Views"
mc:Ignorable="d"
Title="MainWindow" Height="800" Width="1600" WindowStartupLocation="CenterScreen">
<Window.DataContext>
<local:MainWindowViewModel />
</Window.DataContext>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<TextBox Grid.Column="0" Grid.Row="0" Width="120" Height="20">
<TextBox.InputBindings>
<KeyBinding Key="Return"
Command="{Binding Path=ReturnPressCommand}"
CommandParameter="{}"/>
</TextBox.InputBindings>
</TextBox>
<control:SecondPage x:Name="SecondPageX" Grid.Column="0" Grid.Row="0" Grid.ColumnSpan="2" Width="auto" Visibility="Visible"></control:SecondPage>
</Grid>
</Window>
The viewmodel for the main window
using MVVMTEST.Commands;
using System.Windows.Input;
namespace MVVMTEST.ViewModels
{
class MainWindowViewModel
{
public MainWindowViewModel()
{
}
private ICommand _returnPressCommand = null;
public ICommand ReturnPressCommand
{
get
{
if (_returnPressCommand == null)
_returnPressCommand = new ReturnPressCommand();
return _returnPressCommand;
}
}
}
}
The command I want to execute
namespace MVVMTEST.Commands
{
class ReturnPressCommand : CommandBase
{
public override bool CanExecute(object parameter)
{
return true;
}
public override void Execute(object parameter)
{
// Do operations with the observable collection
}
}
}
The user control
<UserControl x:Class="MVVMTEST.Views.SecondPage"
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:MVVMTEST.ViewModels"
mc:Ignorable="d"
d:DesignHeight="400" d:DesignWidth="1600">
<UserControl.DataContext>
<local:SecondPageViewModel />
</UserControl.DataContext>
<Grid Background="Green">
<ListView Grid.Column="0" Grid.Row="0" x:Name="StudentListView" ItemsSource="{Binding Students}">
<ListView.View>
<GridView>
<GridViewColumn DisplayMemberBinding="{Binding Name}" Header="Name"></GridViewColumn>
<GridViewColumn DisplayMemberBinding="{Binding Age}" Header="Age"></GridViewColumn>
<GridViewColumn DisplayMemberBinding="{Binding Gpa}" Header="Gpa"></GridViewColumn>
</GridView>
</ListView.View>
</ListView>
</Grid>
</UserControl>
The viewmodel for the user control
using System.Collections.Generic;
using System.Collections.ObjectModel;
using MVVMTEST.Models;
namespace MVVMTEST.ViewModels
{
public class SecondPageViewModel
{
public IList<Student> Students { get; } = new ObservableCollection<Student>();
public SecondPageViewModel()
{
Students.Add(new Student { Name = "Firstname Lastname", Age = 25, Gpa = 0.0 });
}
}
}
I want the textbox to be visible at all times, however in the future I am planning on adding more user controls and their visibility will change depending on what the user is doing in the application. Right now I want to implement a search feature to filter the students in the observable collection located in the viewmodel for the user control. The user control will then list these filtered students.
You can bind the CommandParameter to the collection via the name of the usercontrol.
<TextBox Grid.Column="0" Grid.Row="0" Width="120" Height="20">
<TextBox.InputBindings>
<KeyBinding Key="Return"
Command="{Binding Path=ReturnPressCommand}"
CommandParameter="{Binding DataContext.Students, ElementName=SecondPageX}" />
</TextBox.InputBindings>
</TextBox>

Add/Remove Tabs with User Control Dynamically in WPF - Binding Tab Name

I would to create application with TabControl.
I would to put UserControls on Tabs, but I wouldn't create this in *.cs file, but using binding.
I have application where I can add tab with usercontrol, but i don't know how bind String with tab name.
My code:
MainWindow.xaml.cs
using System.Windows;
namespace WpfApp3
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
}
}
MainWindow.xaml
<Window x:Class="WpfApp3.MainWindow"
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:WpfApp3"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.DataContext>
<local:MainWindowViewModel/>
</Window.DataContext>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TabControl ItemsSource="{Binding UserControls}">
<TabControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="???" /> <!--binding? -->
</DataTemplate>
</TabControl.ItemTemplate>
</TabControl>
<Button Grid.Row="1" Content="Dodaj zakładkę" Command="{Binding AddButtonCommand}"/>
</Grid>
</Window>
MainWindowViewModel.cs
using Prism.Commands;
using Prism.Mvvm;
using System.Collections.ObjectModel;
using System.Windows.Controls;
using System.Windows.Input;
namespace WpfApp3
{
class MainWindowViewModel : BindableBase
{
public ObservableCollection<UserControl> UserControls { get; set; }
public ICommand AddButtonCommand { get; set; }
public MainWindowViewModel()
{
AddButtonCommand = new DelegateCommand(ClickButton);
UserControls = new ObservableCollection<UserControl>();
}
private void ClickButton()
{
UserControls.Add(new UCTest());
RaisePropertyChanged("UserControls");
}
}
}
I tried add constructor UserControl with parameter with name, but i don't know how join it with binding.
My second thing is create class with UserControl and String (with tab name), but i couldnt bind field with UserControl to Widdow.
Thanks,
regards.
You shouldn't add UserControls or any other UI elements to the ObservableCollection in the view model. Instead you should define your own model type and add instances of this one to the source collection.
You could then bind to any property of this class:
class Model
{
public string Header { get; set; }
}
class MainViewModel : BindableBase
{
public ObservableCollection<Model> UserControls { get; set; }
public ICommand AddButtonCommand { get; set; }
public Window13ViewModel()
{
AddButtonCommand = new DelegateCommand(ClickButton);
UserControls = new ObservableCollection<Model>();
}
private void ClickButton()
{
UserControls.Add(new Model() { Header = "some name..." });
}
}
XAML:
<TabControl ItemsSource="{Binding UserControls}">
<TabControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Header}" />
</DataTemplate>
</TabControl.ItemTemplate>
<TabControl.ContentTemplate>
<DataTemplate>
<local:UCTest />
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>

Filling a ListBox with an ObservableCollection and display properties of selected items in StackPanel

I'm tring to databind properties of an ObservableCollection to a ListBox (Just the Title property for example).
By clicking on one of the ListItem (with an event ), i'd like to display all the properties of the Collection into a StackPanel. After many tries, I still don't know how can I figure it out...
Here is my code behind :
public partial class TestListView : Window
{
public TestListView()
{
ObservableCollection<Programme> pgr = new ObservableCollection<Programme>();
pgr = readfile();
InitializeComponent();
}
public class Programme
{
public String Title { get; set; }
public String Date { get; set; }
public String Chaine { get; set; }
public Programme(String Title, String Date, String Chaine)
{
this.Title = Title;
this.Date = Date;
this.Chaine = Chaine;
}
}
Here is my XAML :
<Window x:Class="Test.TestListView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Test;assembly=Test"
Title="TestListView" Height="500" Width="1000" x:Name="Window">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="249*"/>
<ColumnDefinition Width="743*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="20*"/>
<RowDefinition Height="428*"/>
<RowDefinition Height="21*"/>
</Grid.RowDefinitions>
<ListBox Name="l1" ItemsSource="{Binding pgr}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Title}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<StackPanel Grid.Column="1" Grid.Row="1">
<TextBox Margin="343,0,0,0" x:Name="Recherche"></TextBox>
<Button Height="37" Margin="669,0,0,0" ></Button>
<TextBlock x:Name="t1" Margin="214,0,293,0" Height="33" />
</StackPanel>
</Grid>
</Window>
You need to bind your data to (public) properties. Also, you don't need to use ObservableCollection; any selection changes will be picked up anyhow.
Here's a working sample, with layout and other bits and pieces changed to make it compile for me:
public partial class MainWindow
{
public IList<Programme> pgr { get; }
public MainWindow()
{
pgr = new List<Programme>
{
new Programme("First", "FirstDate", "FirstChaine"),
new Programme("Second", "SecondDate", "SecondChaine"),
new Programme("Third", "ThirdDate", "ThirdChaine"),
};
InitializeComponent();
}
public class Programme
{
// No changes
}
}
...and the XAML:
<Window
x:Name="self"
x:Class="WpfApplication1.MainWindow"
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:WpfApplication1"
mc:Ignorable="d"
Title="MainWindow"
Height="350"
Width="525">
<StackPanel DataContext="{Binding ElementName=self}" Orientation="Horizontal">
<ListBox Name="l1" ItemsSource="{Binding pgr}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Title}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<StackPanel Orientation="Vertical">
<TextBox Margin="10" Text="{Binding ElementName=l1,Path=SelectedItem.Title}" />
<Button Height="37" Margin="0" Content="{Binding ElementName=l1,Path=SelectedItem.Date}"></Button>
<TextBlock Margin="10" Height="33" Text="{Binding ElementName=l1,Path=SelectedItem.Chaine}" />
</StackPanel>
</StackPanel>
</Window>
Note the bindings that reference the selected item:
Text="{Binding ElementName=l1,Path=SelectedItem.Title}"

WPF controls not showing up in ItemTemplate(Listbox/ListView)

I have recently started with XAML and WPF. I just created a new project in wpf and add the below XAML code. But...none of the items which are added inside "Listbox.ItemTemplate" or "ListView.ItemTemplate" for that matter show up in designer window. what am i doing wrong? This is a fresh project and so no code-behind stuff added yet. i scratched my head for 15 mins with this but with no success. Please help
<Window x:Class="WpfApplication3.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 Margin="10">
<ListBox Margin="10">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Name: " />
<TextBlock Text="Age: " />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</Window>
You should bind your ListBox or entire Window to some DataContext (usually this is viewmodel with the data you need to display) or specify items of the list explicitly.
In your snippet you specified only an item template, not the items itself.
The example of XAML-defined items (simple strings):
<Window x:Class="WpfApplication3.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 Margin="10">
<ListBox Margin="10">
<ListBox.Items>
<ListBoxItem>123</ListBoxItem>
<ListBoxItem>456</ListBoxItem>
</ListBox.Items>
</ListBox>
</Grid>
</Window>
The example with DataContext and Bindings.
XAML:
<Window x:Class="WpfApplication3.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 Margin="10">
<ListBox Margin="10" ItemsSource="{Binding Path=Persons}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Label>Name:</Label><TextBlock VerticalAlignment="Center" Text="{Binding Path=Name}" />
<Label>Age:</Label><TextBlock VerticalAlignment="Center" Text="{Binding Path=Age}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</Window>
Codebehind:
namespace WpfApplication3
{
public class PersonViewModel
{
public PersonViewModel(string name, int age)
{
this.name = name;
this.age = age;
}
public string Name
{
get { return name; }
}
private string name;
public int Age
{
get { return age; }
}
private int age;
}
public class MainViewModel
{
public MainViewModel()
{
persons = new ObservableCollection<PersonViewModel>()
{
new PersonViewModel("Lez", 146),
new PersonViewModel("Binja", 158),
new PersonViewModel("Rufus the Destroyer", 9000)
};
}
public ObservableCollection<PersonViewModel> Persons
{
get { return persons; }
}
private ObservableCollection<PersonViewModel> persons;
}
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.DataContext = new MainViewModel();
}
}
}
IMPORTANT: Don't forget to properly implement INotifyPropertyChanged in case of mutable properties of viewmodels (for example, if you will have setters for "Name" and "Age" properties of PersonViewModel).
You don't see any items because your ListBox doesn't contain any data in the designer view. To populate it, a list should be binded to the property "ItemsSource" of your ListBox, or adding datas directly to the property "Items" (XAML or code behind).
If you want to show items in the designer view properly, you should have a ViewModel binding to the DataContext of your page and create a "Sample data" file (via Blend for example).
Item Templates are basically used to show customize data. Just Use simple string items first. It will show in list box.

Categories