Xaml.Win8: How can I bind nested class to datatemplate? - data-binding

I have custom element and want to change it content by selector.
It means:
<xamlExtensions:BitmapButton
Grid.Column="5"
Click="OnBuyButtonClicked"
Command="{Binding BuyCommand}" CommandParameter="{Binding}"
Style="{StaticResource BitmapButtonStyle}"
DisabledStateBitmap="ms-appx:///Assets/UI/Pages/MainPage/BuyCoinsPopup/disabledButton.png">
<xamlExtensions:BitmapButton.Content>
<ContentControl ContentTemplateSelector="{StaticResource ButtonSelector}" Content="{Binding ContentButton}">
</ContentControl>
</xamlExtensions:BitmapButton.Content>
</xamlExtensions:BitmapButton>
<DataTemplate x:Key="EnabledButtonTemplate">
<TextBlock FontWeight="Bold" FontSize="24" Text="{Binding Path =BuyText}"/>
</DataTemplate>
<DataTemplate x:Key="DisabledButtonTemplate" >
<TextBlock FontWeight="Bold" FontSize="18" Text="{Binding Path =NotAvaliable}"/>
</DataTemplate>
<DataTemplate x:Key="TimedButtontemplate" >
<StackPanel >
<TextBlock FontWeight="Bold" FontSize="14" Text="{Binding Path= AvaliableInTitle}" HorizontalAlignment="Center" Foreground="Black"/>
<TextBlock FontWeight="Bold" FontSize="14" Text="{Binding Path = Counter}" HorizontalAlignment="Center" Foreground="Black"/>
</StackPanel>
</DataTemplate>
<helpers1:ButtonDataTemplateSelector x:Key="ButtonSelector"
EnabledButtonTemplate="{StaticResource EnabledButtonTemplate}"
DisabledButtonTemplate="{StaticResource DisabledButtonTemplate}"
TimedButtontemplate="{StaticResource TimedButtontemplate}"/>
view model:
public class ContentButton : ObservableObject
{
private string _buyText = string.Empty;
private string _counter = "--:--";
private ButtonState _buttonState;
private string _avaliableInTitle = LocalizationManager.GetLocalizedString("AvaliableInTitle");
private string _notAvaliable = "Not avaliable";
public string BuyText
{
get { return _buyText; }
set
{
_buyText = value;
RaisePropertyChanged("BuyText");
}
}
public string NotAvaliable
{
get { return _notAvaliable; }
set
{
_buyText = value;
RaisePropertyChanged("NotAvaliable");
}
}
public string Counter
{
get { return _counter; }
set
{
_counter = value;
RaisePropertyChanged("Counter");
}
}
public ButtonState ButtonState
{
get
{
return _buttonState;
}
set
{
_buttonState = value;
RaisePropertyChanged("ButtonState");
}
}
public string AvaliableInTitle
{
get { return _avaliableInTitle; }
set
{
_avaliableInTitle = value;
RaisePropertyChanged("AvaliableInTitle");
}
}
}
public class StorePopupTileItem : TileItem
{
private ContentButton _contentButton;
public ContentButton ContentButton
{
get
{
return _contentButton;
}
set
{
_contentButton = value;
RaisePropertyChanged("ContentButton");
}
}
}
I am binding StorePopupTileItem; and when I change one of properties (AvaliableInTitle, BuyText or else) it doesn't change on the view.
How can I fix it?
Thanks
Added:
protected override DataTemplate SelectTemplateCore(object item, DependencyObject container)
{
if (item != null)
{
var itemCur = (ContentButton)item;
switch (itemCur.ButtonState)
{
case ButtonState.Disabled:
return DisabledButtonTemplate;
case ButtonState.TimeDisabled:
return TimedButtontemplate;
case ButtonState.Enabled:
return EnabledButtonTemplate;
}
}
return EnabledButtonTemplate;
but I don't know what to do if I change only one field (f.e. ButtonState) from the code side?
In this case new information doesn't bind. And right now in every point where I want to update button I need to do this:
StorePopupTileItem tempItem = TileItem;
TileItem.ContentButton = new ContentButton
{
BuyText = tempItem.ContentButton.BuyText,
ButtonState = ButtonState.Enabled,
Counter = tempItem.ContentButton.Counter
}

Related

Passing Data from CollectionView to details page Shell Navigation

I have a CollectionView with a list of names and a label view profile. When I click view profile I want to navigate to the details page. However I am confused with the shell navigation and how to pass data from one page to another.
As well as with CollectionView. This is my first time working with it. I am clicking on viewprofile and navigating to the details page however the data I pass through doesn't pass. The PetName doesn't appear as I guess there is no value. I am using a command to call navigation.
I guess I am unsure how to get the Petsname when I click view profile then pass it on.
MyIDPageViewModel:
class MyIDPageViewModel : INotifyPropertyChanged
{
FirebaseHelper firebaseHelper = new FirebaseHelper();
public Command NavToDetailCommand { get; set; }
public ObservableCollection<PetProfile> source;
public ObservableCollection<PetProfile> PetInfo { get; private set; }
public ObservableCollection<PetProfile> EmptyPetInfo
{
get => source;
private set
{
if (value != source)
{
source = value;
OnPropertyChanged(nameof(EmptyPetInfo));
}
}
}
public MyIDPageViewModel()
{
source = new ObservableCollection<PetProfile>();
CreatePetProfileCollection();
NavToDetailCommand = new Command<PetProfile>(OnNav);
}
private async void OnNav(PetProfile PetDetailsPage)
{
if (PetDetailsPage == null)
return;
await Shell.Current.GoToAsync($"//MyIDPage/PetDetailsPage?PetName={PetDetailsPage.PetName}");
}
public async void CreatePetProfileCollection()
{
var petProfiles = await firebaseHelper.GetAllUserPetInfos();
if (petProfiles != null)
{
EmptyPetInfo = new ObservableCollection<PetProfile>();
foreach (var groupitems in petProfiles)
{
EmptyPetInfo.Add(new PetProfile() { PetName = groupitems.PetName, UserEmail = groupitems.UserEmail, Breed = groupitems.Breed, DOB = groupitems.DOB, Gender = groupitems.Gender, Weight = groupitems.Weight, CareInformation = groupitems.CareInformation });
}
}
}
public async void Refresh()
{
EmptyPetInfo.Clear();
var petProfiles = await firebaseHelper.GetAllUserPetInfos();
if (petProfiles != null)
{
EmptyPetInfo = new ObservableCollection<PetProfile>();
foreach (var groupitems in petProfiles)
{
EmptyPetInfo.Add(new PetProfile() { PetName = groupitems.PetName, UserEmail = groupitems.UserEmail, Breed = groupitems.Breed, DOB = groupitems.DOB, Gender = groupitems.Gender, Weight = groupitems.Weight, CareInformation = groupitems.CareInformation });
}
}
}
#region INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
My collection View:
<CollectionView ItemsSource="{Binding EmptyPetInfo}" SelectedItem="{Binding SelectedPet, Mode=OneWay}" SelectionChanged="OnCollectionViewSelectionChanged">
<CollectionView.ItemTemplate>
<DataTemplate>
<Grid Padding="10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Label Grid.Column="0"
Grid.Row="0"
Text="Image Goes Here"
FontAttributes="Bold" />
<Label Grid.Column="1"
Grid.Row="0"
Text="{Binding PetName}"
FontAttributes="Bold"
x:Name="labelpetname"/>
<Label Grid.Row="0"
Grid.Column="2"
Text="View Profile"
FontAttributes="Italic"
VerticalOptions="End"
>
<Label.GestureRecognizers>
<TapGestureRecognizer Command="{Binding NavToDetailCommand, Source={
RelativeSource AncestorType={x:Type local:MyIDPageViewModel}
}}"
CommandParameter="{Binding .}">
</TapGestureRecognizer>
</Label.GestureRecognizers>
</Label>
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
PetDetailsPage:
public partial class PetDetailsPage : ContentPage
{
FirebaseHelper firebaseHelper = new FirebaseHelper();
private string _PetName;
public string PetName
{
get => _PetName;
set
{
if (value != _PetName)
{
_PetName = value;
}
}
}
public PetDetailsPage()
{
InitializeComponent();
RetrivePetInfo();
}
private async void RetrivePetInfo()
{
var pet = await firebaseHelper.GetPet(_PetName);
if (pet != null)
{
petname.Text = pet.PetName;
}
}
private void Button_Clicked(object sender, EventArgs e)
{
}
}
Code for retrieving PetInfo from firebase:
public async Task<PetProfile> GetPet(string petname)
{
var useremail = Preferences.Get("UserSignInEmail", "");
var PetProfiles = await GetAllPetInfos();
await firebase
.Child("PetProfiles")
.OnceAsync<PetProfile>();
return PetProfiles.Where(a => a.UserEmail == useremail && a.PetName == petname).FirstOrDefault();
}
As Cfun mentioned in comment , Add a QueryProperty attribute above the class .
[QueryProperty(nameof(PetName), "PetName")]
public partial class PetDetailsPage : ContentPage{}
set method of propery PetName is invoked later than class constructor, so _PetName is null in RetrivePetInfo method , as a workaround , you could call RetrivePetInfo directly in set method instead in constructor .
public string PetName
{
get => _PetName;
set
{
if (value != _PetName)
{
_PetName = value;
RetrivePetInfo();
}
}
}

Focus on Next Entry after max length of 1

I have created dynamic 20 entries and want to focus on next entry after user enter a digit and max length of entry is 1. The focus should be automatically move on next entry.I am sharing my code.Thanks in advance for help.
//model
public class CrossingUIModel
{
public int Id { get; set; }
public string FieldValue { get; set; }
}
//on change property
private ObservableCollection<CrossingUIModel> bindCrossingUIModel;
public ObservableCollection<CrossingUIModel> BindCrossingUIModel
{
get { return bindCrossingUIModel; }
set
{
bindCrossingUIModel = value;
OnPropertyChanged(nameof(BindCrossingUIModel));
}
}
//creating ui
public void CreateUI()
{
UserDialogs.Instance.ShowLoading();
BindCrossingUIModel = new ObservableCollection<CrossingUIModel>();
for (int i = 1; i < 21; i++)
{
CrossingUIModel model = new CrossingUIModel();
model.Id = i;
BindCrossingUIModel.Add(model);
}
UserDialogs.Instance.HideLoading();
}
//xml file
<CollectionView x:Name="CrossingView" ItemsSource="{Binding BindCrossingUIModel, Mode=TwoWay}" SelectionMode="Multiple">
<CollectionView.ItemsLayout>
<GridItemsLayout Orientation="Vertical" Span="10" />
</CollectionView.ItemsLayout>
<CollectionView.ItemTemplate>
<DataTemplate>
<StackLayout HorizontalOptions="FillAndExpand">
<Entry x:Name="Fields" Text="{Binding FieldValue, Mode=TwoWay}"
ReturnType="Next" MaxLength="1" Keyboard="Numeric"
TextChanged="Fields_TextChanged" ></Entry>
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
Since you had used Data-Binding , it would be better to handle all the logic in ViewModel .
in code behind
Define a custom Entry
public class MyEntry:Entry
{
public static readonly BindableProperty IsFocusProperty =BindableProperty.Create("IsFocus", typeof(bool), typeof(MyEntry), false,propertyChanged: OnChanged);
static void OnChanged(BindableObject bindable, object oldValue, object newValue)
{
var entry = bindable as MyEntry;
var focus = (bool)newValue;
if(focus)
{
entry.Focus();
}
else
{
entry.Unfocus();
}
}
public bool IsFocus
{
get { return (bool)GetValue(IsFocusProperty); }
set {
SetValue(IsFocusProperty, value);
}
}
public MyEntry()
{
this.Focused += MyEntry_Focused;
this.Unfocused += MyEntry_Unfocused;
}
private void MyEntry_Unfocused(object sender, FocusEventArgs e)
{
this.IsFocus = false;
}
private void MyEntry_Focused(object sender, FocusEventArgs e)
{
this.IsFocus = true;
}
}
in Model
public class CrossingUIModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public int Id { get; set; }
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
string fieldValue;
public string FieldValue
{
get
{
return fieldValue;
}
set
{
if (fieldValue != value)
{
fieldValue = value;
OnPropertyChanged("FieldValue");
}
}
}
bool isFocus = false;
public bool IsFocus
{
get
{
return isFocus;
}
set
{
if (isFocus != value)
{
isFocus = value;
OnPropertyChanged("IsFocus");
}
}
}
}
in ViewModel
public class MyViewModel
{
public ObservableCollection<CrossingUIModel> BindCrossingUIModel { get; set; }
public MyViewModel()
{
BindCrossingUIModel = new ObservableCollection<CrossingUIModel>();
for (int i = 1; i < 21; i++)
{
CrossingUIModel model = new CrossingUIModel();
model.Id = i;
BindCrossingUIModel.Add(model);
}
foreach (CrossingUIModel model in BindCrossingUIModel)
{
model.PropertyChanged += Model_PropertyChanged;
}
}
private void Model_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if(e.PropertyName== "FieldValue")
{
var model = sender as CrossingUIModel;
if(model.FieldValue.Length==1)
{
model.FieldValue = model.FieldValue.Substring(0, 1);
model.IsFocus = false;
int id = model.Id;
BindCrossingUIModel[id].IsFocus = true;
}
}
}
}
in xaml
Now we don't need to set MaxLength and TextChanged any more .
<StackLayout HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand">
<CollectionView x:Name="CrossingView" ItemsSource="{Binding BindCrossingUIModel, Mode=TwoWay}" SelectionMode="Multiple">
<CollectionView.ItemsLayout>
<GridItemsLayout Orientation="Vertical" Span="10" />
</CollectionView.ItemsLayout>
<CollectionView.ItemTemplate>
<DataTemplate>
<StackLayout WidthRequest="100" HeightRequest="30" HorizontalOptions="FillAndExpand">
<local:MyEntry WidthRequest="80" BackgroundColor="LightBlue" HeightRequest="30" x:Name="Fields" Text="{Binding FieldValue, Mode=TwoWay}"
IsFocus="{Binding IsFocus, Mode=TwoWay}"
ReturnType="Next" Keyboard="Numeric"
></local:MyEntry>
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</StackLayout>
By the way , you could use Grid instead of StackLayout as the Parent Layout of the Entry.

Xamarin Forms : How to Handle Listview Image Click Event in ViewModel?

All,
I am binding my Listview to a collection from a Viewmodel. CellView of the ListView includes an image. I would like to invoke a command in my viewmodel when I click the image in the list item.I am trying to avoid event handling in my model. Any idea ?
thanks !
Given below is the xaml and view model.
ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:jList="clr-namespace:JList;assembly=JList"
x:Class="JList.Pages.ItemDetailPage"
Title="Sub Items"
BindingContext="{Binding Source={StaticResource Locator}, Path=ItemDetailViewModel}"
>
<ContentPage.ToolbarItems >
<ToolbarItem Text="Add" Order="Primary" Priority="1" Command="{Binding AddItemCommand}"></ToolbarItem>
<ToolbarItem Text="Edit" Order="Primary" Priority="2" Command="{Binding EditItemCommand}"></ToolbarItem>
</ContentPage.ToolbarItems>
<StackLayout>
<SearchBar Placeholder="Search..." VerticalOptions="Fill" SearchCommand="{Binding SearchCommand}" Text="{Binding SearchString}" ></SearchBar>
<ListView RowHeight="200" ItemsSource="{Binding SubItemsCollection}" BackgroundColor="Gainsboro" SelectedItem="{Binding SubItemSelected, Mode=TwoWay}" x:Name="List" >
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell >
<StackLayout>
<Grid VerticalOptions="Fill" BackgroundColor="White" Padding="5">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Image Source="{Binding ImagePath}" Aspect="AspectFit">
<Label Grid.Row="0" Grid.Column="0" Text="{Binding Name}" HorizontalTextAlignment="Center" VerticalTextAlignment="Center" TextColor="Chocolate" Font="Bold,20" />
</Grid>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
<ContentPage.Behaviors>
<jList:CustomBehavior />
</ContentPage.Behaviors>
View Model
namespace JList.Core.ViewModels
{
public class ItemDetailViewModel : ViewModelBase, IViewModel
{
private IItemService _itemService;
private ICommandFactory _cmdFactory;
private INavigationService _navService;
private ItemListViewModel _parent;
private IAppInstanceData _appData;
public ItemDetailViewModel(IItemService itemService, ICommandFactory cmdFactory, INavigationService navService, IAppInstanceData appData, ItemListViewModel parent)
{
_itemService = itemService;
_cmdFactory = cmdFactory;
_navService = navService;
_parent = parent;
ParentItemSelected = _parent.ItemSelected.Id;
_appData = appData;
// FetchSubItemsAsync();
}
public int ParentItemSelected { get; set; }
private string _searchString;
public String SearchString
{
get { return _searchString; }
set
{
if (_searchString != value)
{
_searchString = value;
OnPropertyChanged();
}
}
}
private ObservableCollection<SubItem> _subItemsCollection;
public ObservableCollection<SubItem> SubItemsCollection
{
get { return _subItemsCollection; }
set
{
if (_subItemsCollection != null)
{
if (!_subItemsCollection.SequenceEqual(value))
{
_subItemsCollection = value;
OnPropertyChanged();
}
}
else
{
_subItemsCollection = value;
OnPropertyChanged();
}
}
}
private async void FetchSubItemsAsync()
{
ParentItemSelected = _parent.ItemSelected.Id;
var items = await _itemService.GetAllSubItemsAsync(_parent.ItemSelected.Id);
var coll = new ObservableCollection<SubItem>();
foreach (var it in items)
{
coll.Add(it);
}
SubItemsCollection = coll;
}
public void RefreshAsync()
{
FetchSubItemsAsync();
}
private SubItem _itemSelected;
public SubItem SubItemSelected
{
get => _itemSelected;
set
{
_itemSelected = value;
// _navService.PushView(typeof(EditSubItemViewModel).ToString());
}
}
#region FetchCommand
private ICommand _fetchItemsCommand;
public ICommand FetchItemsCommand
{
get
{
if (_fetchItemsCommand == null)
_fetchItemsCommand = _cmdFactory.CreateCommand(FetchSubItemsAsync, () => true);
return _fetchItemsCommand;
}
}
#endregion
#region AddItemCommand
private ICommand _addItemCommand;
public ICommand AddItemCommand
{
get
{
if (_addItemCommand == null)
_addItemCommand = _cmdFactory.CreateCommand(AddItem, () => true);
return _addItemCommand;
}
}
public void AddItem()
{
_appData.IsEditSubItem = false;
_navService.PushView(typeof(SubItemViewModel).ToString());
}
#endregion
#region EditItemCommand
private ICommand _editItemCommand;
public ICommand EditItemCommand
{
get
{
if (_editItemCommand == null)
_editItemCommand = _cmdFactory.CreateCommand(EditItem, () => true);
return _editItemCommand;
}
}
public void EditItem()
{
_appData.IsEditSubItem = true;
_navService.PushView(typeof(SubItemViewModel).ToString());
}
#endregion
#region SearchCommand
private ICommand _searchCommand;
public ICommand SearchCommand
{
get
{
if (_searchCommand == null)
_searchCommand = _cmdFactory.CreateCommand(SearchItemAsync, () => true);
return _searchCommand;
}
}
private async void SearchItemAsync()
{
var items = await _itemService.GetAllSubItemsAsync(_parent.ItemSelected.Id);
var sstring = SearchString.ToLower();
items = items.Where(i => i.Name.ToLower().Contains(sstring));
var coll = new ObservableCollection<SubItem>();
foreach (var it in items)
{
coll.Add(it);
}
SubItemsCollection = coll;
}
#endregion
}
}
You can add TapGestureRecognizer to the image and bind the command in your ViewModel. Also, you are binding the command inside ViewCell, so you need to set the source of BindingContext.
<ContentPage x:Name="ABCPage">
...
<Image Source="abc">
<Image.GestureRecognizers>
<TapGestureRecognizer
Command="{Binding Path=BindingContext.ImageCommand, Source={x:Reference Name=ABCPage}}"
CommandParameter="{Binding .}" />
</Image.GestureRecognizers>
</Image>
...
</ContentPage>

ComboBox selectedItem affect another ComboBox

I have a question about Databinding which I'm really struggling to understand. I have two ComboBox on my extended splash screen. What I want to achieve is when you select an item from the first ComboBox, the items in the 2nd ComboBox should change. Please see the code below.
First let me try to explain how my Data looks like and what problem I'm facing.
Collection
A
AA
AB
AC
B
BA
BB
C
CA
The First ComboBox should show A,B and C as items. Now lets say you selected A, the ComboBox 2 should show AA,AB and AC as items. The problem I have is that ComboBox 2 is showing AA only not all 3 items.
My ViewModel Called MainViewModel looks like this:-
public class ItemViewModel : INotifyPropertyChanged
{
private string _befattning;
public string Befattning
{
get
{
return _befattning;
}
set
{
if (value != _befattning)
{
_befattning = value;
NotifyPropertyChanged("Befattning");
}
}
}
private string _befattning2;
public string Befattning2
{
get
{
return _befattning2;
}
set
{
if (value != _befattning2)
{
_befattning2 = value;
NotifyPropertyChanged("Befattning2");
}
}
}
private string _befattning3;
public string Befattning3
{
get
{
return _befattning3;
}
set
{
if (value != _befattning3)
{
_befattning3 = value;
NotifyPropertyChanged("Befattning3");
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String propertyName)
{
//NotifyPropertyChanged Code
}
}
public class MainViewModelGroups : INotifyPropertyChanged
{
public MainViewModelGroups(String enhet)
{
this._enhetsNamn = enhet;
}
private string _enhetsNamn;
public string EnhetsNamn
{
get { return _enhetsNamn; }
}
private string _selectedItem;
public string SelectedItem
{
get { return _selectedItem; }
set
{
if (value != _selectedItem)
{
_selectedItem = value;
NotifyPropertyChanged("SelectedItem");
}
}
}
private ObservableCollection<ItemViewModel> _items = new ObservableCollection<ItemViewModel>();
public ObservableCollection<ItemViewModel> Items
{
get
{
return this._items;
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String propertyName)
{
//NotifyPropertyChangedCode
}
}
public sealed class MainViewModel
{
private static MainViewModel _mainViewModel = new MainViewModel();
private ObservableCollection<MainViewModelGroups> _collection = new ObservableCollection<MainViewModelGroups>();
public ObservableCollection<MainViewModelGroups> Collection
{
get { return this._collection; }
}
public MainViewModel()
{
var enhet1 = new MainViewModelGroups("Akutmottagning");
enhet1.Items.Add(new ItemViewModel() { Befattning = "Ledningsansvarig sjuksköterska" });
Collection.Add(enhet1);
}
And my XAML code looks like this
<ComboBox x:Name="EnhetLista"
ItemsSource="{Binding Collection}"
SelectedItem="{Binding SelectedItem, Mode=OneWay}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding EnhetsNamn}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<ComboBox x:Name="BefattningsLista"
DataContext="{Binding ElementName=EnhetLista, Path=SelectedItem, Mode=OneWay}"
ItemsSource="{Binding Path=Items, Mode=OneWay}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
Can someone please helps by explaining what is wrong with my code and how to achieve my goal?
Add a second ObservableCollection to your viewmodel, then change that based on the selected item.
public sealed class MainViewModel
{
private static MainViewModel _mainViewModel = new MainViewModel();
private ObservableCollection<MainViewModelGroups> _collection = new ObservableCollection<MainViewModelGroups>();
public ObservableCollection<MainViewModelGroups> Collection
{
get { return this._collection; }
}
public ObservableCollection<ItemViewModel> Items
{
get { return this._items; }
set { this._items = value; OnPropertyChanged("Items"); }
}
public MainViewModelGroups SelectedGroup
{
get { return this._selectedGroup; }
set { this._selectedGroup = value; Items = value.Items; }
}
public MainViewModel()
{
var enhet1 = new MainViewModelGroups("Akutmottagning");
enhet1.Items.Add(new ItemViewModel() { Befattning = "Ledningsansvarig sjuksköterska" });
Collection.Add(enhet1);
}
}
Your Xaml will change to:
<ComboBox x:Name="EnhetLista"
ItemsSource="{Binding Collection}"
SelectedItem="{Binding SelectedItem, Mode=TwoWay}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding EnhetsNamn}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<ComboBox x:Name="BefattningsLista"
ItemsSource="{Binding Path=Items}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
Your viewmodel may need to implement INotifyPropertyChanged. It may not though, as ObservableCollection may take care of that for you.

Listbox binding in Silverlight

I have a listbox on silverlight page, the datacontext of the page is set to an instance -- TestQuestions, please see the code below. The listbox uses a DataTemplate and its ItemSource is 'Answers' which is a property of the page's DataContext, everything works fine until I try to bind to 'ShowAnswer', a property on the page's DataContext within the DataTemplate. No matter what I tried it won't pick the property's value.
Thank you all for your help.
Xaml:
<ListBox ItemsSource="{Binding Path=Answers, Mode=TwoWay}">
<ListBox.ItemTemplate>
<DataTemplate>
<RadioButton IsChecked="{Binding Path=Correct, Mode=TwoWay}" >
<Grid>
<StackPanel Visibility="{Binding Path=ShowAnswer}">
<Rectangle Fill="Blue" Visibility="{Binding Path=Correct}" />
</StackPanel>
<TextBlock Text="{Binding Path=AnswerText, Mode=TwoWay}" TextWrapping="Wrap" />
</Grid>
</RadioButton>
</DataTemplate>
</ListBox.ItemTemplate>
C#:
public class Answer
{
private bool correct = false;
public bool Correct
{
get { return correct; }
set
{
correct = value;
NotifyPropertyChanged("Correct");
}
}
private string answerText = false;
public string AnswerText
{
get { return answerText; }
set
{
answerText = value;
NotifyPropertyChanged("AnswerText");
}
}
}
public class TestQuestions
{
private ObservableCollection<Answer> answers = new ObservableCollection<Answer>();
public ObservableCollection<Answer> Answers
{
get { return answers; }
set
{
if (answers != value)
{
answers = value;
NotifyPropertyChanged("Answers");
}
}
}
private bool showAnswer = false;
public bool ShowAnswer
{
get { return showAnswer; }
set
{
showAnswer = value;
NotifyPropertyChanged("ShowAnswer");
}
}
}
It looks to me like you're trying to bind the UIElement.Visibility to a boolean value. Change your 'ShowAnswer' property from a boolean to a Visibility property and you should be set.
private Visibility showAnswer = Visibility.Collapsed;
public Visibility ShowAnswer
{
get { return showAnswer; }
set
{
showAnswer = value;
NotifyPropertyChanged("ShowAnswer");
}
}
EDIT:
If you are trying to bind to a property on the DataContext of the parent control, you could do this:
Name your UserControl
Example:
<UserControl x:Class="MvvmLightProto.MainPage"
x:Name="mainProtoPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Height="700"
Width="1200">
In the above example, the UserControl has the name of "mainProtoPage", now in your XAML, you could do this:
<StackPanel Visibility="{Binding DataContext.ShowAnswer, ElementName=mainProtoPage}">

Resources