How can I toggle component in datatemplate, when I select an item? - c#

I have a CollectionView in my page, which displays items. I need to toggle visual indicator (checkmark), that item is selected. The checkmark should be stylized, but I haven't done it, I only tried with BoxView. Nothing reasonable seems to work.
I have tried setting a flag in my Model if item is selected and then reload collection, but this is a very bad approach, that also consumes a lot of resources. I just need a toggle, that will appear on item click and dissappear on second one.
<Label Text="{Binding price, Converter={StaticResource Price}}" Style="{StaticResource PriceLabel}" Grid.Row="0" Grid.ColumnSpan="2"/>
<Label Text="{Binding name}" Style="{StaticResource CommonLabel}" VerticalTextAlignment="Center" Grid.Row="1" Grid.ColumnSpan="2"/>
<!-- Somehow change this-->
<BoxView BackgroundColor="Blue" Grid.Row="0" Grid.Column="1"/>
Disired result should look like this but that's another part of the story

According to your description, if you want to BoxView to display selected or unselected for Collectionview item, I suggest you can use one property to bind BoxView IsVisible, I do one sample that you can take a look:
Model:
public class Model:ViewModelBase
{
private string _DisplayName;
public string DisplayName
{
get { return _DisplayName; }
set
{
_DisplayName = value;
RaisePropertyChanged("DisplayName");
}
}
private bool _selected;
public bool Selected
{
get { return _selected; }
set
{
_selected = value;
RaisePropertyChanged("Selected");
}
}
}
ViewModel:
public class collectionviewmodel:ViewModelBase
{
public ObservableCollection<Model> Items { get; set; }
public collectionviewmodel()
{
Items = new ObservableCollection<Model>();
Items.Add(new Model() { DisplayName = "AAA", Selected = false });
Items.Add(new Model() { DisplayName = "BBB", Selected = false });
Items.Add(new Model() { DisplayName = "CCC", Selected = false });
Items.Add(new Model() { DisplayName = "DDD", Selected = false });
Items.Add(new Model() { DisplayName = "EEE", Selected = false });
}
}
ContentPage:
<CollectionView
x:Name="list1"
ItemsLayout="VerticalList"
ItemsSource="{Binding Items}"
SelectionChanged="List1_SelectionChanged"
SelectionMode="Single">
<CollectionView.ItemTemplate>
<DataTemplate>
<StackLayout Orientation="Horizontal">
<Label
HorizontalOptions="StartAndExpand"
Text="{Binding DisplayName}"
TextColor="Fuchsia" />
<BoxView
HorizontalOptions="End"
IsVisible="{Binding Selected}"
Color="Fuchsia" />
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
public Page23 ()
{
InitializeComponent ();
this.BindingContext = new collectionviewmodel();
}
The screenshot like this:

What I did understand
you are trying to display an indicator on an item when it's selected, and only one item can be selected at the same time
So you need to set the SelectionMode to Single in your CollectionView, so only one item can be selected at a time
then you can display the indicator on the selected item and hide it on the previous one using OnCollectionViewSelectionChanged
you can find more details here Xamarin-Collectionview-Selection

Related

Maui Listview grouping

I have a list which consists of around 100 object. Each object has 2 properties (name, punch_time). The class is as follows:
public class Trxs
{
public string punch_time { get; set; }
public string name { get; set;}
}
the list name is (Punch_Times):
List<Trxs> Punch_times = new List<Trxs>();
It is a finger-print machine transactions. I want to populate a list view in Maui, so that the data will be grouped based on the name, as below:
It should show like this
I Tried the following grouping of the list, It showed the list grouped but without the group name. The listview name is (Trx_List):
var sorted = Punch_times.GroupBy(x => x.name)
.Select(grp => grp.ToList())
.ToList();
Trx_List.ItemsSource = sorted ;
the result showed like this (the group names are empty):
But it is showing like this
I have created a class to represent to new list, which will be the item source of the Trx_List as follows:
public class Grouped_list
{
public string emp_name { get; set; }
public List<Trxs> trxes { get; set; }
}
And created a new list:
List<Grouped_list> new_list = new List<Grouped_list>();
but how to copy the items from (sorted) to (new_list). Or is it needed? how to make item source of the list view grouped by name?
Any help please!
Thank you
To be frank, I recommend to use CollectionView instead of ListView. There is a known issue about iOS GroupHeaderTemplate :ListView GroupHeaderTemplate produces blank headers on iOS and MacCatalyst. It just render a blank headers. That's why i recommend to use CollectionView. The usage is almost the same. You could refer to Display grouped data in a CollectionView.
For your case, how to reflect sorted to new_list really matters. I made a small demo following the official documentation based on your code.
For MainPageViewModel.cs,
public class MainPageViewModel
{
public List<Trxs> Punch_times { get; set; } = new List<Trxs>();
public List<Grouped_list> new_list { get; set; } = new List<Grouped_list>();
public MainPageViewModel()
{
//Add some data for test
Punch_times.Add(new Trxs
{
name = "John",
punch_time = "13:33"
});
......
// translate list to dict (key is name)
var dict = Punch_times.GroupBy(o => o.name)
.ToDictionary(g => g.Key, g => g.ToList());
foreach (KeyValuePair<string, List<Trxs>> item in dict)
{
new_list.Add(new Grouped_list(item.Key,new List<Trxs>(item.Value)));
}
}
}
For Grouped_list.cs,
public class Grouped_list : List<Trxs>
{
public string Name { get; set; }
public Grouped_list(string name, List<Trxs> trxs) : base(trxs)
{
Name = name;
}
}
For MainPage.xaml which consumes the ListView or CollectionView,
<CollectionView ItemsSource="{Binding new_list}"
IsGrouped="True">
<CollectionView.GroupHeaderTemplate>
<DataTemplate>
<StackLayout>
<Label Text="{Binding Name}" TextColor="Black" VerticalOptions="CenterAndExpand"
BackgroundColor="LightGray"
FontSize="20"
FontAttributes="Bold" />
</StackLayout>
</DataTemplate>
</CollectionView.GroupHeaderTemplate>
<CollectionView.ItemTemplate>
<DataTemplate>
<StackLayout>
<Label Text="{Binding punch_time}" BackgroundColor="Yellow"
FontSize="20" HorizontalTextAlignment="Center"
VerticalOptions="CenterAndExpand" HorizontalOptions="CenterAndExpand"/>
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
or you may use ListView but not render correctly on iOS as i mention above.
<ListView ItemsSource="{Binding new_list}"
IsGroupingEnabled="True">
<ListView.GroupHeaderTemplate>
<DataTemplate>
<ViewCell>
<Label Text="{Binding Name}" TextColor="Black" VerticalOptions="CenterAndExpand"
BackgroundColor="LightGray"
FontSize="20"
FontAttributes="Bold" />
</ViewCell>
</DataTemplate>
</ListView.GroupHeaderTemplate>
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout>
<Label Text="{Binding punch_time}" BackgroundColor="Yellow"
FontSize="20" HorizontalTextAlignment="Center"
VerticalOptions="CenterAndExpand" HorizontalOptions="CenterAndExpand"/>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
For more info, you could refer to ListView : Display grouped data and Display grouped data in a CollectionView
Hope it works for you.
public class Grouped_list : List<Trxs>
{
public string emp_name { get; set; }
public Grouped_list(string name, List<Trxs> list) : base(list)
{
emp_name = name;
}
}
You need something like that.
And then your observable is:
public ObservableCollection<Grouped_list> GroupedLists...
Set it as ItemSource, and don't forget to set IsGrouped to true.
In the GroupHeaderTemplate there should be binding to emp_name.
And its DataType should be Grouped_list.
Also, It is EmpName, not emp_name. And GroupedList not Grouped_list.
Follow the naming conventions.

C# WPF How can I edit the values in a collection presented in a ListView / Textbox

I have a list view that displays the EditCollection property stored in a viewmodel which is of type ObservableCollection. It displays each element as a textbox with the string as its text so I can edit the string of each element. There is an Add button that adds an element whose handler is AddToCollection. There is also a Save button. When it is clicked, EditCollection should be copied into another ObservableCollection property called Collection. But what actually happens is that any added elements are shown, but their edited values do not appear in EditCollection, only their default values.
private ObservableCollection<string> _editCollection;
public ObservableCollection<string> EditCollection
{
get { return _editCollection; }
set
{
_editCollection = value;
OnPropertyChanged("EditCollection");
}
}
private ObservableCollection<string> _collection;
public ObservableCollection<string> Collection
{
get { return _collection; }
set
{
_collection = value;
_editCollection = new ObservableCollection<string>(_collection);
OnPropertyChanged("Collection");
OnPropertyChanged("EditCollection");
}
}
public void Save(object item)
{
string value;
if (EditCollection.Count > 1)
{
value = EditCollection[1];
}
; // break point: value = "default value" even if I edit the textbox
Collection = new ObservableCollection<string>(new List<string>( EditCollection ));
}
public void AddToCollection(object item)
{
EditCollection.Add("default value");
OnPropertyChanged("EditCollection");
}
view.xaml
<Button Content="Save" Width="50" HorizontalAlignment="Right"
Command="{Binding SaveCommand}"/>
<ListView Grid.Row="1" ItemsSource="{Binding Path=EditCollection}">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBox Text="{Binding Path=.,
UpdateSourceTrigger=PropertyChanged}"/>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<Button Grid.Row="2" Content="Add" Width="50" HorizontalAlignment="Center"
Command="{Binding AddToCollectionCommand}"/>
The way to do this is bind to a class instead of the string directly.
private ObservableCollection<Item> _editCollection;
public ObservableCollection<Item> EditCollection
{
get { return _editCollection; }
set
{
_editCollection = value;
OnPropertyChanged("EditCollection");
}
}
public class Item : INotifyPropertyChanged
{
private string _text;
public string Text
{ get { return _text; }
set{ _text = value; OnPropertyChanged("Text");
}
}
<ListView Grid.Row="1" ItemsSource="{Binding Path=EditCollection}">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBox Text="{Binding Path=Text,
UpdateSourceTrigger=PropertyChanged}"/>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>

Xamarin.Forms How to two-way bind to a control in Listview

Im having a hard time trying to figure out how to set up a two-way binding for a control inside a listview.
Im using ReactiveUI and Xamarin.Forms.
In this case i would like to load a list of objects that have a quantity. This is set initially when the page loads. However i would like to be able to change these quantity values in the view when the program is run. I used an Entry for that.
Setting up a two-way Binding for the List itself (done in code behind, the reactive way) is not possible. It will error.
Is there another way to observe changes done to the Text property in the Entry control and reflect them to the according item from the list in my viewmodel?
I've been having trouble finding a solution for this and don't really know how to go about this.
Here is my XAML code:
<CustomControls:AutoLoadListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Margin="20,0,0,0" Orientation="Vertical" HorizontalOptions="StartAndExpand">
<Label Margin="0,5,0,-5" Style="{StaticResource ViewCellPrimaryLabelStyle}" x:Name="txt" Text="{Binding itemname}" />
<Label Margin="0,-5,0,5" Style="{StaticResource ViewCellSecondaryLabelStyle}" x:Name="barcode" Text="{Binding productcode}" />
</StackLayout>
<Entry Margin="5,0,5,0" x:Name="quantity" Text="{Binding quantity}">
<Entry.BindingContext>
<ViewModel:AankoopEditViewModel />
</Entry.BindingContext>
</Entry>
<Image Margin="5,5,5,5" x:Name="delete" Source="{Mobile:ImageResource tbin_pos.png}">
<Image.GestureRecognizers>
<TapGestureRecognizer
Command="{Binding Path=BindingContext.DeleteCommand,Source={x:Reference Name=AankoopEditPage}}"
CommandParameter="{Binding}" />
</Image.GestureRecognizers>
</Image>
</ViewCell>
</DataTemplate>
</CustomControls:AutoLoadListView.ItemTemplate>
My Viewmodel:
public class AankoopEditViewModel : BaseViewModel
{
private VmPurchase Purchase;
public AankoopEditViewModel()
{
PurchaseList = new ReactiveObservableCollection<AankoopEditListItem>()
{
ChangeTrackingEnabled = true
};
this.WhenAnyValue(x => x.PurchaseID).SubscribeOn(RxApp.MainThreadScheduler).Subscribe((x) =>
{
this.Purchase = DatabaseHelper.Purchase.LoadSingleById<VmPurchase>(PurchaseID);
if (Purchase != null)
{
this.Title = Purchase.supplier.name;
using (PurchaseList.SuppressChangeNotifications())
{
foreach (var detail in Purchase.purchasedetails)
{
PurchaseList.Add(new AankoopEditListItem { productcode = detail.item.code, itemname = detail.item.namenl, identifier = detail.key, quantity = detail.quantity.ToString() });
}
}
}
});
try
{
this.WhenAnyValue(x => x.PurchaseList).SubscribeOn(RxApp.MainThreadScheduler).Subscribe((x) =>
{
Console.WriteLine("The List has changed");
});
}
catch (Exception e)
{
return;
}
}
private string _purchaseID;
public string PurchaseID
{
get { return _purchaseID; }
set { this.RaiseAndSetIfChanged(ref _purchaseID, value); }
}
private ReactiveObservableCollection<AankoopEditListItem> _purchases;
public ReactiveObservableCollection<AankoopEditListItem> PurchaseList
{
get
{
return this._purchases;
}
set
{
this.RaiseAndSetIfChanged(ref _purchases, value);
}
}
My Model :
public class AankoopEditListItem : ReactiveObject
{
public string identifier { get; set; }
public string itemname { get; set; }
public string productcode { get; set; }
public string quantity { get; set; }
}
Be careful, when you do this
<Entry.BindingContext>
<ViewModel:AankoopEditViewModel />
</Entry.BindingContext>
you create a new instance of your view model for each item and you bind your Entry to it. Just remove it and keep the binding as it is (Text="{Binding quantity}") if you want to bind your entry to the row view model

Picker not showing value in ContentView in ViewCell

This question is very similar to Picker not showing value in Xamarin.Forms on Windows Phone and UWP however there are some different aspects to this issue. Also the workaround selected as an answer to that question does not work in this case.
I have a ListView with an ItemTemplate that contains a ContentView. The ContentView contains a bindable picker. When the picker is selected the selected value is not displayed. This is an obvious bug because (1) you can resize the window and the value will appear and (2) this problem only occurs on UWP...iOS and Android versions are fine.
Here is the simplified issue. First the main window XAML...
<StackLayout Padding="10,40">
<Label>First List</Label>
<ListView Margin="20" x:Name="listView1" ItemsSource="{Binding ItemContexts}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<local:ContentView1
QuantityRows="{Binding Source={x:Reference listView1}, Path=BindingContext.QuantityRows}"
/>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<Label>Second List</Label>
<ListView Margin="20" x:Name="listView2" ItemsSource="{Binding ItemContexts}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Horizontal">
<Picker x:Name="quantity" ItemsSource="{Binding Source={x:Reference listView2}, Path=BindingContext.QuantityView}" ItemDisplayBinding="{Binding FullName}"
SelectedItem="{Binding QuantityRow, Converter={StaticResource QuantityValueConverter}}"
WidthRequest="200">
</Picker>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<Label>End</Label>
</StackLayout>
There are two list views. The second one works fine and the first one illustrates the problem.
Here is the XAML for the content view...
<ContentView xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="XamarinFormsBench.ContentView1" x:Name="contextView1">
<ContentView.Content>
<StackLayout Orientation="Horizontal">
<Picker x:Name="quantity" ItemsSource="{Binding Source={x:Reference contextView1}, Path=QuantityRows}" ItemDisplayBinding="{Binding Name}"
SelectedItem="{Binding QuantityRow}"
WidthRequest="200">
</Picker>
</StackLayout>
</ContentView.Content>
</ContentView>
Code behind for content view...
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class ContentView1 : ContentView
{
public static BindableProperty QuantityRowsProperty = BindableProperty.Create("QuantityRows", typeof(ObservableCollection<QuantityRow>), typeof(SummaryDetailView), null, BindingMode.TwoWay, null);
public ObservableCollection<QuantityRow> QuantityRows
{
get
{
return GetValue(QuantityRowsProperty) as ObservableCollection<QuantityRow>;
}
set
{
SetValue(QuantityRowsProperty, value);
}
}
public ContentView1 ()
{
InitializeComponent ();
}
}
}
Finally here is the view model...
public class QuantityRow
{
public int ID { get; set; }
public string Name { get; set; }
}
public class ViewModel : INotifyPropertyChanged
{
public ViewModel()
{
QuantityRows = new ObservableCollection<QuantityRow>();
QuantityRows.Add(new QuantityRow() { ID = 1, Name = "Length" });
QuantityRows.Add(new QuantityRow() { ID = 2, Name = "Diameter" });
QuantityRows.Add(new QuantityRow() { ID = 3, Name = "Temperature" });
QuantityRows.Add(new QuantityRow() { ID = 4, Name = "Pressure" });
QuantityRows.Add(new QuantityRow() { ID = 5, Name = "Angle" });
}
public ObservableCollection<QuantityRow> QuantityRows { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
}
}
I am using Xamarin Forms 2.3.4.247 which is the last stable release as of this writing. I tried the latest pre-release which might fix the problem..it is impossible to say because it created a host of other issues.
I've tried invalidating the layout of the content view when the picker's selected index changes, but again, this seems to fix the one problem and create a host of other problems.
So it seems that this will be fixed in the next stable release of Xamarin Forms. What I need now is an effective workaround so I can work with what I have.
I have tested your code and reproduced your issue. The problem is that your BindingContext of ContentView1 has never been set value. And this design is inconsequent, although it can work in the ios and andriod. For your requirement, you could realize it via custom ViewCell.
<ViewCell xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="XamarinPickerTest.CustomViewCell">
<ViewCell.View>
<StackLayout>
<Picker x:Name="quantity" ItemsSource="{Binding QuantityRows}"
ItemDisplayBinding="{Binding Name}"
SelectedItem="{Binding SelectedQuantityRow}"
WidthRequest="200">
</Picker>
</StackLayout>
</ViewCell.View>
</ViewCell>
ViewModel.cs
public class ViewModel : ViewModelBase
{
public ViewModel()
{
QuantityRows = new ObservableCollection<QuantityRow>();
QuantityRows.Add(new QuantityRow() { ID = 1, Name = "Length" });
QuantityRows.Add(new QuantityRow() { ID = 2, Name = "Diameter" });
QuantityRows.Add(new QuantityRow() { ID = 3, Name = "Temperature" });
QuantityRows.Add(new QuantityRow() { ID = 4, Name = "Pressure" });
QuantityRows.Add(new QuantityRow() { ID = 5, Name = "Angle" });
}
private ObservableCollection<QuantityRow> quantityRows;
public ObservableCollection<QuantityRow> QuantityRows
{
get
{
return quantityRows;
}
set
{
quantityRows = value;
OnPropertyChanged();
}
}
private QuantityRow selectedQuantityRow;
public QuantityRow SelectedQuantityRow
{
get { return selectedQuantityRow; }
set
{
if (selectedQuantityRow != value)
{
selectedQuantityRow = value;
OnPropertyChanged();
}
}
}
}
public class QuantityRow : ViewModelBase
{
public int ID { get; set; }
public string Name { get; set; }
}
Usage
<ListView Margin="20" x:Name="listView1" ItemsSource="{Binding ItemContexts}" >
<ListView.ItemTemplate>
<DataTemplate>
<local:CustomViewCell/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
And the above solution works well in ios and android.

WPF MVVM moving a UserControl from one ObservableCollection to another by event

I have a checklist view that has 2 ScrollViewers. One checklist is for incomplete items, the other is for complete items. They are populated by 2 separate observable collections and bound to by ItemsControls.
The UserControl has a button, when clicked will move that 'check' to the other collection.
Currently the way I have this setup is in the ViewModel that's the DataContext for the UserControl there is a public event that is subscribed to by the main window's VM by using:
((CheckItemVM) ((CheckListItem) cli).DataContext).CompleteChanged += OnCompleteChanged;
where cli is the checklist item.
then the OnCompleteChanged finds the appropriate View object by using:
foreach (object aCheck in Checks)
{
if (aCheck.GetType() != typeof (CheckListItem)) continue;
if (((CheckListItem) aCheck).DataContext == (CheckItemVM) sender)
{
cliToMove = (CheckListItem) aCheck;
break;
}
}
It's pretty obvious this breaks MVVM and I'm looking for a way around it (CheckListItem is the View, and CheckItemVM is it's DataContext ViewModel). Reasoning for the boxed type is I've got another UserControl that will have instances inside both, which are basically section labels, and I need to be able to sort my observable collections where there is an association between the checklistitem to a specific section by name.
This can be done in MVVM using commands, and bindings....
The idea that I propouse here is to create a command in the Windows view model, that manage the check command, and this command to receive the item view model in the params, then manage the the things in the command. I'm going to show you a simple example, using MvvmLight library:
The model:
public class ItemViewModel : ViewModelBase
{
#region Name
public const string NamePropertyName = "Name";
private string _name = null;
public string Name
{
get
{
return _name;
}
set
{
if (_name == value)
{
return;
}
RaisePropertyChanging(NamePropertyName);
_name = value;
RaisePropertyChanged(NamePropertyName);
}
}
#endregion
#region IsChecked
public const string IsCheckedPropertyName = "IsChecked";
private bool _myIsChecked = false;
public bool IsChecked
{
get
{
return _myIsChecked;
}
set
{
if (_myIsChecked == value)
{
return;
}
RaisePropertyChanging(IsCheckedPropertyName);
_myIsChecked = value;
RaisePropertyChanged(IsCheckedPropertyName);
}
}
#endregion
}
A simple model with two property, one for the name (an identifier) and another for the check status.
Now in the Main View Model, (or Windows view model like you want)....
First the Collections, one for the checked items, and another for the unchecked items:
#region UncheckedItems
private ObservableCollection<ItemViewModel> _UncheckedItems;
public ObservableCollection<ItemViewModel> UncheckedItems
{
get { return _UncheckedItems ?? (_UncheckedItems = GetAllUncheckedItems()); }
}
private ObservableCollection<ItemViewModel> GetAllUncheckedItems()
{
var toRet = new ObservableCollection<ItemViewModel>();
foreach (var i in Enumerable.Range(1,10))
{
toRet.Add(new ItemViewModel {Name = string.Format("Name-{0}", i), IsChecked = false});
}
return toRet;
}
#endregion
#region CheckedItems
private ObservableCollection<ItemViewModel> _CheckedItems;
public ObservableCollection<ItemViewModel> CheckedItems
{
get { return _CheckedItems ?? (_CheckedItems = GetAllCheckedItems()); }
}
private ObservableCollection<ItemViewModel> GetAllCheckedItems()
{
var toRet = new ObservableCollection<ItemViewModel>();
foreach (var i in Enumerable.Range(11, 20))
{
toRet.Add(new ItemViewModel { Name = string.Format("Name-{0}", i), IsChecked = true });
}
return toRet;
}
#endregion
And the command:
#region CheckItem
private RelayCommand<ItemViewModel> _CheckItemCommand;
public RelayCommand<ItemViewModel> CheckItemCommand
{
get { return _CheckItemCommand ?? (_CheckItemCommand = new RelayCommand<ItemViewModel>(ExecuteCheckItemCommand, CanExecuteCheckItemCommand)); }
}
private void ExecuteCheckItemCommand(ItemViewModel item)
{
//ComandCode
item.IsChecked = true;
UncheckedItems.Remove(item);
CheckedItems.Add(item);
}
private bool CanExecuteCheckItemCommand(ItemViewModel item)
{
return true;
}
#endregion
The magic here could be in the Data binding, in this case I used command parameter and the FindAncestor binding, check the Data Template:
<DataTemplate x:Key="UncheckedItemDataTemplate">
<Grid>
<StackPanel Orientation="Horizontal">
<TextBlock HorizontalAlignment="Left" TextWrapping="Wrap" Text="{Binding Name}" VerticalAlignment="Top"/>
<CheckBox HorizontalAlignment="Left" VerticalAlignment="Top" IsChecked="{Binding IsChecked}" IsEnabled="False"/>
<Button Content="Check" Width="75" Command="{Binding DataContext.CheckItemCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:MainWindow}}}" CommandParameter="{Binding Mode=OneWay}"/>
</StackPanel>
</Grid>
</DataTemplate>
<DataTemplate x:Key="CheckedItemDataTemplate">
<Grid>
<StackPanel Orientation="Horizontal">
<TextBlock HorizontalAlignment="Left" TextWrapping="Wrap" Text="{Binding Name}" VerticalAlignment="Top"/>
<CheckBox HorizontalAlignment="Left" VerticalAlignment="Top" IsChecked="{Binding IsChecked}" IsEnabled="False"/>
</StackPanel>
</Grid>
</DataTemplate>
One data template for checked items, and another for unchecked items. Now the usage, this is simpler:
<ListBox Grid.Row="2" Margin="5" ItemsSource="{Binding UncheckedItems}" ItemTemplate="{DynamicResource UncheckedItemDataTemplate}"/>
<ListBox Grid.Row="2" Margin="5" Grid.Column="1" ItemsSource="{Binding CheckedItems}" ItemTemplate="{DynamicResource CheckedItemDataTemplate}"/>
This is a cleaner solution, hope is helps.

Categories