TwoWay data binding between various controls - wpf

I'm very new to WPF, (I started yesterday) and I'm very confused about data binding. I have a View Model for a Window, which contains a widget called Foo which has its own View Model.
The widget Foo binds its Visibility TwoWay (via a BooleanToVisibilityConverter) to a bool field Visible on its FooViewModel. FooViewModel implements INotifyPropertyChanged and fires a PropertyChanged event whenever Visible is set.
In the Xaml for the Window, it creates a Foo whenever a button is clicked. The Window's view model has another boolean field which is bound TwoWay to the Visibility of its instance of a Foo View. The view model of the WIndow implements INotifyPropertyChanged and fires PropertyChanged events whenever the boolean field is modified.
What I expect this to do is whenever the window's boolean property changes, the visibility of the Foo instance will be set. When this happens I expect the View Model of Foo to be updated, since Foo's visibility binding is two way. When the Foo View Model changes its boolean field I expect the View to change its visibility. Further, I expect the Window view model to be notified that its instance of Foo is no longer visible, and hence the View model of the Window will update its own boolean field. Is this a fundamental misunderstanding?
I post the (obfuscated) code below if it helps shed light on this misunderstanding. Thanks.
Window Xaml
<Window x:Class="XXX.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="clr-namespace:XXX.ViewModel"
xmlns:v="clr-namespace:XXX"
Title="MainWindow" Height="350" Width="525" WindowStartupLocation="CenterOwner" WindowState="Maximized">
<Window.Resources>
<vm:AppViewModel x:Key="AppViewModel"/>
<vm:TwoWayVisibilityConverter x:Key="BoolToVisibility" />
</Window.Resources>
<Grid DataContext="{Binding Source={StaticResource AppViewModel}}">
<DockPanel>
<Menu DockPanel.Dock="Top">
<MenuItem Header="_Connection" Command="{Binding Authenticate}"/>
<MenuItem Header="_About" Command="{Binding ShowAbout}"/>
<MenuItem Header="_Logout" Command="{Binding Logout}"/>
<MenuItem Header="_Configuration" Command="{Binding Configuration}"/>
<MenuItem Header="_Info" Command="{Binding ShowInfo}"/>
</Menu>
<StackPanel>
</StackPanel>
</DockPanel>
<Border HorizontalAlignment="Center"
VerticalAlignment="Center"
Background="White"
Padding="10"
BorderThickness="0">
<TextBlock Text="XXX"/>
</Border>
<Grid x:Name="Overlay" Panel.ZIndex="1000" DataContext="{Binding Source={StaticResource AppViewModel}}">
<Border HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Visibility="{Binding Path=Modal, Converter={StaticResource BoolToVisibility}, Mode=OneWay}"
Background="DarkGray"
Opacity=".7" />
<v:Configuration HorizontalAlignment="Center"
VerticalAlignment="Center"
Visibility="{Binding Path=ConfigurationVisible, Converter={StaticResource BoolToVisibility}, Mode=TwoWay}"/>
<v:Connect HorizontalAlignment="Center"
VerticalAlignment="Center"
Visibility="{Binding Path=AuthenticateVisible, Converter={StaticResource BoolToVisibility}, Mode=TwoWay}"/>
</Grid>
</Grid>
Window View Model
class AppViewModel : INotifyPropertyChanged
{
[Import(typeof (IEventBus))] private IEventBus _bus;
public AppViewModel()
{
Authenticate = new ForwardCommand(obj => ShowAuthenticationView(), obj => !AuthenticateVisible);
Configuration = new ForwardCommand(obj => ShowConfigurationView(), obj => !ConfigurationVisible);
}
public bool Modal
{
get
{
return AuthenticateVisible || ConfigurationVisible;
}
}
public ICommand Authenticate { get; set; }
public bool AuthenticateVisible { get; set; }
public ICommand ShowInfo { get; set; }
public ICommand ShowAbout { get; set; }
public ICommand Logout { get; set; }
public ICommand Configuration { get; set; }
public bool ConfigurationVisible { get; set; }
private void ShowAuthenticationView()
{
AuthenticateVisible = !AuthenticateVisible;
if (null != PropertyChanged)
{
PropertyChanged(this, new PropertyChangedEventArgs("AuthenticateVisible"));
PropertyChanged(this, new PropertyChangedEventArgs("Modal"));
}
}
private void ShowConfigurationView()
{
ConfigurationVisible = !ConfigurationVisible;
if (null != PropertyChanged)
{
PropertyChanged(this, new PropertyChangedEventArgs("ConfigurationVisible"));
PropertyChanged(this, new PropertyChangedEventArgs("Modal"));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
UserControl Xaml
<UserControl x:Class="XXX.Connect"
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:vm="clr-namespace:XXX.ViewModel"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<UserControl.Resources>
<vm:ConnectViewModel x:Key="ViewModel"/>
<vm:TwoWayVisibilityConverter x:Key="BoolToVisibility" />
</UserControl.Resources>
<Grid Width="280"
Height="173"
DataContext="{Binding Source={StaticResource ViewModel}}"
Visibility="{Binding Path=Visible, Converter={StaticResource BoolToVisibility}, Mode=TwoWay}"
Background="White">
<Label Content="URL" Height="28" HorizontalAlignment="Left" Margin="12,12,0,0" Name="label1" VerticalAlignment="Top" />
<TextBox Height="23" HorizontalAlignment="Left" Margin="102,12,0,0" Name="url" VerticalAlignment="Top" Width="169" Text="{Binding Path=Url, Mode=OneWayToSource}" TabIndex="0" />
<TextBox Height="23" HorizontalAlignment="Left" Margin="102,70,0,0" Name="username" VerticalAlignment="Top" Width="171" Text="{Binding Path=Username, Mode=OneWayToSource}" TabIndex="2" />
<TextBox Height="23" HorizontalAlignment="Left" Margin="102,41,0,0" Name="password" VerticalAlignment="Top" Width="169" Text="{Binding Path=Password, Mode=OneWayToSource}" TabIndex="1" />
<Label Content="Username" Height="28" HorizontalAlignment="Left" Margin="12,39,0,0" Name="label3" VerticalAlignment="Top" />
<Label Content="Password" Height="28" HorizontalAlignment="Left" Margin="12,68,0,0" Name="label2" VerticalAlignment="Top" />
<DockPanel HorizontalAlignment="Right" VerticalAlignment="Bottom" Margin="13">
<Button Content="OK" Height="23" HorizontalAlignment="Left" Margin="5" Name="ok" VerticalAlignment="Top" Width="75" Command="{Binding ConnectCommand}" TabIndex="3" />
<Button Content="Cancel" Height="23" HorizontalAlignment="Left" Margin="5" Name="cancel" VerticalAlignment="Top" Width="75" Command="{Binding CloseCommand}" TabIndex="4" />
</DockPanel>
</Grid>
</UserControl>
UserControl View Model
internal class ConnectViewModel : INotifyPropertyChanged
{
[Import(typeof (IEventBus))] private IEventBus _bus;
public ConnectViewModel()
{
ConnectCommand = new ForwardCommand(obj => Fire(),
obj =>
Visible && !String.IsNullOrEmpty(Url) && !String.IsNullOrEmpty(Url) &&
!String.IsNullOrEmpty(Url));
CloseCommand = new ForwardCommand(obj => Hide(), obj => Visible);
}
public ICommand ConnectCommand { get; set; }
public ICommand CloseCommand { get; set; }
public string Url { get; set; }
public string Username { get; set; }
public string Password { get; set; }
private bool _visible;
public bool Visible
{
get { return _visible; }
set { _visible = value; }
}
private void Fire()
{
_bus.Publish<SessionCreatedEvent, SessionEventHandler>(new SessionCreatedEvent(Url, Username, Password));
Hide();
}
private void Hide()
{
Visible = false;
if (null != PropertyChanged)
PropertyChanged(this, new PropertyChangedEventArgs("Visible"));
}
public event PropertyChangedEventHandler PropertyChanged;
}

Binding always works on properties. So while you Raise Visible in your Hide method, you don't raise it in the actual property. But the property is what the binding engine will set. If you bind this to another dependency property it won't get notified about it.
Btw. whats a TwoWayVisibilityConverter? BooleanToVisibilityConverter is perfectly capable of handling two way bindings.
tl;dr to make two way binding work properly (and in fact even one way binding) you need to implement INotifyPropertyChanged properly which means, if the setter is called raise the property.
public bool Visible
{
get { return _visible; }
set
{
_visible = value;
if (null != PropertyChanged)
PropertyChanged(this, new PropertyChangedEventArgs("Visible"));
}
}

Related

WPF C# Command Binding

I have problem with binding, I want to navigate to new Page (not new window). I Have tried by click event, this is working but if I am trying by ICommand interface, it isn't working good. I don't want why, i have tried in cross-platform, everything works fine. I am thinking what's is wrong with that code.
Main XAML
<Window x:Class="WpfAppFP.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:WpfAppFP"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525"
Background="#67696d"
x:Name="_CLK">
<Window.Content>
<Border Background="#202021" CornerRadius="40" >
<StackPanel Margin="20">
<Label Content="Type in your data" Foreground="White" HorizontalAlignment="Center" FontSize="20" FontWeight="Bold"/>
<Separator/>
<Label Content="Name" HorizontalAlignment="Center" Foreground="White" FontWeight="Bold"/>
<TextBox HorizontalAlignment="Center" MinWidth="320" MinHeight="32" Foreground="Black" Background="#f5ddff" FontSize="15" FontWeight="DemiBold"/>
<Label Content="Surname" HorizontalAlignment="Center" Foreground="White" FontWeight="Bold"/>
<TextBox HorizontalAlignment="Center" MinWidth="320" MinHeight="32" Foreground="Black" Background="#f5ddff" FontSize="15" FontWeight="DemiBold"/>
<Label Content="Social" HorizontalAlignment="Center" Foreground="White" FontWeight="Bold"/>
<TextBox HorizontalAlignment="Center" MinWidth="320" MinHeight="32" Foreground="Black" Background="#f5ddff" FontSize="15" FontWeight="DemiBold" MaxLength="11" />
<Separator Margin="0,10,0,0"/>
<Button HorizontalAlignment="Center" MinHeight="32" MinWidth="120" Foreground="Black" Background="White" Margin="0,10,0,0" Content="Login" FontWeight="Bold" BorderThickness="2"
x:Name="BtnClk" Command="{Binding CandidatesVM}"/>
</StackPanel>
</Border>
</Window.Content>
MainPage
public partial class MainWindow : Window
{
CandidatesVM candidatesVM;
public MainWindow()
{
InitializeComponent();
candidatesVM = new CandidatesVM();
this.DataContext = candidatesVM;
}
}
CandidatesVM
public class CandidatesVM
{
public NavigationCandidates navigationCandidates { get; set; }
public CandidatesVM()
{
navigationCandidates = new NavigationCandidates(this);
}
public void Navigate()
{
MainWindow mainWindow = new MainWindow();
mainWindow._CLK.Content = new Candidates();
}
}
NavigationCandidates
public class NavigationCandidates : ICommand
{
public CandidatesVM candidatesVM { get; set; }
public event EventHandler CanExecuteChanged;
public NavigationCandidates(CandidatesVM canVM)
{
candidatesVM = canVM;
}
public bool CanExecute(object parameter)
{
return true;
}
public void Execute(object parameter)
{
candidatesVM.Navigate();
}
}
Bind to navigationCandidates, that's the command:
<Button x:Name="BtnClk" ... Command="{Binding navigationCandidates}"/>
Then I don't know why you are creating a new instance of the MainWindow in the Navigate() method of CandidatesVM. I guess you want to set the Content of the already existing one:
public class CandidatesVM
{
public NavigationCandidates navigationCandidates { get; set; }
private readonly MainWindow _mainWindow;
public CandidatesVM(MainWindow mainWindow)
{
_mainWindow = mainWindow;
navigationCandidates = new NavigationCandidates(this);
}
public void Navigate()
{
_mainWindow.Content = new Candidates();
}
}
public partial class MainWindow : Window
{
CandidatesVM candidatesVM;
public MainWindow()
{
InitializeComponent();
candidatesVM = new CandidatesVM(this);
this.DataContext = candidatesVM;
}
}
You should be binding to navigationCandidates rather than CandidateVM
<Button HorizontalAlignment="Center" MinHeight="32" MinWidth="120" Foreground="Black" Background="White" Margin="0,10,0,0" Content="Login" FontWeight="Bold" BorderThickness="2"
x:Name="BtnClk" Command="{Binding navigationCandidates }"/>
Why ? CandidateVM is served as a data context to your window. So you should be binding to some property of data context and not to data context itself.

How do I initialize viewmodel's datacontext when the application starts?

I started to use MVVMLight framework recently.
When I use ContentPresenter to swtich between ViewModel, it seems like it initialize the datacontext when it first displays.
However, I want it to initialize it's datacontext so it can keep track of any change from the initial loading of the application, or at least share the data with other viewmodel(I assume maybe I can use dataservice to keep track of all the data, but I could not find a right example to use it with contentpresenter & MVVMLight).
Below is the sample code I made. When I click Review button, "usercontrolview" will display "Picture Saved", however "contentpresenterview" will display "No Picture".
Sample Image
MainView.xaml
<Grid>
<Button x:Name="CaptureButton" Content="Capture" HorizontalAlignment="Left" Margin="34,10,0,0" VerticalAlignment="Top" Width="75"
Command="{Binding CaptureCommand}"/>
<Button x:Name="ReviewButton" Content="Review" HorizontalAlignment="Left" Margin="146,10,0,0" VerticalAlignment="Top" Width="75"
Command="{Binding ShowReviewCommand}"/>
<TextBlock FontSize="36"
FontWeight="Bold"
Foreground="Purple"
Text="{Binding CaptureStatus}"
VerticalAlignment="Center"
HorizontalAlignment="Center"
TextWrapping="Wrap" />
<Grid x:Name="usercontrolview" Visibility="{Binding ReviewModeOn, Converter={StaticResource BooleanToVisibilityConverter}}" Margin="0,50,150,0">
<view:ReviewView/>
</Grid>
<ContentPresenter x:Name="contentpresenterview" Content="{Binding CurrentContent}" Margin="150,50,0,0"/>
</Grid>
MainViewModel.cs (Partial)
public MainViewModel()
{
CaptureStatus = "No Picture";
CaptureCommand = new RelayCommand(Capture);
ShowReviewCommand = new RelayCommand(ShowReview);
ReviewModeOn = false;
}
public RelayCommand CaptureCommand { get; private set; }
private void Capture()
{
CaptureStatus = "Pictures Saved";
Messenger.Default.Send<NotificationMessage>(new NotificationMessage("Pictures Saved"), "Captured");
}
public RelayCommand ShowReviewCommand { get; private set; }
private void ShowReview()
{
ReviewModeOn = !ReviewModeOn;
CurrentContent = ContentViewModel;
}
And my template for ReviewViewModel & ReviewContentPresenterViewModel
public ***ViewModel()
{
Messenger.Default.Register<NotificationMessage>(this, "Captured", Captured);
CaptureStatus = "No Picture";
}
private void Captured(NotificationMessage notificationMessage)
{
CaptureStatus = notificationMessage.Notification;
}
private string _captureStatus;
public string CaptureStatus
{
get { return _captureStatus; }
set { Set(ref _captureStatus, value); }
}
======================= Update =======================
My template for ReviewView & ReviewContentPresenterView.
It takes DataContext by locator.
<UserControl x:Class="***View"
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:ignore="http://www.galasoft.ch/ignore"
mc:Ignorable="d ignore"
DataContext="{Binding ***ViewModel, Source={StaticResource Locator}}">
<Grid Background="Gray">
<TextBlock FontSize="36"
FontWeight="Bold"
Foreground="Purple"
Text="{Binding CaptureStatus}"
VerticalAlignment="Center"
HorizontalAlignment="Center"
TextWrapping="Wrap" />
</Grid>
</UserControl>
It seems your DataContext in the root Grid and all it's children is the MainViewModel and you want other DataContext for ContentPresenter. Create the other ViewModel as a resource e.g.
<Grid>
<Grid.Resources>
<local:TheViewModelIWant x:Key=ContentViewModel/>
</Grid.Resources>
...
...
<ContentPresenter DataContext={StaticResource ContentViewModel} ...
(By the way, if you are already creating an instance of TheViewModelIWant somewhere e.g. in other ViewModels or view code behind then you can stop using that instance and access this instance in C# code as Resources["ContentViewModel"])

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 PropertyChanged event is null after updating property

I'm struggling with some databinding. In my MainWindow I have 2 buttons which are databound to a property Result in a class "Properties" - strictly for holding properties that I will be using for databinding. The buttons are hidden by default, and when I want them to become visible I simply set Result property that they are bound to to "True"
I know the databinding is working because if I set the property to a static value, the buttons are visible / not visible. See below for my XAML
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<StackPanel.Resources>
<BooleanToVisibilityConverter x:Key="BoolToVis" />
</StackPanel.Resources>
<Button x:Name="btnBack" Height="25" Content="<- Back" Visibility="{Binding Path=Result, Converter={StaticResource BoolToVis},
UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Top" Width="75" Click="btnBack_Click" Margin="0,0,10,0" />
<Button x:Name="btnNext" Height="25" Content="Next ->" Visibility="{Binding Path=Result, Converter={StaticResource BoolToVis},
UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Top" Width="75" Click="btnNext_Click" Margin="10,0,0,0"/>
</StackPanel>
So they are bound to "Result" property, and I have UpdateSourceTrigger=Propertychangedin my binding.
In my "Properties" class I have the below and AM implementing INotifyPropertyChanged
bool _result;
#endregion
public bool Result {
get
{
return _result;
}
set
{
_result = value;
NotifyPropertyChanged("Result");
}
}
#region EVENTS
public event PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChanged(string propName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propName));
}
}
But for some reason when I change the property to "True" the PropertyChanged Event is null and therefore the event never fires.
Any idea as to why this is happening? Could it be because this code isn't in my ViewModel and just in a separate class?
Make sure that you have set the DataContext of the window to an instance of your Properties class and that you don't set the DataContext property of any parent element of the StackPanel to something else because the DataContext is inherited.
Please refer to the following sample code. The Buttons do become visible as expected after the 3 second delay:
public partial class MainWindow : Window
{
private Properties _viewModel = new Properties();
public MainWindow()
{
InitializeComponent();
DataContext = _viewModel;
this.Loaded += async (s, e) =>
{
await Task.Delay(3000);
_viewModel.Result = true;
};
}
}
public class Properties : INotifyPropertyChanged
{
bool _result;
public bool Result
{
get
{
return _result;
}
set
{
_result = value;
NotifyPropertyChanged("Result");
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChanged(string propName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propName));
}
}
}
<Window 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="300" Width="300">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<StackPanel.Resources>
<BooleanToVisibilityConverter x:Key="BoolToVis" />
</StackPanel.Resources>
<Button x:Name="btnBack" Height="25" Content="<- Back" Visibility="{Binding Path=Result, Converter={StaticResource BoolToVis},
UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Top" Width="75" Margin="0,0,10,0" />
<Button x:Name="btnNext" Height="25" Content="Next ->" Visibility="{Binding Path=Result, Converter={StaticResource BoolToVis},
UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Top" Width="75" Margin="10,0,0,0"/>
</StackPanel>
</Window>

WPF displaying object properties from Observable Collection MVVM

I am trying to display the properties from an object which is contained in an observable list but it is just not working.
I was hoping someone could point me in the right direction.
Here is my XAMl
<Window x:Name="MainViewWindow" x:Class="WpfApplication1.View.MainView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local ="clr-namespace:WpfApplication1.ViewModel"
Title="MainView" Height="413.514" Width="607.095">
<Window.DataContext>
<local:MainViewModel />
</Window.DataContext>
<Grid>
<Label Content="Text:" HorizontalAlignment="Left" Margin="55,135,0,0" VerticalAlignment="Top"/>
<Label Content="{Binding Name}" HorizontalAlignment="Left" Margin="98,135,0,0" VerticalAlignment="Top"/>
<Button Content="Button" HorizontalAlignment="Left" Margin="61,108,0,0" VerticalAlignment="Top" Width="75" Command="{Binding UpdateNameCommand}"/>
<Label Content="ActivateButton" HorizontalAlignment="Left" Margin="52,82,0,0" VerticalAlignment="Top"/>
<CheckBox Content="CheckBox" HorizontalAlignment="Left" Margin="173,87,0,0" VerticalAlignment="Top" IsChecked="{Binding ButtonActive}" />
<Label Content="CustomerName" HorizontalAlignment="Left" Margin="55,166,0,0" VerticalAlignment="Top"/>
<StackPanel HorizontalAlignment="Left" Height="100" Margin="173,166,0,0" VerticalAlignment="Top" Width="100"/>
<ItemsControl x:Name="lstPeople" Background="AliceBlue" Width="130" Margin="273,29,196,35" ItemsSource="{Binding CustomerList}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
My CustomerList is a property located in the MainViewModel:
ObservableCollection<Customer> _CustomerList;
ObservableCollection<Customer> CustomerList
{
get { return _CustomerList; }
set
{
if (_CustomerList != value)
{
_CustomerList = value;
PropertyChanged(this, new PropertyChangedEventArgs("CustomerList"));
}
}
}
My Customer class only contains one property: Name
public class Customer : INotifyPropertyChanged
{
private string _Name;
public string Name
{
get { return _Name; }
set
{
if (_Name != value)
{
_Name = value;
PropertyChanged(this, new PropertyChangedEventArgs("Name"));
}
}
}
public event PropertyChangedEventHandler PropertyChanged = delegate { };
}
I have created an instance of the CustomerList in the MainViewModel constructor but i cannot see any of my customers showing up in the application:
public MainViewModel()
{
ButtonActive = true;
CustomerList = new ObservableCollection<Customer>() { new Customer() { Name = "NewCust33" } };
CustomerList.Add(new Customer() { Name = "NewCust" });
}
It looks like the property you're binding to is private?
You can only bind to public properties.
public ObservableCollection<Customer> CustomerList

Resources