Binding ObservbleCollection to Combo box in XAML - Windows phone - xaml

I tried to bind an ObservableCollection variable to a ComboBox in the XAML. The data is not binding.
XAML File
<ComboBox x:Name="cmbCity" Height="44" Width="150" Grid.Row="4"
ItemsSource="{Binding}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Margin="5" Text="{Binding lstCity}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
Code behind (After navigating to another page)
protected override void OnNavigatedTo(NavigationEventArgs e)
{
UserInfo userInfo = new UserInfo();
userInfo.UserName = "Gayathri";
userInfo.Country = "India";
userInfo.State = "TN";
ObservableCollection<string> cityInfo = new ObservableCollection<string>();
cityInfo.Add("Chennai");
cityInfo.Add("Cuddalore");
cityInfo.Add("Pondicherry");
cityInfo.Add("Villupuram");
userInfo.lstCity = cityInfo;
this.DataContext = userInfo;
}
Here I am passing values in the DataContext. The data is getting bound to the textbox but not the Combobox.
Output:

You're bindings are slightly wrong.
They should be like this:
<ComboBox x:Name="cmbCity" Height="44" Width="150" Grid.Row="4"
ItemsSource="{Binding lstCity}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Margin="5" Text="{Binding}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
(I've moved the reference to lstCity)
Previously you were binding the whole DataContext to the ComboBox and then each TextBlock to the Collection of strings.
You need to bind the ItemsSource of the ComboBox to the collection and then each TextBlock should contain one of the strings.

Related

UWP Bind to ObservableCollection declaratively

I have a simple UWP page; there is a public ObservableCollection in the page code-behind:
public ObservableCollection<Book> MyObservableColl{ get; } = new ObservableCollection<Book>();
(note the collection consists of a single item)
I would like to bind to the collection; here is what I tried:
<StackPanel x:Name="stackPanel"
Grid.Row="2"
Margin="50"
DataContext="{x:Bind MyObservableColl, Mode=OneWay}">
<TextBox x:Name="txtTitle"
TextWrapping="Wrap"
Text="{x:Bind Title, Mode=OneWay}" />
</StackPanel>
The visual studio designer complains "the property Title was not found".
I appreciate any help to bind my text boxes to the Observable Collection.
the property Title was not found
txtTitle TextBox can't access Book item where in the MyObservableColl collection directly, you need place txtTitle under items control's ItemTemplate.
For example
<ListView ItemsSource="{x:Bind MyObservableColl, Mode=OneWay}">
<ListView.ItemTemplate>
<DataTemplate x:DataType="local:Book">
<StackPanel>
<TextBox Text="{x:Bind Title}" />
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
For more info please refer to listview document.
Update
For single item please refer to this xaml
<StackPanel
x:Name="stackPanel"
Grid.Row="2"
Margin="50"
DataContext="{x:Bind MyObservableColl[0], Mode=OneWay}">
<TextBox Text="{Binding Title}"/>
</StackPanel>

Check the checkbox = listviewitem row is selected

I am developing a UWP app.
I have a listview which the listviewitem has a checkbox and the content. What I need to implement is, when I check the checkbox, the related listviewitem is selected; when I uncheck it, the related listviewitem is deselected. My listview need support multi-selection.
Here is my xmal code:
<ListView Grid.Row="1" x:Name="SuggestListView" ItemsSource="{Binding SuggestList}" IsMultiSelectCheckBoxEnabled="True" IsItemClickEnabled="True" SelectionChanged="SuggestListView_SelectionChanged">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<ctl:PersonUserControl HorizontalAlignment="Left"/>
<CheckBox Name="CheckBoxhhh" HorizontalAlignment="Right" IsChecked="{Binding IsSelected, Mode=TwoWay}" Checked="CheckBox_Checked" Unchecked="CheckBox_Unchecked"/>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
<Interactivity:Interaction.Behaviors>
<Core:EventTriggerBehavior EventName="SelectionChanged">
<Core:InvokeCommandAction Command="{Binding SelectSuggestPersonCommand}"/>
</Core:EventTriggerBehavior>
</Interactivity:Interaction.Behaviors>
</ListView>
Can anybody throw me some lights?
You're on the right track but if you're wanting to use this with the IsMultiSelectCheckBoxEnabled set to true, you don't need to implement your own Checkbox in the ItemTemplate.
From what I gathered from your comments on the question, you're looking for a way to get the items from one collection to another when you're selecting from the other.
So remove the checkbox and also add the SelectionMode="Multiple" to your ListView.
In the Behavior of your ListView, you're listening for the SelectionChanged so remove this from your ListView and it should look like this:
<ListView Grid.Row="1" x:Name="SuggestListView" ItemsSource="{Binding SuggestList}" IsMultiSelectCheckBoxEnabled="True" SelectionMode="Multiple">
<ListView.ItemTemplate>
<DataTemplate>
<ctl:PersonUserControl HorizontalAlignment="Left"/>
</DataTemplate>
</ListView.ItemTemplate>
<Interactivity:Interaction.Behaviors>
<Core:EventTriggerBehavior EventName="SelectionChanged">
<Core:InvokeCommandAction Command="{Binding SelectSuggestPersonCommand}"/>
</Core:EventTriggerBehavior>
</Interactivity:Interaction.Behaviors>
</ListView>
Then in your bound Command for the SelectionChanged event you're utilising in the Behavior, you'll want to add the items that are added and removed to an ObservableCollection which you can bind to from your other ListView to show the selected ones.
The method will look something like this:
public ObservableCollection<ItemType> SelectedItems { get; private set; }
private void SelectedItemsChanged(SelectionChangedEventArgs args)
{
foreach (var item in args.AddedItems)
{
var vm = item as ItemType;
if (vm == null)
{
continue;
}
this.SelectedItems.Add(vm);
}
foreach (var item in args.RemovedItems)
{
var vm = item as ItemType;
if (vm == null)
{
continue;
}
this.SelectedItems.Remove(vm);
}
}

Toggle Button inside a canvas

I have a canvas object in my xaml that has a togglebutton and two textblocks, like this.
<ListBox.ItemTemplate>
<DataTemplate >
<Canvas HorizontalAlignment="Right" VerticalAlignment="Top" Width="485"
Margin="-15,0,-15,80" Visibility="Visible"
MouseLeftButtonUp="MandantenStackPanel_MouseLeftButtonDown">
<ToggleButton Name="FavToggle" Checked="FavChecked" Unchecked="FavUnchecked"
Style="{StaticResource CustomToggleButtonStyle}"
Foreground ="White" BorderBrush="Red" HorizontalAlignment="Left"
Canvas.Left="0" Canvas.Top="0">
<ImageBrush ImageSource="/Icons/favs.png" Stretch="UniformToFill" >
</ImageBrush>
</ToggleButton>
<TextBlock Text="{Binding MandantenNummer}" FontSize="24"
TextWrapping="Wrap" Canvas.Left="90" Canvas.Top="20"/>
<TextBlock Text="{Binding MandantenBezeichnung}" FontSize="24"
TextWrapping="Wrap" Canvas.Left="90" Canvas.Top="50"/>
</Canvas>
</DataTemplate>
</ListBox.ItemTemplate>
In my .cs i am binding a collection item to that listbox that also has a boolean called isFavorite that i'd like to toggle with my togglebutton. How can i access the data context from the canvas from inside my toggle event handlers? I tried it like i did it like i do it when you click on the textbox:
private void FavChecked(object sender, EventArgs e)
{
ClassX x = (sender as Canvas).DataContext as Class x;
x.isFavorite = true;
}
but that of course doesn't work cause my sender is the togglebutton and not the canvas. Can i access the canvas from here?
The sender is ToggleButton and not Canvas because that is the control on which you attached that event handler.
Also, DataContext is set recursively so ToggleButton inherits the same data context the parent has.

Binding from multi object in to one value in XAML

I have a ListView which have a DataTemplate like this:
<DataTemplate x:Key="FilterDataTemplate">
<StackPanel Orientation="Horizontal" Background="White" Height="50" HorizontalAlignment="Left">
<ComboBox x:Name="TermsItemComboBox" Width="160"
ItemsSource="{Binding ItemList}" Tag="{Binding}"
DisplayMemberPath="Key" SelectionChanged="AddTermsItem_SelectionChanged"
Background="#FFD1D1D1" SelectedItem="{Binding SelectedItem, Mode=TwoWay}" />
<TextBox x:Name="TermsInputTxt1" Text="{Binding FilterText, Mode=TwoWay}"
BorderBrush="#FF727272" Background="#FFD1D1D1" HorizontalAlignment="Left"
Width="200" FontSize="16" VerticalAlignment="Center"
Visibility="{Binding IsTxtForm, Converter={StaticResource BooleanToVisibilityConverter}}"
Height="45"/>
<TextBox x:Name="TermsInputTxt2" Text="{Binding FilterText, Mode=TwoWay}"
BorderBrush="#FF727272" Background="#FFD1D1D1" HorizontalAlignment="Left"
Width="200" FontSize="16" VerticalAlignment="Center"
Visibility="{Binding IsTxtForm, Converter={StaticResource BooleanToVisibilityConverter}}"
Height="45"/>
<Button x:Name="TrashBtn" HorizontalAlignment="Left" VerticalAlignment="Stretch"
BorderBrush="#FF575757" Foreground="#FF494949" BorderThickness="2" Tapped="TrashBtn_Tapped"
Style="{StaticResource DiscardAppBarButtonStyle}" Height="45" Width="55"
RenderTransformOrigin="0.5,0.5">
<Button.RenderTransform>
<CompositeTransform ScaleX="-1" />
</Button.RenderTransform>
</Button>
</StackPanel>
It's have a combobox and two TextBox. At default, the combobox don's show anything, just a blank item, I want when user type some text to the TermsInputTxt1 or TermsInputTxt2, the combobox will select the first item.
I try to bind the selectedindex of combobox with the lenght of those two textbox with a converter but look like XAML doesn't support multi binding like that.
Any suggest? Thank you!
So, this is a bit of a difficult situation. You have a couple of ways of going about it:
Bind the TermsInputTxt1 and TermsInputTxt2 to the ViewModel, with the Setter on the ViewModel controlling an ObservableCollection, adding and removing items as they get set in the property.
Create a Model for each entry with a Value field (string) and bind the Terms... to accessors in the ViewModel. Then, the ComboBox items will automatically change.
I suggest doing the first one. You'll have to have a SelectedItem/SelectedIndex property in the ViewModel which the ComboBox will bind to. You may also want to change the method by which the binding on the TextBoxs are updated, either so that they are updated immediately (lots of processing) or after it loses focus (less processing, but won't update the UI immediately).

How to bind to a list of images

I have changed my code to this:
the view:
<phone:Panorama.ItemTemplate>
<DataTemplate>
<ScrollViewer Width="800" HorizontalContentAlignment="Left" Margin="0,50,0,0">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<ListBox x:Name="list_of_images" ItemsSource="{Binding ImagesUrls}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<Image Width="300" Height="300" Source="{Binding}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ListBox>
<TextBlock Text="{Binding Title}"
Grid.Row="1"
Loaded="TextBlock_Loaded_1"
Margin="50,0,0,0"
FontSize="23"
TextWrapping="Wrap"
Width="360"
HorizontalAlignment="Left"
Foreground="Black"/>
<TextBox Text="{Binding ContactEmail}"
Grid.Row="2"
BorderBrush="Black"
Width="340"
HorizontalAlignment="Left"
BorderThickness="1"
Margin="40,0,0,0"
Foreground="Black" />
<TextBlock Text="{Binding Body}"
Grid.Row="3"
TextWrapping="Wrap"
Foreground="Black"
Margin="50,5,0,0"
Width="360"
HorizontalAlignment="Left"
FontSize="20" />
</Grid>
and I build a new object with different properties, with one of the properties being a list of strings which represents the imageurls, but I cannot get the images to show?
I have attached screenshots, what in my xaml must I change so that I can display the images, cause at the moment it doesn't show any images but it shows all the other details
code for populating collection:
ObservableCollection<ClassifiedAds> klasifiseerd_source = new ObservableCollection<ClassifiedAds>();
ImagesClassifieds new_Classifieds = new ImagesClassifieds();
ObservableCollection<string> gallery_images = new ObservableCollection<string>();
new_Classifieds.Title = klasifiseerd_source[0].Title;
new_Classifieds.ContactEmail = klasifiseerd_source[0].ContactEmail;
new_Classifieds.Body = klasifiseerd_source[0].Body;
foreach (var item in klasifiseerd_source[0].Gallery.Images)
{
var deserialized = JsonConvert.DeserializeObject<GalleryImages>(item.ToString());
gallery_images.Add(deserialized.ImageUrl);
//new_Classifieds.ImageUrls.Add(deserialized.ImageUrl);
}
new_Classifieds.ImageUrls = gallery_images;
// classifiedPanorama.ItemsSource = new_list;
new_Classifieds_list.Add(new_Classifieds);
classifiedPanorama.ItemsSource = new_Classifieds_list;
public class ImagesClassifieds
{
public string Title { get; set; }
public string ContactEmail { get; set; }
public string Body { get; set; }
public ObservableCollection<string> ImageUrls { get; set; }
}
here is the imageurl format, this works (in another par tof my app I simply bind to 1 image in this format and it works perfectly)
Depending on whether you want to just display a list of images or if you also want to be able to select them, you may either choose an ItemsControl or a ListBox. In both case you have to define a DataTemplate that controls how each item is displayed.
<ItemsControl ItemsSource="{Binding Images}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Image Source="{Binding}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
or
<ListBox ItemsSource="{Binding Images}">
<ListBox.ItemTemplate>
<DataTemplate>
<Image Source="{Binding}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Then you should think about how you define your item class. Just in case you want to be able to dynamically add or remove images from the list and let the UI be automatically updated, you should use an ObservableCollection as container type. As there is a built-in type conversion from string to ImageSource (the type of the Image control's Source property), you may simply use an ObservableCollection<string>.
public class Gal
{
public ObservableCollection<string> Images { get; set; }
}
You may create an instance of that class like so:
var gallery = new Gal();
gallery.Images = new ObservableCollection<string>(
Directory.EnumerateFiles(#"C:\Users\Public\Pictures\Sample Pictures", "*.jpg"));
Now you may directly bind to that instance by simply setting the DataContext of your Window (or wherever the image list should be shown) to this instance:
DataContext = gallery;
Note the binding declaration in the ItemsControl or ListBox above was {Binding Images}. If you really have to have a property Gallery (which I assume is in MainWindow) and bind like {Binding Gallery.Images} you may set the DataContext like this:
DataContext = this;
so I basically created a loaded event on the listbox and added this code
private void list_of_images_Loaded_1(object sender, RoutedEventArgs e)
{
ListBox lst = (ListBox)sender;
lst.ItemsSource = new_Classifieds_list[0].ImageUrls;
}
which binds the itemssource of the listbox to the list of imageurls. since I cannot access the listbox from codebehind due to it being inside the panorama's itemstemplate