TabItem Clicked - wpf

I have a problem, I have a wpf form with a tabcontrol, inside the tabcontrol there are multiple tabitems. By the way i'm doing the mvvm design patten with mvvmlight. Ok, now I want to pass some data from the viewmodel that is bound to the first tabitem to the other the second viewmodel that is bound to the second tabitem but only when the second tabitem is clicked. Thanks in advance

This sounds like a really odd requirement, please correct me if I'm wrong but I suspect that the way you've worded it isn't actually what you're trying to accomplish. The usual way to manage tabs with MVVM is to start by creating a view model for your tab panels:
public class TabItemViewModel
{
public string Header { get; set; }
// fields for the actual panel items go here
public override string ToString() => this.Header;
}
Then back in your view model you create an observable collection of these and a property to track which tab is currently selected:
public ObservableCollection<TabItemViewModel> MyItems { get; } = new ObservableCollection<TabItemViewModel>
{
new TabItemViewModel { Header = "Tab Page 1" },
new TabItemViewModel { Header = "Tab Page 2" },
new TabItemViewModel { Header = "Tab Page 3" }
};
private TabItemViewModel _CurrentTab;
public TabItemViewModel CurrentTab
{
get { return this._CurrentTab; }
set
{
if (this._CurrentTab != value)
{
this._CurrentTab = value;
RaisePropertyChanged(() => this.CurrentTab);
}
}
}
}
Your XAML then binds to the collection and the property:
<TabControl ItemsSource="{Binding MyItems}" SelectedItem="{Binding CurrentTab}" />
Result:
Since CurrentTab tracks the currently selected tab your view model code can easily check at any time to see if that's the one that the user has currently selected, so there's no need to mess around with the bindings themselves. Since the binding is two-way the view model can also control which tab is currently active, which is particularly handy when adding navigational helpers to your app.
If you genuinely want to remove bindings then it's easy enough to add an extra data field to your view model and then set/clear it in the CurrentTab setter.

Related

Xamarin Forms create a Clicked Event for CheckBox Control

so I am trying to use the CheckBox Control with MVVM logic. However the only event existing is CheckedChanged, which also triggers if I am navigating from the page for example.
I am searching for a Clicked event, like a button has.
Do I need to create a custom control with custom renderer, or is there a better solution?
Looking forward to replies.
[EDIT]
To provide more information about my issue, I will put code examples below.
My CheckBoxes are inside a ListView. Each CheckBox is defined like this in XAML:
<CheckBox
IsChecked="{Binding IsCompleted}">
<CheckBox.Behaviors>
<prism:EventToCommandBehavior
EventName="CheckedChanged"
Command="{Binding SubTaskStateChangedCommand}"/>
</CheckBox.Behaviors>
</CheckBox>
The ItemSource of the ListView has a property IsCompleted and a DelegateCommand SubTaskStateChangedCommand. It is worth mentioning that i am using Prism.
In the constructor:
SubTaskStateChangedCommand = new DelegateCommand(OnSubTaskStateChangedCommandExecuted);
Class SubTaskModel:
public DelegateCommand SubTaskStateChangedCommand { get; set; }
private void OnSubTaskStateChangedCommandExecuted()
{
//Do something
}
private bool _isCompleted;
public bool IsCompleted
{
get { return _isCompleted; }
set { _isCompleted = value; OnPropertyChanged(); }
}
So when I am navigating to another page in my ViewModel using the Prism NavigationService, the OnSubTaskStateChangedCommandExecuted Method gets triggered. However, I noticed that when this happens, the IsCompleted value DOES NOT change.

Selection changed event of combobox in wpf mvvm

I am new to wpf and MVVM, and I've spent all day trying to get the value of a ComboBox to my ViewModel on SelectionChanged. I want to call a function in the selection changed process. In mvvm, what is the solution for it?
In MVVM, we generally don't handle events, as it is not so good using UI code in view models. Instead of using events such as SelectionChanged, we often use a property to bind to the ComboBox.SelectedItem:
View model:
public ObservableCollection<SomeType> Items { get; set; } // Implement
public SomeType Item { get; set; } // INotifyPropertyChanged here
View:
<ComboBox ItemsSource="{Binding Items}" SelectedItem="{Binding Item}" />
Now whenever the selected item in the ComboBox is changed, so is the Item property. Of course, you have to ensure that you have set the DataContext of the view to an instance of the view model to make this work. If you want to do something when the selected item is changed, you can do that in the property setter:
public SomeType Item
{
get { return item; }
set
{
if (item != value)
{
item = value;
NotifyPropertyChanged("Item");
// New item has been selected. Do something here
}
}
}

Refresh listbox in wp7

I have model:
public class Song
{
public int ContentID { get; set; }
public bool IsSelected
{
get
{
var song = PlayerHelper.ReadNowPlaying();
return song.Id == ContentID;
}
}
}
I have a view with ListBox:
<ListBox x:Name="songsLstBox" ItemsSource="{Binding Top100Songs}" />
And ViewModel with list of Songs items. So, sometimes i want to refresh (redraw) the listbox. It's need to display that IsSelected is changed (No, i can't using INotifyPropertyChanged in model and setting it in viewmodel).
So how i can redraw a listbox in WP7? I can't find any Refresh or Update method for UIElements.
I tried calling this.OnPropertyChanged("Top100Songs"); but it doesn't work. I tried calling UpdateLayout - the same.
One way is setting DataContex for page to null and then revert to my ViewModel. It works, but is so long (about 5 secs. for changing).
So any ideas?
Write your own collection wrapper and use it for the Top100Songs property
class SongCollection : ObservableCollection<Song>
{
public Refresh()
{
OnCollectionChanged(
new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
}

Implementing a "Search as you type" in Silverlight

I am trying to implement a search as you type screen in my Silverlight application. The idea is that I have a screen with a textedit control and a listbox. The listbox is filled with all my data.
When the user types something in the textbox the following happens:
All the items that are not containing all the letters from the user input are hidden.
The matching letters of the visible list items are highlighted with a different color.
I am not sure how to start with this, so all pointers, samples and hints are welcome!
I would suggest using a CollectionViewSource. A CollectionViewSource has the ability to filter items. You can bind your ListBox to the CollectionViewSource and handle Filter event to do the filtering. Bind your "Search Box" to a Text property which you can use in your Filter event. You can handle the "KeyUp" event of the TextBox control to kick off your filtering, by calling the Refresh method on the CollectionViewSource View.
Filtering Data using CollectionViewSource: http://xamlcoder.com/blog/2010/10/27/filtering-data-using-collectionviewsource/
http://msdn.microsoft.com/en-us/library/system.windows.data.collectionviewsource.filter.aspx
http://msdn.microsoft.com/en-us/library/system.componentmodel.icollectionview.aspx
http://timheuer.com/blog/archive/2009/11/04/updated-silverlight-3-datagrid-grouping-data-pagedcollectionview.aspx
http://bea.stollnitz.com/blog/?p=392
Sudo code:
// ViewModel - properties should fire NotifyPropertyChanged
public class ViewModel : INotifyPropertyChanged
{
public ViewModel
{
this.Data = new CollectionViewSource();
this.Data.Source = this.GenerateObjects();
this.Data.Filter += (s,e) =>
{
// TODO: add filter logic
DataObject item = e.Item as DataObject;
return item.Name.Contains(this.SearchText);
};
}
public string SearchText{get;set;}
public CollectionViewSource Data {get;set;}
private List<DataObject> GenerateObjects(){ // generate list of data objects }
}
// View XAML
<StackPanel>
<TextBox Text="{Binding SearchText, Mode=TwoWay}" KeyUp="OnKeyUp"/>
<ListBox ItemsSource="{Binding Data.View}"/>
</StackPanel>
// View Code Behind
public class View : UserControl
{
public View() { this.DataContext = new ViewModel(); }
private ViewModel ViewModel { get { return this.DataContext as ViewModel; } }
private OnKeyUp()
{
this.ViewModel.Data.View.Refresh();
}
}
You may want to start with the AutocompleteBox from the Silverlight Toolkit.
It has a number of handy points where you would be able to extend it's functionality, for example in the instance searching your pool of values.

binding certain items from listbox to combox itemsource

I have a list box containing many items and I have a combobox in C# WPF.
I would like to bind the itemsource of the combobox to that of the listbox but I want to filter out some of the items (it's an xml datasource, I want to filter by the contents of a certain element of the item element).
Example item:
<Item>
<itemtype>A</itemtype>
<itemname>Name</itemname>
</item>
<Item>
<itemtype>B</itemtype>
<itemname>Name</itemname>
</item>
I thought of manually adding an item to the combobox when adding an item to the listbox but then the 'name' value of the item is not updated when it is changed in the listbox.
What is a good way to do this? Let's say I only want to show all item names with itemtype B. Can it be done in wpf binding or do I have to do some code behind?
It's a reference to the datasource, e.g. to a collection in your viewmodel if you use MVC pattern. The amazing thing is, that it is so simple in usage. The view is updated an has it's own refresh handling. I'll make a little example:
In WPF:
<ListBox ItemsSource={Binding Path=MySource} ItemTemplate="{StaticResource myItemTemplate}" />
The code logic:
public class Item
{
public string Name { get; set; }
public string Type { get; set; }
}
public class MyViewModel
{
public ObservableCollection<Item> MySource { get; set; }
public MyViewModel()
{
this.MySource = new ObservableCollection<Item>();
this.MySource.Add(new Item() { Name = "Item4", Type = "C" });
this.MySource.Add(new Item() { Name = "Item1", Type = "A" });
this.MySource.Add(new Item() { Name = "Item2", Type = "B" });
this.MySource.Add(new Item() { Name = "Item3", Type = "A" });
// get the viewsource
ListCollectionView view = (ListCollectionView)CollectionViewSource
.GetDefaultView(this.MySource);
// first of all sort by type ascending, and then by name descending
view.SortDescriptions.Add(new SortDescription("Type", ListSortDirection.Ascending));
view.SortDescriptions.Add(new SortDescription("Name", ListSortDirection.Descending));
// now i like to group the items by type
view.GroupDescriptions.Add(new PropertyGroupDescription("Type"));
// and finally i want to filter all items, which are of type C
// this is done with a Predicate<object>. True means, the item will
// be shown, false means not
view.Filter = (item) =>
{
Item i = item as Item;
if (i.Type != "C")
return true;
else
return false;
};
// if you need a refreshment of the view, because of some items were not updated
view.Refresh();
// if you want to edit a single item or more items and dont want to refresh,
// until all your edits are done you can use the Edit pattern of the view
Item itemToEdit = this.MySource.First();
view.EditItem(itemToEdit);
itemToEdit.Name = "Wonderfull item";
view.CommitEdit();
// of course Refresh/Edit only makes sense in methods/callbacks/setters not
// in this constructor
}
}
Interesting is, that this pattern directly affects the listbox in the gui. If you add the grouping / sorting, this will affect the listbox's display behavior, even if the itemssource is only bound to the viewmodel.
The problem with Binding in this case, is that its only set once. So if you bind it, the sources are synchron. You could use a converter for the binding, which filters the items you not like to bind. Another way would be to use WPF's wonderful CollectionViewSource.
You can add Groupings/Sortings and a Filter to a CollectionViewSource on any kind of ItemsSource. Use the ListCollectionView for example.
ListCollectionView view =
(ListCollectionView)CollectionViewSource.GetDefaultView(yourEnumerableSource);

Resources