WPF binding doesn't work - wpf

I have simplified example:
XAML:
<CheckBox IsChecked="{Binding Path=IsSelected, Mode=TwoWay}" Name="cb" />
<Button Name="button1" Click="button1_Click" />
Code behind:
public partial class MainWindow : Window
{
private ObservableCollection<MyObject> collection = new ObservableCollection<MyObject>();
public MainWindow()
{
InitializeComponent();
collection.Add(new MyObject(true));
//grid.DataContext = collection[0];
}
private void button1_Click(object sender, RoutedEventArgs e)
{
collection[0].IsSelected = false;
}
}
public class MyObject
{
public bool IsSelected { get; set; }
public MyObject(bool isSelected)
{
this.IsSelected = isSelected;
}
}
The cb.IsChecked doesn't change by button clicking though the collection[0].IsSelected is changed.
Even if I uncomment grid.DataContext = collection[0]; - nothing changed.
In real example I have the same checkbox in the item template of a listbox. So the behaviour is the same - the selection of checkboxes don't change.

You need to implement INotifyPropertyChanged on your MyObject type

Please try the following codes:
public class MyObject : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(string info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
private bool _isSelected;
public bool IsSelected
{
get { return _isSelected; }
set
{
_isSelected = value;
NotifyPropertyChanged("IsSelected");
}
}
public MyObject(bool isSelected)
{
this.IsSelected = isSelected;
}
}

Related

How to add files into my binding ListView with Pure XAML

So i have Page with Button and ListView.
Via this Button the user select files that i want to add into my ListView
<Page.Resources>
<vm:ViewModelBase x:Key="ViewModelBase"/>
</Page.Resources>
<Button Command="{Binding AddFilesCommand, Source={StaticResource ViewModelBase}}"/>
<ListView ItemsSource="{Binding Files}"/>
My ViewModel:
public class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private ObservableCollection<FileBase> _files;
public AddFilesCommand AddFilesCommand { get; set; }
public ViewModelBase()
{
_files = new ObservableCollection<FileBase>();
AddFilesCommand = new AddFilesCommand(this);
}
public void AddFile()
{
OpenFileDialog openFileDialog = new OpenFileDialog
{
Title = "Please Select File(s)",
Multiselect = true
};
if (openFileDialog.ShowDialog() == true)
{
string[] files = openFileDialog.FileNames;
if (files.Length > 0)
AddFile(files);
}
}
public void AddFile(string[] files)
{
// Here i am add all my files into my Files collection
}
public ObservableCollection<FileBase> Files
{
get { return _files; }
set
{
_files= value;
NotifyPropertyChanged();
}
}
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
AddFilesCommand
public class AddFilesCommand : ICommand
{
public event EventHandler CanExecuteChanged;
public bool canExecute { get; set; }
public ViewModelBase ViewModel { get; set; }
public AddFilesCommand(ViewModelBase viewModel)
{
canExecute = true;
ViewModel = viewModel;
}
public bool CanExecute(object parameter)
{
return canExecute;
}
public void Execute(object parameter)
{
ViewModel.AddFile();
}
}
Now this works fine and i can see the all the files that the user select are inside my Files collection but i cannot see this files inside my ListView

Visibility of StackPanel in MVVM

I'm working with WPF using Prism ( MVVM). I wanted to set visibililty
of StackPanel from ViewModel calss. The StackPanel's visibility is
binded like :
<StackPanel x:Name="spVisibility" Orientation="Horizontal"
Visibility="{Binding spVisibility, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}">
I've view model class like :
public class SearchId : BindableBase, INotifyPropertyChanged
{
private Visibility _visibility = Visibility.Collapsed;
private DelegateCommand<object> searchCommand;
public event PropertyChangedEventHandler PropertyChanged;
public SearchId()
{
searchCommand = new DelegateCommand<object>(this.SearchData);
}///
public Visibility spVisibility
{
get { return _visibility; }
set
{
if (!string.Equals(_visibility, value))
{
_visibility = value;
RaisePropertyChanged("spVisibility");
}
}
}
private void RaisePropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this,
new PropertyChangedEventArgs (propertyName));
}
}
private async void SearchData(object parameter)
{
_visibility = Visibility.Visible;
}
}
But this not working. Please help me.
_visibility = Visibility.Visible is setting the private property instead of using the public one so RaisePropertyChanged("spVisibility") is being bypassed. You need to use spVisibility = Visibility.Visible.
If you are using MVVM i would recommend using a Boolean value instead of Visibility. The whole purpose of MVVM is seperation of View Logic from DataLogic.
View logic:
<StackPanel Orientation="Horizontal"
Visibility="{Binding ShowStackPanel, Converter={StaticResource BooleanToVisibilityConverter}}">
Use a Converter to convert the boolan to a Visibility Property.. BooleanToVisibilityConverter is part of .NET and can be referenced without defining it manually in the xaml.
public class SearchId : BindableBase, INotifyPropertyChanged
{
private bool _showStackPanel;
private DelegateCommand<object> searchCommand;
public event PropertyChangedEventHandler PropertyChanged;
public SearchByIDVM()
{
searchCommand = new DelegateCommand<object>(this.SearchData);
}///
public bool ShowStackPanel
{
get { return _showStackPanel; }
set
{
if (!Equals(_showStackPanel, value))
{
_showStackPanel= value;
RaisePropertyChanged("ShowStackPanel");
}
}
}
private void RaisePropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this,
new PropertyChangedEventArgs (propertyName));
}
}
private async void SearchData(object parameter)
{
ShowStackPanel= true;
}
}

Silverlight MVVM:Updating parent view model based on status of child View model

I am new to Silverlight MVVM.
I have one requirement to show checkbox in a parent child hierarchy.
While loading the page if the child is checked then parent checkbox should also get checked.
I have created a ViewModel as below
public class TestViewModel : INotifyPropertyChanged
{
private string name;
private string percent;
private bool isChecked;
internal event EventHandler CheckboxStateChanged = delegate { };
private List<TestViewModel> testViewModel;
public List<TestViewModel> TestViewModel1
{
get { return testViewModel; }
set
{
testViewModel = value;
NotifyPropertyChanged("TestViewModel1");
}
}
public TestViewModel()
{
//IsChecked = true;
//Name = "Hello";
//Percent = "10";
}
public bool IsChecked
{
get { return isChecked; }
set
{
isChecked = value;
NotifyPropertyChanged("IsChecked");
CheckboxStateChanged(this, new EventArgs());
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
In my main.xaml.cs I have created recursive method which will create the parent child hierarchy of checkboxes.
On clicking the child checkbox, parent checkbox is getting checked as I have added eventhandler in my VM (CheckboxStateChanged ) for that.But while on page load if child is checked then parent also get checked,I am unable to do that..Pls help.
Note I can not make parents checked until I get the status of child and once I get child status m not sure how to go back to parent.
Parent VM contains list of same VM as children(i.e public List TestViewModel1)
If I understand your question correct you are looking for a way to bouble up checkbox values from the children to its parent checkbox.
I've done a similar solution for a tree view. This code works but needs some event detaching if the collection changes.
The following is the set of classes that is used to run the ViewModel part of this solution.
public class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public class StructureViewModel : ViewModelBase
{
private bool? _isChecked = false;
public bool? IsChecked
{
get { return _isChecked; }
set
{
if (_isChecked != value)
{
_isChecked = value;
RaisePropertyChanged("IsChecked");
}
}
}
public string Name { get; set; }
}
public class ChildViewModel : StructureViewModel
{
}
public class ParentViewModel : StructureViewModel
{
public ParentViewModel()
{
Children = new List<ChildViewModel>();
}
public ICollection<ChildViewModel> Children { get; set; }
}
public class MainViewModel : ViewModelBase
{
public MainViewModel()
{
Parents = new List<ParentViewModel>();
var parent = new ParentViewModel { Name = "Parent" };
parent.Children.Add(new ChildViewModel
{
Name = "Child1"
});
parent.Children.Add(new ChildViewModel
{
Name = "Child2"
});
Parents.Add(parent);
}
public ICollection<ParentViewModel> Parents { get; set; }
}
To display this I use the following markup:
<TreeView ItemsSource="{Binding Parents}">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Children}" >
<CheckBox IsChecked="{Binding IsChecked, Mode=TwoWay}" Content="{Binding Name}">
<i:Interaction.Behaviors>
<local:CheckParentBehavior Children="{Binding Children}" />
</i:Interaction.Behaviors>
</CheckBox>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
The magic that fixes the checkboxes are the CheckParentBehavior:
public class CheckParentBehavior : Behavior<CheckBox>
{
public IEnumerable<StructureViewModel> Children
{
get { return (IEnumerable<StructureViewModel>)GetValue(ChildrenProperty); }
set { SetValue(ChildrenProperty, value); }
}
public static readonly DependencyProperty ChildrenProperty =
DependencyProperty.Register("Children", typeof(IEnumerable<StructureViewModel>), typeof(CheckParentBehavior), new PropertyMetadata(OnChildrenChanged));
protected override void OnAttached()
{
if (Children != null)
AssociatedObject.IsChecked = GetCheck(Children);
}
private static void OnChildrenChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (e.NewValue != null)
{
foreach (var child in e.NewValue as IEnumerable<StructureViewModel>)
child.PropertyChanged += (_, args) => OnChildPropertyChanged(d as CheckParentBehavior, args);
}
}
private static void OnChildPropertyChanged(CheckParentBehavior behavior, PropertyChangedEventArgs args)
{
if (args.PropertyName == "IsChecked")
behavior.AssociatedObject.IsChecked = GetCheck(behavior.Children);
}
public static bool? GetCheck(IEnumerable<StructureViewModel> children)
{
if (children.All(c => c.IsChecked.GetValueOrDefault()))
return true;
else if (children.Any(c => c.IsChecked.GetValueOrDefault()))
return null;
else
return false;
}
}
What happens is that it listens to each childs propertychanged event and if it changes the ischecked property it will change the parents accordingly.
Hopefully you can use some of this code to solve your problem.

How to implement dependency object/property on custom class?

Here is my Person Class:
public class Person
{
private string _lastName;
public string LastName
{
get { return _lastName; }
set { _lastName = value; }
}
}//close class
Here is my XAML:
<StackPanel>
<TextBox x:Name="txtLastName"
Height="50" Width="300"
DataContext="{Binding ElementName=_this, Path=PersonObject}"
Text="{Binding Path=LastName}" />
<Button Height="50" Width="100" x:Name="btnChangeValue" Content="Change Value" Click="btnChangeValue_Click"/>
</StackPanel>
Here is my XAML.CS
public partial class ClassDependency : Window
{
public Person objPerson = new Person();
public ClassDependency()
{
objPerson.LastName = "testing...";
InitializeComponent();
}
public Person PersonObject
{
get { return objPerson; }
set { objPerson = value; }
}
private void btnChangeValue_Click(object sender, RoutedEventArgs e)
{
objPerson.LastName = "New value after click....";
}
}//close class
My question is: After clicking "btnChangeValue" it does changing Last Name in my code behind but it is not reflection my textbox "txtLastName". How can I fix this??? Should I implement Dependency Property in my xaml.cs file?? I tried that too but no use.
public static readonly DependencyProperty PersonObjectProperty = DependencyProperty.Register("PersonObject", typeof(object), typeof(ClassDependency));
public Person PersonObject
{
get { return (Person)GetValue(PersonObjectProperty); }
set { SetValue(PersonObjectProperty, value); }
}
What should I do?? Please advice..
Try this:
public class Person : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private string _lastName;
public string LastName
{
get { return _lastName; }
set
{
_lastName = value;
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs("LastName"));
}
}
}
}
This way, the framework gets notified when the property changes. See INotifyPropertyChanged Interface.
The problem with your code is that you are not raising the PropertyChanged event, so the UI is not aware of the value change, on the setter of your dependency properties raise the PropertyChanged event as shown below:
public class Person : INotifyPropertyChanged
{
private string _lastName;
public string LastName
{
get { return _lastName; }
set
{
_lastName = value;
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs("LastName"));
}
}
}
}

WPF MVVM User Control binding problem

I have an wpf mvvm application. I try to write checkbox list control.
I can bind the checkbox list elements.
Added to this issue, I want to get sum of the selected checkbox list elements values.
I added DependencyProperty and bind it to view model property.
But, they dont fire each other.
CheckBoxList User Control Xaml
<ListBox x:Name="ItemsControl" ItemsSource="{Binding}">
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox Content="{Binding Text}" IsChecked="{Binding IsSelected, Mode=TwoWay}"
Checked="CheckBox_Checked" Unchecked="CheckBox_Checked" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
CheckBoxList Code Behind
public partial class CheckBoxList : UserControl
{
public CheckBoxList()
{
InitializeComponent();
}
public static readonly DependencyProperty SelectedCheckBoxItemsValueProperty =
DependencyProperty.Register("SelectedCheckBoxItemsValue", typeof(int), typeof(CheckBoxList),
new FrameworkPropertyMetadata(
0,
new FrameworkPropertyMetadata(0, OnSelectedItemsChanged));
public int SelectedCheckBoxItemsValue
{
get { return (int)GetValue(SelectedCheckBoxItemsValueProperty); }
set { SetValue(SelectedCheckBoxItemsValueProperty, value); }
}
private static int GetSelectedCheckBoxItemsValue(DependencyObject obj)
{
return (int)obj.GetValue(SelectedCheckBoxItemsValueProperty);
}
private static void OnSelectedItemsChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
{
CheckBoxList checkboxList = obj as CheckBoxList;
ObservableCollection<ISelectableItem> items = checkboxList.DataContext as ObservableCollection<ISelectableItem>;
foreach (var item in items)
{
item.IsSelected = (GetSelectedCheckBoxItemsValue(obj) & item.Value) != 0;
}
}
private void CheckBox_Checked(object sender, RoutedEventArgs e)
{
CheckBoxList checkboxList = sender as CheckBoxList;
ObservableCollection<ISelectableItem> coll = ItemsControl.DataContext as ObservableCollection<ISelectableItem>;
if (coll == null) return;
int count = 0;
foreach (var item in coll)
{
if (item.IsSelected)
{
count += item.Value;
}
}
SelectedCheckBoxItemsValue = count;
}
}
SelectableItem Class
public interface ISelectableItem : INotifyPropertyChanged
{
bool IsSelected { get; set; }
string Text { get; set; }
int Value { get; set; }
string GroupName { get; set; }
}
public class SelectableItem : ISelectableItem
{ ....
ViewModel Property
public int SelectedCheckBoxEnumItemsValue
{
get
{
return _selectedCheckBoxEnumItemsValue;
}
set
{
_selectedCheckBoxEnumItemsValue = value;
NotifyOfPropertyChange("SelectedCheckBoxEnumItemsValue");
}
}
At Binder Class
string selectedItemPropertyName = "Selected" + viewModelProperty.Name + "Value";
var property = viewModelProperties.FirstOrDefault(p => p.Name.Contains(selectedItemPropertyName));
if (property != null)
{
var selectedItemOrValueBinding = new Binding(property.Name)
{
Mode = property.CanWrite ? BindingMode.TwoWay : BindingMode.OneWay,
ValidatesOnDataErrors = Attribute.GetCustomAttributes(property, typeof(ValidationAttribute), true).Any()
};
BindingOperations.SetBinding(control, CheckBoxList.SelectedCheckBoxItemsValueProperty, selectedItemOrValueBinding);
}
Below code solves your problem..
Please Note the segrgation of view models.
<StackPanel>
<TextBlock Text="{Binding Count}"></TextBlock>
<ListBox x:Name="ItemsControl" ItemsSource="{Binding CheckList}">
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox Name="item" Content="{Binding Text}" IsChecked="{Binding IsSelected, Mode=TwoWay}" Command="{Binding CheckboxCheckedCommand}" CommandParameter="{Binding IsChecked, ElementName=item}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new MasterViewModel();
}
}
public class MasterViewModel : INotifyPropertyChanged
{
private List<CheckBoxItem> checkList;
private int count;
public int Count
{
get
{
return count;
}
set
{
count = value;
OnPropertyChanged("Count");
}
}
public List<CheckBoxItem> CheckList
{
get
{
return checkList;
}
set
{
checkList = value;
OnPropertyChanged("CheckList");
}
}
public event PropertyChangedEventHandler PropertyChanged;
public MasterViewModel()
{
checkList = new List<CheckBoxItem>();
for (int i = 0; i < 5; i++)
{
CheckBoxItem item = new CheckBoxItem();
item.Text = i.ToString();
item.IsSelected = false;
item.CheckboxCheckedCommand = new RelayCommand(new Action<object>(ExecuteCheckCommand));
checkList.Add(item);
}
}
private void ExecuteCheckCommand(object parameter)
{
if (parameter.GetType() == typeof(bool))
{
bool value = bool.Parse(parameter.ToString());
int val = count;
if (value)
{
val++;
}
else
{
val--;
}
Count = val;
}
}
private void OnPropertyChanged(string p)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(p));
}
}
}
public class CheckBoxItem : INotifyPropertyChanged
{
private bool isSelected;
private string text;
public string Text
{
get
{
return text;
}
set
{
text = value;
OnPropertyChanged("Text");
}
}
public bool IsSelected
{
get
{
return isSelected;
}
set
{
isSelected = value;
OnPropertyChanged("IsSelected");
}
}
public ICommand CheckboxCheckedCommand
{
get;
set;
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string p)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(p));
}
}
}
public class RelayCommand : ICommand
{
private Action<object> executeCommand;
public RelayCommand(Action<object> executeCommand)
{
this.executeCommand = executeCommand;
}
public bool CanExecute(object parameter)
{
return true;
}
public event EventHandler CanExecuteChanged;
public void Execute(object parameter)
{
executeCommand(parameter);
}
}

Resources