Silverlight 5: Binding command to listboxitem - xaml

I am beginner in silverlight and all this mvvm pattern is bit confusing.
In my application I have two listboxs one for country and one for states.
What I want to do is when I select a Country from the listbox1 second listbox will display states from the selected country.
i.e I want to bind command in xaml to listboxitem.
I try to find the solution by Google but either solutions was too complex for me to understand or using different mvvm pattern like prism,light etc.

There are a few different ways of doing this:
1: (Easiest!) Bind the SelectedItem of the first ListBox to your ViewModel. In the Setter for the ViewModel property, change the list that you're binding to the second listbox. Note that your ViewModel property will need to use INotifyPropertyChanged to notify that the list has changed.
Eg: If your xaml looks like:
<ListBox ItemSource="{Binding ListOne}" SelectedItem="{Binding SelectedItem, Mode=TwoWay}"/>
<ListBox ItemSource="{Binding ListTwo}"/>
Then your ViewModel might be a bit like:
public List<MyItem> ListOne { get; set; }
private MyItem _selectedItem
public MyItem SelectedItem
{
get { return _selectedItem; }
set
{
_selectedItem = value;
ListTwo = _selectedItem.SubItems;
}
}
private List<MyOtherItem> _listTwo
public List<MyOtherItem> ListTwo
{
get { return _listTwo; }
set
{
_listTwo = value;
RaisePropertyChanged("ListTwo");
}
}
2: If the data for the second list is literally a property of the items in the first list, you can use an Binding in xaml to directly join them up.
ItemSource="{Binding Path=SelectedItem.MyItemsProperty, ElementName=MyFirstListBoxName}"
3: You can use an EventTrigger with an EventToCommand to turn the SelectedItemChanged event into a Command execution. You're not literally binding a command to the ListBoxItem, you're binding the command to the change.
I would recommend the first option, it's easiest and gives you good control of what's going on without getting too complicated.

Related

WinRT ComboBox SelectedValue is null

I have created a class for creating the item to add to combobox
public class ComboBoxItemClass
{
public string Text { get; set; }
public object Value { get; set; }
public override string ToString()
{
return Text;
}
}
My XAML is as follows for the combobox
<TextBlock Text="State"/>
<ComboBox x:Name="cbState"/>
My C# code in the code-behind is as follows
private void NavigationHelper_LoadState(object sender, LoadStateEventArgs e)
{
List<ComboBoxItemClass> state_items = new List<ComboBoxItemClass>();
List<State> states = Location.GetStates();
foreach(State s in states)
{
ComboBoxItemClass item = new ComboBoxItemClass() { Text = s.State_Name, Value = s.State_Id };
state_items.Add(item);
}
cbState.ItemsSource = state_items;
cbState.SelectedValue = 3;
The combobox on running in emulator does not show the selected state. On clicking it shows the list of states.
On debugging the selectedvalue is shown to be null despite assigning it a value.
There is no problem with the rest of code and there exists a state with State_Id=3
I have solved this in two ways
The first way is to get the list of states in states variable. Assign this to ComboBox ItemSource. Then get the the State_Id and find the index of that particular state from the same states list and assign it to selected index.
Code Behind as Follows
states = Location.GetStates();
cbState.ItemsSource = states;
cbState.SelectedIndex = states.IndexOf(states.Where(x=>x.State_Id==State_Id).First());
Second method is as suggested in the comments section
states = Location.GetStates();
cbState.ItemsSource = states;
int index=states.IndexOf(states.Where(x=>x.State_Id==State_Id).First());
cbState.SelectedItem = states[index];
XAML is as follows
<ComboBox x:Name="cbState" >
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding State_Name}"></TextBlock>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
Also I would like to post to my fellow WinRT developers that it is not required to create a separate class like ComboBoxItemClass like I did in the question to use combo box. Just get the list of your states, assign it to ItemSource and use any of the above methods.
Also if you want the State_Name and State_Id from the ComboBox you can do this.
State mystate=(State)ComboBox.SelectedItem;

Setting the initial selected item when binding to a ListView's SelectedItem property

I have a Xamarin.Forms xaml page in which I am using a ListView to allow the user to pick a single item out of a list. I have bound the ListView's SelectedItem property to a property on my ViewModel and this works fine. As soon as the user changes the selected item the property in my viewmodel updates as well.
However, even though I initially set the property in my ViewModel to one of the values from the list, when the page loads the ListView's SelectedItem property is null, which in turn sets the ViewModel property to null as well.
What I need is the other direction, I want the ListView to initially select the item that i've set in the VM property.
I can hack together a solution by writing extra code in the code behind file to explicitly set the initial selected item, but this introduces additional properties and complexity and is quite ugly.
What is the correct way to set the initial selected item of a ListView who's selected item is bound to a viewmodel property?
-EDIT-
I was asked to provide the code that I'm using for my binding.
It's very simple, standard:
<ListView x:Name="myList" ItemsSource="{Binding Documents}" SelectedItem="{Binding SelectedDocument}">
the view model that is set as the binding context for the listview is instantiated before the page is created and looks like this:
public class DocumentSelectViewModel : ViewModelBase
{
private Document selectedDocument;
public List<Document> Documents
{
get { return CachedData.DocumentList; }
}
public Document SelectedDocument
{
get { return selectedDocument; }
set { SetProperty(ref selectedDocument, value);
}
public DocumentSelectViewModel()
{
SelectedDocuement = CachedData.DocumentList.FirstOrDefault();
}
}
SetProperty is a function which simply rasies the INotifyPropertyChanged event if the new value is different from the old one, classical binding code.
I am a little rusty on XAML but don't you need to make the binding two-way?
E.G.
{ Binding SelectedDocument, Mode=TwoWay }
As long as the SelectedDocument property change raises the INotifyPropertyChanged event then you should get the desired effect.
If you replace
public DocumentSelectViewModel()
{
SelectedDocument = CachedData.DocumentList.FirstOrDefault();
}
By
public DocumentSelectViewModel()
{
SelectedDocument = Documents.FirstOrDefault();
}
Does it work for you ?
I had a similar problem that has been resolved this way...
You can use ctor DocumentSelectViewModel for set initial value. Honestly I dont like to make some job in ctor block but Xamarin.... You dont need DocumentSelectViewModel method. It will work.
public DocumentSelectViewModel ()
{
SelectedDocument = Documents[0]; //or any your desired.
}

How to access Pivot.TitleTemplate as UserControl?

Subj, how can i get it?
<controls:Pivot.TitleTemplate>
<DataTemplate>
<mainPivot:MyUserControl Name="MainPivotHeader"/>
</DataTemplate>
</controls:Pivot.TitleTemplate>
Tried to find it via VisualTreeFinders, but it sees only pivot item.
UserControl shows a picture, but it depends on user. During first initialization, it is empty, because user is not yet logged in. So, i'd like to force its update.
I can use mvvm light messaging, but i'm looking for self-sufficient components. This forcing is rare, so i dont want to use messaging here.
You should bind the Title property of the Pivot to a property on a ViewModel. Your DataTemplate would then have it's DataContext already set to that object. When you need to refresh, you call some method on that object.
Example
public class ViewModel : INotifyPropertyChanged
{
private MyTitleObject _titleObject;
public MyTitleObject TitleObject
{
get { return _titleObject; }
set
{
_titleObject = value;
OnPropertyChanged("TitleObject");
}
}
public void Refresh()
{
TitleObject = new MyTitleObject();
// or refresh values directly on the object
}
...
}
You xaml for your Pivot would need to following
<controls:Pivot Title="{Binding TitleObject}">
</controls:Pivot>
When you want to refresh, call the refresh on the viewmodel.

Hiding elements in XAML

I have defined a XAML page for my WP8 app that currently holds a LongListSelector with an ItemTemplate.
I'm outputting some personal info like name and age. Each is a TextBlock defined like so:
<TextBlock Text="{Binding Age, StringFormat='Age: {0}'}" Visibility="{Binding AgeVisibility}"/>
The thing is that the user doesn't always input all the data, so sometimes some attributes are missing (like age). In those cases I would like to remove the TextBlock.
With the code defined like it is (note the use of the Visibility attribute) it only hides the element, which leaves an ugly space in the form.
Is there a way to remove an element from the list, if it might be undefined/missing?
EDIT: I should note that while I do use a LongListSelector, it only actually holds a single element. This element is then binded to a pure data class with many properties:
public class Details
{
public string Name { get; set; }
public string Age { get; set; }
}
I would recommend creating an ObservableCollection of objects you'd like to bind, and adding it to the LongListSelector like this:
longListSelector.ItemsSource = myCollection;.
Everytime you'd like to remove an element from the list, you'd just call something like myCollection.RemoveAt(0) and the list will update itself.

How to disable selection a single item in a GridView

How do you disable the selection single item from a GridView?
I have a GridView with it's ItemsSource bound to an IEnumerable<SampleDataItem>. I'd like to be able to programmatically not allow the selection of some items in the list while allowing selection of the others.
While I haven't done this, you should be able to use an ItemContainerStyleSelector on the GridView, the method gives you the container (GridViewItem) and the item you're binding to. From there you can set the IsEnabled property on the GridViewItem to false which makes it unselectable.
You'll also probably need to select a custom style as well since the default GridViewItem style will customise how a disabled item will look.
Update DataTemplateSelector Solution
public class IssueGridTemplateSelector : DataTemplateSelector
{
protected override DataTemplate SelectTemplateCore(object item, DependencyObject container)
{
var selectorItem = container as SelectorItem;
if (item is Issue)
return IssueTemplate;
selectorItem.IsEnabled = false;
selectorItem.Style = RepositoryItemStyle;
return RepositoryTemplate;
}
public DataTemplate IssueTemplate
{
get;
set;
}
public DataTemplate RepositoryTemplate
{
get;
set;
}
public Style RepositoryItemStyle
{
get;
set;
}
}
Nigel's answer is great. I just added some attached properties to the WinRT XAML Toolkit that should make it simpler to do if you are populating your GridView using the ItemsSource property binding.
For me the usual way to modify the GridViewItem properties then was using GridView.ItemContainerStyle property. Using that method you would need to specify the IsEnabled property using a style and style setters don't support bindings in WinRT. Using the ItemContainerStyleSelector might be one way, but it requires defining a custom class.
I have created a GridViewItemExtensions class with an IsEnabled property that you can set on any control in your GridView.ItemTemplate like this:
xmlns:xyzc="using:Xyzzer.WinRT.Controls"
xyzc:GridViewItemExtensions.IsEnabled="{Binding IsEnabled}"
The property has a behavior of finding the GridViewItem in its ancestors visual tree and keeping its IsEnabled value synchronized to the GridViewItemExtensions.IsEnabled value set on its descendant.
Then as Nigel said - you still need to extract the template from a GridViewItem and modify it so the disabled items don't look out of place.