I want to pass selected items of listview checkbox in view model, later I will use further process to store in database.
Code in the FormWeek.xaml as
<Window.DataContext>
<Binding Source="{StaticResource Locator}" Path="TaskExecDefModel"></Binding>
</Window.DataContext>
<Window.Resources>
<ResourceDictionary>
<DataTemplate x:Key="ItemDataTemplate">
<CheckBox
x:Name="checkbox"
Content="{Binding}" Command="{Binding CheckBoxCommand}" CommandParameter="{Binding ElementName=checkedListView, Path=SelectedItems}"
IsChecked="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListViewItem}}, Path=IsSelected}" />
</DataTemplate>
</ResourceDictionary>
<StackPanel Grid.Column="1" Grid.Row="3" Margin="5">
<CheckBox x:Name="selectAll" Content="Select all" Click="OnSelectAllChanged"/>
<ListView x:Name="checkedListView" SelectionMode="Multiple" ItemsSource="{Binding CollectionOfDays}" DataContext="{Binding}"
ItemTemplate="{StaticResource ItemDataTemplate}" SelectedValue="WorkingDay"
CheckBox.Unchecked="OnUncheckItem" SelectionChanged="SelectDays" SelectedItem="{Binding SelectedItems}">
</ListView>
</StackPanel>
Code in FormWeek.xaml.cs
private void SelectDays(object sender, SelectionChangedEventArgs e)
{
(this.DataContext as TaskExecDefinitionViewModel).OnCheckBoxCommand(checkedListView.SelectedItems,true);
}
My View Model TaskWeek.cs as follows
//Declaration
private RelayCommand<object> _checkBoxCommand;
public ObservableCollection<string> CollectionOfDays { get; set; }
public ObservableCollection<string> SelectedItems { get; set; }
public RelayCommand<object> CheckBoxCommand
{
get
{
if (_checkBoxCommand == null)
{
_checkBoxCommand = new RelayCommand<object>((args) => OnCheckBoxCommand(args,true));
// _checkBoxCommand = new RelayCommand(() => OnCheckBoxCommand(object args));
}
return _checkBoxCommand;
}
}
//Constructor
CollectionOfDays = new ObservableCollection<string>();
//Method
private void GetWeekDays()
{
try
{
Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action(() =>
{
CollectionOfDays.Add("Saturday");
CollectionOfDays.Add("Sunday");
CollectionOfDays.Add("Monday");
CollectionOfDays.Add("Tuesday");
CollectionOfDays.Add("Wednesday");
CollectionOfDays.Add("Thursday");
CollectionOfDays.Add("Friday");
}));
}
catch(Exception Ex)
{
MessageBox.Show(Ex.Message, "TaskWeek:GetWeekDays");
}
}
public void OnCheckBoxCommand(object obj, bool _direction)
{
try
{
if (SelectedItems == null)
SelectedItems = new ObservableCollection<string>();
if (obj != null)
{
SelectedItems.Clear();
StringBuilder items = new StringBuilder();
if (_direction)
{
foreach (string item in CollectionOfDays)
{
items.AppendFormat(item + ",");
}
}
MessageBox.Show(items.ToString());
}
else
SelectedItems.Clear();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "TaskDefinition:OnCheckBoxCommand");
}
}
And below is button click commond to save the data.
<Button Grid.Column="2" Grid.Row="2" Content="Save" HorizontalAlignment="Center" VerticalAlignment="Bottom"
Command="{Binding InsertExecDefCommand}" Margin="5" >
Now my requirement is to pass selected listview items to view model through command object. I had done this using following code in FormWeek.xam.cs through SelectionChanged event as
private void OnSelectedItems(object sender, RoutedEventArgs e)
{
StringBuilder items = new StringBuilder();
foreach (string item in checkedListView.SelectedItems)
{
items.AppendFormat(item + ",");
}
string AllDays= items.ToString();
}
But please let me know how to achieve this logic through MVVM. How to get selecteditems in my view model TaskWeek.cs
After R&D and google i had done chages through RelayCommand. In OnCheckBoxCommand method foreach statement is wrong it is passing all days. I want to pass only selected listview item. Please suggest me what is wrong in OnCheckBoxCommand method.
Here are my findings;
use this code in code behind of FormWeek.xaml:
private void SelectDays(object sender, SelectionChangedEventArgs e)
{
(this.DataContext as TaskExecDefinitionViewModel).OnCheckBoxCommand(checkedListView.SelectedItems,true);
}
And in 'OnCheckBoxCommand': -
public void OnCheckBoxCommand(object obj, bool _direction)
{
try
{
if (SelectedItems == null) SelectedItems = new ObservableCollection<string>();
if (obj != null)
{
SelectedItems.Clear();
var _list = ((IList)obj).Cast<string>().ToList();
if (_direction)
{
_list.ForEach(item => SelectedItems.Add(item));
}
}
else
SelectedItems.Clear();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "TaskDefinition:OnCheckBoxCommand");
}
}
Have a nice day man.....keep going.
Hi try something like this
<StackPanel Grid.Column="1" Grid.Row="3" Margin="5">
<CheckBox x:Name="selectAll" Content="Select all" Command="{Binding CheckBoxCommand}" CommandParameter="{Binding IsChecked, RelativeSource={RelativeSource Mode=Self}}"/>
<ListView x:Name="checkedListView" SelectionMode="Extended" ItemsSource="{Binding CollectionOfDays}" SelectedItem="{Binding SelectedItems}"/>
</StackPanel>
public class MainViewModel
{
public MainViewModel()
{
CollectionOfDays = new ObservableCollection<string>();
SelectedItems = new ObservableCollection<string>();
CollectionOfDays.Add("Saturday");
CollectionOfDays.Add("Sunday");
CollectionOfDays.Add("Monday");
CollectionOfDays.Add("Tuesday");
CollectionOfDays.Add("Wednesday");
CollectionOfDays.Add("Thursday");
CollectionOfDays.Add("Friday");
}
private CommandHandler _checkBoxCommand;
public CommandHandler CheckBoxCommand
{
get
{
return _checkBoxCommand ?? (_checkBoxCommand=new CommandHandler((param)=>OnCheckBoxCommand(param)));
}
}
public ObservableCollection<string> CollectionOfDays { get; set; }
public ObservableCollection<string> SelectedItems {get;set;}
private void OnCheckBoxCommand(object obj)
{
if (obj is bool)
{
if (SelectedItems == null)
SelectedItems = new ObservableCollection<string>();
if ((bool)obj)
{
SelectedItems.Clear();
foreach (var item in CollectionOfDays)
{
SelectedItems.Add(item);
}
}
else
SelectedItems.Clear();
}
}
}
public MainWindow()
{
InitializeComponent();
DataContext = new MainViewModel();
}
I hope this will give you an idea.
Related
Please find the below code.
public enum SortByType
{
[Display(Name = "Y Value")]
Y_Value,
[Display(Name = "X Value")]
X_Value,
[Display(Name = "Z Value")]
Z_Value,
}
public class ViewModel : INotifyPropertyChanged
{
ObservableCollection<SortByType> sortList;
SortByType selectedType;
public ViewModel()
{
SortList = new ObservableCollection<SortByType>(Enum.GetValues(typeof(SortByType)).OfType<SortByType>().ToList());
}
public ObservableCollection<SortByType> SortList
{
get
{
return sortList;
}
set
{
sortList = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(SortList)));
}
}
public SortByType SelectedType
{
get
{
return selectedType;
}
set
{
selectedType = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(SelectedType)));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
public partial class MainWindow : Window
{
public MainWindow()
{
DataContext = new ViewModel();
(DataContext as ViewModel).SelectedType = SortByType.Y_Value;
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
(DataContext as ViewModel).SortList.Clear();
(DataContext as ViewModel).SortList = new ObservableCollection<SortByType>(Enum.GetValues(typeof(SortByType)).OfType<SortByType>().ToList());
}
}
<Grid>
<StackPanel VerticalAlignment="Center">
<ComboBox ItemsSource="{Binding SortList}"
SelectedItem="{Binding SelectedType}">
<ComboBox.ItemTemplate>
<DataTemplate>
<Label Content="{Binding}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<Button Height="25" Width="150" Content="Details" Click="Button_Click"/>
</StackPanel>
</Grid>
Just, Clear the collection and re-initialize the combo box item source on button click event. On this time I have noticed that the Data error shown on the combo box. Can anyone explain what is the exact problem whether it may be a memory issue or some thing i have missed while implement the Item Template
The value of SelectedType must be present in the source collection. It's not when you assign the source property to a new list of new values, unless you set explicitly set it to any of these new values:
private void Button_Click(object sender, RoutedEventArgs e)
{
var viewModel = DataContext as Win32ViewModel;
viewModel.SortList = new ObservableCollection<SortByType>(Enum.GetValues(typeof(SortByType)).OfType<SortByType>().ToList());
viewModel.SelectedType = viewModel.SortList.FirstOrDefault(x => x == viewModel.SelectedType);
}
My Problem, I can't remove list in my listbox from browser, but when i debug in my code data list has removed.
View Model
private List<Customer> _listCustomer = new List<Customer>();
public List<Customers> ListCustomers
{
get { return _listCustomers; }
set { _listCustomers = value; OnPropertyChanged("ListCustomers"); }
}
private ICommand _removeCommand;
public ICommand RemoveCommand
{
get { return _removeCommand ?? (_removeCommand = new RelayCommand(param => ButtonRemoveCustomer(), null)); }
set { OnPropertyChanged("ListCustomers"); }
}
private void ButtonRemoveCustomer()
{
ListCustomers.Remove(this.SelectCustomer);
this.SelectCustomer = null;
}
My View
<Intersoft:UXListBox x:Name="CustData" Width="200" MaxHeight="500" SelectedItem="{Binding SelectCustomer, Mode=TwoWay}"
ItemsSource="{Binding ListCustomers, Mode=TwoWay}" ItemTemplate="{StaticResource DataListTemplate}"
VerticalScrollBarVisibility ="Visible" HorizontalScrollBarVisibility="Visible"/>
<Intersoft:UXButton Content="Remove List" Command="{Binding RemoveCommand, Mode=TwoWay}" Width="100"/>
How to fix my code ??
private void ButtonRemoveCustomer()
{
ListCustomers.Remove(this.SelectCustomer);
OnPropertyChanged("ListCustomers");
this.SelectCustomer=null;
}
I have items stored in the ItemSource property of a combobox, however, when the user types in a name that does not exist in the list I need it to create a new object and use that as the SelectedObject. I am pretty new to WPF and used to WindowsForms, so I might just be going about doing this the totally wrong way, any input is appreciated.
Xaml:
<Window x:Class="ComboExample.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">
<StackPanel>
<ComboBox x:Name="cboName" IsEditable="True" SelectionChanged="ComboBox_SelectionChanged"></ComboBox>
<DockPanel>
<Label>Selected Value</Label>
<TextBox Text="{Binding Name}"></TextBox>
</DockPanel>
<Button Click="Button_Click">Click Me</Button>
</StackPanel>
and code behind (which displays "value is null" if you type a new value in
class SomeClass
{
public SomeClass(string name) {this.Name = name;}
public string Name { get; set; }
}
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
cboName.ItemsSource = new SomeClass[] { new SomeClass("A"), new SomeClass("B") };
cboName.DisplayMemberPath = "Name";
cboName.SelectedItem = cboName.ItemsSource.OfType<SomeClass>().FirstOrDefault();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
SomeClass value = cboName.SelectedValue as SomeClass;
if (value == null)
MessageBox.Show("No item is selected.");
else
MessageBox.Show("An item is selected.");
}
SomeClass empty = new SomeClass("");
private void ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
DataContext = cboName.SelectedItem as SomeClass;
if (DataContext == null)
cboName.SelectedValue = DataContext = empty;
}
}
here one way to do it:
<StackPanel>
<ComboBox x:Name="cboName" ItemsSource="{Binding ComboBoxItems}" DisplayMemberPath="Name" SelectedItem="{Binding ComboBoxItems[0],Mode=OneTime}" IsEditable="True"/>
<DockPanel>
<Label>Selected Value</Label>
<TextBox Text="{Binding SelectedItem.Name,ElementName=cboName}"></TextBox>
</DockPanel>
<Button Click="Button_Click">Click Me</Button>
</StackPanel>
and the code behind :
public partial class MainWindow : Window
{
private ObservableCollection<SomeClass> _comboBoxItems;
public ObservableCollection<SomeClass> ComboBoxItems
{
get
{
return _comboBoxItems;
}
set
{
_comboBoxItems = value;
}
}
public MainWindow()
{
InitializeComponent();
this.DataContext = this;
ComboBoxItems = new ObservableCollection<SomeClass>()
{
new SomeClass("First Name"),
new SomeClass("Second Name"),
new SomeClass("Third Name")
};
}
private void Button_Click(object sender, RoutedEventArgs e)
{
if (!ComboBoxItems.Any(x => x.Name == cboName.Text))
{
ComboBoxItems.Add(new SomeClass(cboName.Text));
}
}
}
public class SomeClass
{
public SomeClass(string name) { this.Name = name; }
public string Name { get; set; }
}
To better manage your objects you may consider
defining a new property For the Selected ComboBox Item (Of Type SomeClass), and bind it to the ComboBox SelectedItem,
Use ObservableCollection instead of just list and Implement the INotifyPropertyChanges Interface.
I should load images to listbox.I have a trouble when I choose images, to listbox added only border without nothing and only one, I have debuged my code and in collection 6 bitmap images, but loaded only 1 border.
1.That is my class Album:
public class Album : INotifyPropertyChanged
{
private string name;
public string Name
{
get { return name; }
set
{
name = value;
OnPropertyChanged(new PropertyChangedEventArgs("Name"));
}
}
private string description;
public string Description
{
get
{
return description;
}
set
{
description = value;
OnPropertyChanged(new PropertyChangedEventArgs("Description"));
}
}
private List<BitmapImage> images;
public List<BitmapImage> Images
{
get
{
return images;
}
set
{
images = value;
OnPropertyChanged(new PropertyChangedEventArgs("Images"));
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(PropertyChangedEventArgs e)
{
if (PropertyChanged != null)
PropertyChanged(this, e);
}
public Album() { }
public Album(string name, string description, List<BitmapImage> files)
{
Name = name;
Description = description;
Images = files;
}
}
2.That my code for child window.When i push button create, I write name, description, and add some photos(please check my method for add is it correct).
public partial class DialogCreate : ChildWindow
{
private List<BitmapImage> temps = new List<BitmapImage>();
private string tempName;
private string tempDescription;
public List<BitmapImage> Temps
{
get { return temps; }
set { temps = value; }
}
public string TempName
{
get { return tempName; }
set { tempName = value; }
}
public string TempDescription
{
get { return tempDescription; }
set { tempDescription = value; }
}
private OpenFileDialog addPhoto;
public DialogCreate()
{
InitializeComponent();
addPhoto = new OpenFileDialog();
addPhoto.Multiselect = true;
addPhoto.Filter = "Image files(*.BMP;*.JPG;*.GIF)|*.BMP;*.JPG;*.GIF|All files (*.*)|*.*";
}
private void OKButton_Click(object sender, RoutedEventArgs e)
{
tempName = txtGetName.Text;
tempDescription = txtGetDescription.Text;
this.DialogResult = true;
}
private void CancelButton_Click(object sender, RoutedEventArgs e)
{
this.DialogResult = false;
}
private void AddButton_Click(object sender, RoutedEventArgs e)
{
bool result = (bool)addPhoto.ShowDialog();
if (!result)
return;
IEnumerable<FileInfo> file = addPhoto.Files;
foreach (FileInfo files in file)
{
Stream s = files.OpenRead();
BitmapImage i = new BitmapImage();
i.SetSource(s);
temps.Add(i);
}
}
}
3.After that I return to:
private void CreateButton_Click(object sender, RoutedEventArgs e)
{
dialogAlbum = new DialogCreate();
dialogAlbum.Show();
dialogAlbum.Closed += delegate
{
albums.Add(new Album(dialogAlbum.TempName, dialogAlbum.TempDescription, dialogAlbum.Temps));
AlbumScroll.ItemsSource = albums;
lsPhoto.ItemsSource = albums;
};
}
4.That my xaml:
<ListBox Style="{StaticResource ListBoxStyle}" ItemsSource="{Binding Images}" Margin="121,38,171,23" x:Name="lsPhoto" Grid.Column="1" Grid.Row="2" Height="144" Width="600">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<Border Width="100" Height="100">
<Image x:Name="listPhotos" Source="{Binding}" Width="Auto" Height="Auto"/>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Please help me, what I did wrong?Or give your advertise.
I created a new class something like this
public class ImageInformation:INotifyPropertyChanged
{
public string Name { get; set; }
public BitmapImage ImageInfo { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(PropertyChangedEventArgs e)
{
if (PropertyChanged != null)
PropertyChanged(this, e);
}
}
I replaced all the places where you use BitmapImage and in mainpage.xaml
<ListBox x:Name="lsPhoto" Grid.RowSpan="2">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Height="25" Width="25">
<Image Height="25" Width="25" Source="{Binding ImageInfo}"></Image>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
With these two changes and other impacted changes, my Listbox shows the image that was selected by the user. If you need the solution i tried, send me a mail.
I have a treeview which shows a hierarchy of items where each item has a checkbox. I would like to show below the treeview a listbox with all the checked items. How to achieve such functionality using MVVM pattern?
Thanks in advance
Lukasz Glaz
Here's an example:
ViewModel
public class TreeNodeViewModel : ViewModelBase
{
#region Constructors
public TreeNodeViewModel(string text, params TreeNodeViewModel[] nodes)
: this(text, new ObservableCollection<TreeNodeViewModel>(nodes))
{
}
public TreeNodeViewModel(string text, ObservableCollection<TreeNodeViewModel> nodes)
{
Text = text;
Nodes = nodes;
foreach (var node in Nodes)
{
node.Parent = this;
}
Nodes.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(Nodes_CollectionChanged);
}
#endregion
#region Private methods
private void Nodes_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
foreach (var node in e.OldItems.Cast<TreeNodeViewModel>())
{
node.Parent = null;
}
foreach (var node in e.NewItems.Cast<TreeNodeViewModel>())
{
node.Parent = this;
}
OnPropertyChanged("CheckedNodes");
}
private void NotifyParent()
{
if (Parent != null)
{
Parent.OnPropertyChanged("CheckedNodes");
Parent.NotifyParent();
}
}
#endregion
#region Private data
private string _text;
private bool _isChecked;
private TreeNodeViewModel _parent;
#endregion
#region Public properties
public string Text
{
get { return _text; }
set
{
if (value != _text)
{
_text = value;
OnPropertyChanged("Text");
}
}
}
public bool IsChecked
{
get { return _isChecked; }
set
{
if (value != _isChecked)
{
_isChecked = value;
NotifyParent();
OnPropertyChanged("IsChecked");
}
}
}
public ObservableCollection<TreeNodeViewModel> Nodes { get; private set; }
public IEnumerable<TreeNodeViewModel> CheckedNodes
{
get
{
foreach (var node in Nodes)
{
if (node.IsChecked)
yield return node;
foreach (var child in node.CheckedNodes)
{
yield return child;
}
}
}
}
public TreeNodeViewModel Parent
{
get { return _parent; }
private set
{
if (value != _parent)
{
_parent = value;
OnPropertyChanged("Parent");
}
}
}
#endregion
}
XAML
<TreeView Grid.Row="0" ItemsSource="{Binding Nodes}">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Nodes}">
<StackPanel Orientation="Horizontal">
<CheckBox IsChecked="{Binding IsChecked}" />
<TextBlock Text="{Binding Text}" />
</StackPanel>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
<ListBox Grid.Row="1" ItemsSource="{Binding CheckedNodes}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Text}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Code-behind
this.DataContext = new TreeNodeViewModel(
null,
new TreeNodeViewModel(
"1",
new TreeNodeViewModel(
"1.1",
new TreeNodeViewModel("1.1.1"),
new TreeNodeViewModel("1.1.2")),
new TreeNodeViewModel("1.2")),
new TreeNodeViewModel(
"2",
new TreeNodeViewModel("2.1"),
new TreeNodeViewModel(
"2.2",
new TreeNodeViewModel("2.2.1"))));
Note that it is a rather naive implementation, it could easily be improved... For instance, the whole list of checked nodes is reevaluated every time a node is checked/unchecked, which could lead to bad performance for a big TreeView