WPF binding with ContentControl not working - wpf

I'm just starting to use WPF, but my binding doesn't work.
When I start the application the screen is just blank.
This is my XAML
<Window x:Class="HelloWPF.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>
<ContentControl Content="{Binding PersonOne}" Width="auto" Height="auto" >
<ContentControl.ContentTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding FirstName}" FontSize="15" />
<TextBlock Text="{Binding Age}" FontSize="12" />
</StackPanel>
</DataTemplate>
</ContentControl.ContentTemplate>
</ContentControl>
</Grid>
This is the code:
public partial class MainWindow : Window
{
public Person PersonOne;
public MainWindow()
{
InitializeComponent();
PersonOne = new Person();
PersonOne.Gender = Gender.Female;
PersonOne.Age = 24;
PersonOne.FirstName = "Jane";
PersonOne.LastName = "Joe";
this.DataContext = this;
}
}
And this is the person class
public class Person
{
public string LastName { get; set; }
public string FirstName { get; set; }
public int Age { get; set; }
public Gender Gender { get; set; }
}
public enum Gender
{
Male,
Female
}
What am I doing wrong?

You cannot bind to fields, only properties, so change this:
public Person PersonOne;
to this:
public Person PersonOne {get;set;}
BTW, you probably need to create a ViewModel rather than putting the Data inside the Window itself.

Related

Add item to selection listbox on button click

I have setup a WPF with several listboxes and an add button:
<Window x:Class="QuickSlide_2._0.Window1"
x:Name="load_style"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:self="clr-namespace:QuickSlide_2._0"
xmlns:e="http://schemas.microsoft.com/expression/2010/interactivity"
Title="Load_style" Height="300" Width="300" MinHeight="720" MinWidth="1280" WindowStyle="None" AllowsTransparency="True" Background="#B0000000" AllowDrop="True" WindowStartupLocation="CenterScreen" ShowInTaskbar="False">
<Grid>
<Rectangle Height="720" HorizontalAlignment="Left" Name="rectangle1" Stroke="#00000000" VerticalAlignment="Top" Width="1280" MinHeight="320" MinWidth="380" Fill="DarkGray"/>
<ListBox Height="241" HorizontalAlignment="Left" Margin="502,371,0,0" Name="Presentation_slide_items" VerticalAlignment="Top" Width="199" />
<ListBox Name="subjects_list" Margin="74,154,1039,171" ItemsSource="{Binding ElementName=styles_list, Path=SelectedItem.subjects}"/>
<ListBox Name="sub_subjects_list" Margin="264,154,849,171" ItemsSource="{Binding ElementName=subjects_list, Path=SelectedItem.sub_subjects}"/>
<ComboBox x:Name="styles_list" HorizontalAlignment="Left" VerticalAlignment="Top" Width="120" Margin="74,112,0,0"/>
<ListBox Name="user_inputs" Margin="502,154,565,421" ItemsSource="{Binding ElementName=sub_subjects_list, Path=SelectedItem.possible_input, Mode=TwoWay}" >
<ListBox.ItemTemplate>
<DataTemplate>
<TextBox Name="TextBoxList" Text="{Binding input}" BorderThickness="0" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<Button x:Name="button_add_input" Content="Add" HorizontalAlignment="Left" Margin="502,279,0,0" VerticalAlignment="Top" Width="106" Command="{Binding ElementName=sub_subjects_list.add_input} />
</Grid>
Now I want to add an additional user_input to the list in the user_inputs listbox when clicking on the button "button_add_input". I have been searching and it looks like using the "command" option of the button could be the way to go.
This is my class "sub_subject"
public class sub_subject
{
public string short_name { get; set; }
public string name { get; set; }
public bool read_from_db { get; set; }
public string table_name { get; set; }
//public ObservableCollection<string> possible_input { get; set; }
public ObservableCollection<possible_input> possible_input { get; set; }
public sub_subject(string name)
{
this.name = name;
possible_input = new ObservableCollection<possible_input>();
//possible_input = new ObservableCollection<string>();
}
public override string ToString()
{
return this.name;
}
public void add_input()
{
possible_input input = new possible_input();
input.input = "";
possible_input.Add(input);
}
}
I was thinking I can add a function to the class that adds a possible_input to the ObservableCollection and calling this function in the command of the button. But I just cannot figure out how to setup the proper command. Any suggestions?
I assume that sub_subject is the viewmodel (the datacontext) of the window (the view).
In this case you should add a Command class to your project. This is an implementation of the ICommand. You can find an implementation of the ICommand here: https://msdn.microsoft.com/en-us/magazine/dd419663.aspx
After that you will have to create a property in your viewmodel for the command that calls the add_input method. Then, bind your command property to the Command property of the button.

WPF: Update ListBox from bound property when button is pressed, not automatically

Given the following classes (where ViewModelBase contains the INotifyPropertyChanged members)
namespace WpfApplication1
{
class ViewModel : ViewModelBase
{
private Person selectedPerson;
public ObservableCollection<Person> Persons { get; set; }
public Person SelectedPerson
{
get
{
return selectedPerson;
}
set
{
selectedPerson = value;
OnPropertyChanged("SelectedPerson");
}
}
public ViewModel()
{
Persons = new ObservableCollection<Person>();
Persons.Add(new Person { FirstName = "John", LastName = "Smith" });
Persons.Add(new Person { FirstName = "Jane", LastName = "Jones" });
SelectedPerson = new Person();
}
}
class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
}
And the following XAML
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="clr-namespace:WpfApplication1"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<vm:ViewModel />
</Window.DataContext>
<Grid>
<StackPanel>
<ListBox ItemsSource="{Binding Persons}"
DisplayMemberPath="FirstName"
SelectedItem="{Binding SelectedPerson}"/>
<StackPanel DataContext="{Binding SelectedPerson}">
<TextBox Text="{Binding FirstName}" />
<TextBox Text="{Binding LastName}" />
</StackPanel>
</StackPanel>
</Grid>
</Window>
If the value in the TextBox bound to FirstName is changed, the change is automatically reflected in the ListBox. Assuming that I add a Button control and associated Command, is there a way instead to have the changed value propagated to the ListBox only if that Button has been pressed?

Binding a property inside observerList in wpf

I am writing an application in C#, WPF, XAML using MVVM patterm.
After many examples that I founded online the data that I try to Bind to the UI is not shown in the screen.
My architecture is : In the MainViewModel I have an ObserverList from type family,
in Family class I have an ObserverList from type Child,
in Child class I have Name.
How to Bind the Child Name in to TextBlock?
Some examples that I founded:
https://msdn.microsoft.com/en-us/library/aa970558%28v=vs.110%29.aspxv
<Window x:Class="DataTemplates.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:DataTemplates"
Title="MainWindow"
Height="350"
Width="525">
<Window.Resources>
<DataTemplate x:Key="MyDataTemplate"
DataType="local:MyData">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0"
Text="First Name: " />
<TextBlock Grid.Column="1"
Text="{Binding Path=FirstName}" />
<TextBlock Grid.Column="2"
Text="Last Name: " />
<TextBlock Grid.Column="3"
Text="{Binding Path=LastName}" />
<CheckBox Grid.Column="4"
Content="Is Lecturer?"
IsEnabled="False"
IsChecked="{Binding Path=IsLecturer}" />
</Grid>
</DataTemplate>
</Window.Resources>
<StackPanel>
<ListBox ItemsSource="{Binding}"
ItemTemplate="{StaticResource MyDataTemplate}"
HorizontalContentAlignment="Stretch" />
<Button Content="Add"
Click="Button_Click" />
</StackPanel>
</Window>
and the code Behind
using System.Collections.ObjectModel;
using System.Windows;
namespace CollectionDemo
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private ObservableCollection<MyData> _myCollection =
new ObservableCollection<MyData>();
public MainWindow()
{
InitializeComponent();
DataContext = _myCollection;
_myCollection.Add(
new MyData
{
FirstName = "Arik",
LastName = "Poznanski",
IsLecturer = true
});
_myCollection.Add(
new MyData
{
FirstName = "John",
LastName = "Smith",
IsLecturer = false
});
}
private int counter = 0;
private void Button_Click(object sender, RoutedEventArgs e)
{
++counter;
_myCollection.Add(
new MyData()
{
FirstName = "item " + counter,
LastName = "item " + counter,
IsLecturer = counter % 3 == 0
});
}
}
}
class my data form the example
public class MyData
{
public string User { get; set; }
public string Password { get; set; }
}
I made a custom example which matches your scenario, take a look at this.
MainWindow.xaml
<Window x:Class="SO.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>
<TextBlock Height="30" Text="{Binding Parent.Child.SampleText}" HorizontalAlignment="Center"/>
</Grid>
</Window>
MainWindow.xaml.cs
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
MainViewModel obj = new MainViewModel();
this.DataContext = obj;
}
}
MainViewModel.cs
public class MainViewModel
{
private ParentModel _Parent = new ParentModel();
public ParentModel Parent
{
get { return _Parent; }
set { _Parent = value; }
}
public MainViewModel() //Data Load in Constructor
{
ChildModel child = new ChildModel();
child.SampleText = "Hi, I am Child!";
Parent.Child = child;
}
}
ParentModel.cs
public class ParentModel
{
private ChildModel _Child = new ChildModel();
public ChildModel Child
{
get { return _Child; }
set { _Child = value; }
}
}
ChildModel.cs
public class ChildModel
{
private string _SampleText ;
public string SampleText
{
get { return _SampleText; }
set { _SampleText = value; }
}
}
Corrections in your eg:
Your View and Code behind is perfect.
You didn't add properties in model class which is to be binded in UI.
class MyData
{
//public string User { get; set; }
//public string Password { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public bool IsLecturer { get; set; }
}

WPF ListView within a ListView

I am sure I am missing something simple/obvious, but I cannot seem to bind the data of a ListView within a ListView
<Window x:Class="TestList.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">
<Window.Resources>
<DataTemplate x:Key="InsideListTemplate">
<StackPanel Orientation="Horizontal">
<TextBlock Text="test" Width="50"></TextBlock>
<TextBlock Text="{Binding OrderId}" Width="50"></TextBlock>
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="OrdersTemplate">
<ListView HorizontalAlignment="Stretch"
HorizontalContentAlignment="Stretch"
MinWidth="100"
MinHeight="25"
ItemsSource="{Binding Orders}"
ItemTemplate="{StaticResource InsideListTemplate}"
>
</ListView>
</DataTemplate>
<DataTemplate x:Key="CustomersTemplate">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Stretch">
<TextBlock Text="{Binding CustomerId}" Width="50" Foreground="Navy" VerticalAlignment="Center" />
<ListBox ItemsSource="{Binding Orders}" ItemTemplate="{StaticResource OrdersTemplate}" HorizontalContentAlignment="Stretch"></ListBox>
</StackPanel>
</DataTemplate>
</Window.Resources>
<DockPanel LastChildFill="True">
<ListView Name="listView" ItemTemplate="{StaticResource CustomersTemplate}" >
</ListView>
</DockPanel>
using System.Collections.Generic;
namespace TestList
{
public partial class MainWindow
{
public class Customer
{
public int CustomerId { get; set; }
public List<Order> Orders { get; set; }
}
public class Order
{
public int OrderId { get; set; }
}
public MainWindow()
{
InitializeComponent();
DataContext = this;
var customers = new List<Customer>
{
new Customer
{
CustomerId = 1,
Orders = new List<Order>
{
new Order {OrderId = 1},
new Order {OrderId = 2}
}
},
new Customer
{
CustomerId = 2,
Orders = new List<Order>
{
new Order {OrderId = 1},
new Order {OrderId = 2}
}
}
};
listView.ItemsSource = customers;
}
}
}
This is an explanation of Hadis answer:
You are binding a ListBox to the Orders collection within the customer template. And then in the orders template you define a ListView binding again to the orders. This means that the binding path at that point is customer.orders.orders which does not exists.
If you just remove the OrdersTemplate and place the ListView where the ListBox is in the customer template then it works.
How about changing it list this:
public partial class MainWindow : Window
{
public class Customer
{
public int CustomerId { get; set; }
public List<Order> Orders { get; set; }
}
public class Order
{
public int OrderId { get; set; }
public List<OrderItem> Items { get; set; }
}
public class OrderItem
{
public int No { get; set; }
public string Name { get; set; }
}
public MainWindow()
{
InitializeComponent();
DataContext = this;
var customers = new List<Customer>
{
new Customer
{
CustomerId = 1,
Orders = new List<Order>
{
new Order {OrderId = 1, Items = new List<OrderItem>(new[] { new OrderItem { Name = "CD Player", No = 1}, new OrderItem { Name = "VCR Player", No = 2} })},
new Order {OrderId = 2, Items = new List<OrderItem>(new[] { new OrderItem { Name = "DVD Player", No = 1} })}
}
},
new Customer
{
CustomerId = 2,
Orders = new List<Order>
{
new Order {OrderId = 1},
new Order {OrderId = 2}
}
}
};
listView.ItemsSource = customers;
}
}
and on your Xaml modify it like this:
<DataTemplate x:Key="InsideListTemplate">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding No}" Width="50"></TextBlock>
<TextBlock Text="{Binding Name}" Width="50"></TextBlock>
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="OrdersTemplate">
<StackPanel>
<TextBlock Text="{Binding OrderId}" />
<ListView HorizontalAlignment="Stretch"
HorizontalContentAlignment="Stretch"
MinWidth="100"
MinHeight="25"
ItemsSource="{Binding Items}"
ItemTemplate="{StaticResource InsideListTemplate}" />
</StackPanel>
</DataTemplate>
And your output will display the details

DataBinding with DataContext

what am I doing wrong here? I'm trying to create a DataTemplate using a collection inside the DataContext object, like the following:
C#:
namespace StackOverflowTests
{
/// <summary>
/// Interaction logic for Window1.xaml
/// </summary>
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
this.DataContext = new People();
}
}
class People
{
public List<Person> PersonList { get; set; }
public People()
{
this.PersonList = new List<Person>()
{
new Person(){FirstName = "Carlo", LastName = "Toribio" },
new Person(){FirstName = "Guy", LastName = "Incognito" }
};
}
}
class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
}
XAML:
<Window x:Class="StackOverflowTests.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" x:Name="window1" Height="300" Width="300">
<Window.Resources>
<DataTemplate x:Key="peopleTemplate">
<StackPanel>
<TextBlock Text="First Name" FontWeight="Bold" />
<TextBlock Text="{Binding PersonList.FirstName}" />
<TextBlock Text="Last Name" FontWeight="Bold" />
<TextBlock Text="{Binding PersonList.LastName}" />
</StackPanel>
</DataTemplate>
</Window.Resources>
<Grid x:Name="gridMain">
<ItemsControl ItemsSource="{Binding}" ItemTemplate="{StaticResource peopleTemplate}" />
</Grid>
</Window>
I've done this a lot easier by using a class that inherits from Collection<T>, but for many reasons, I can't do that to solve this problem. Any suggestion is greatly appreciated.
Thanks!
try this one:
<Grid x:Name="gridMain">
<ItemsControl ItemsSource="{Binding PersonList}" ItemTemplate="{StaticResource peopleTemplate}" />
</Grid>

Resources