So if I have a collection of variables which have been assigned data and binded to the listbox item template, how can I get the collection of data based on the selection of the listbox item?
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical" Height="500">
<Image Source="{Binding img }" Width="853" Height="480" VerticalAlignment="Top" Margin="0,10,8,0"/>
<StackPanel Width="370">
<TextBlock Text="{Binding text}" Foreground="#FFC8AB14" FontSize="28" />
<TextBlock Text="{Binding text2}" TextWrapping="Wrap" FontSize="24" />
</StackPanel>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
C#:
public class collection
{
public string text { get; set; }
public string img { get; set; }
public string text2 { get; set; }
}
private void ListBox1_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
ListBox1.SelectedItems
//how do you get the selected data in the img, text, text2 on selection?
}
Since you are binding your collection class in the ListBox, I presume that is done somewhere in the lying viewmodel on the back. The best approach then would always be to check for ListBox1.SelectedIndex and you can definitely bind it in your viewmodel too so you dont have to really access it on your codebehind. On that case you can definitely use a event to command or something like that to bind the SelectionChanged event back to the viewmodel.
If you do prefer to use the codebehind like the example you gave just check out ListBox1.SelectedIndex for single selection strategy and ListBox1.SelectedItems for multiple selection strategies.
Kindly have a look on this or this for more details on the context here. :)
You need to cast your data. e.g. using LINQ
var items = ListBox1.SelectedItems.Cast<collection>();
Then you can iterate over them using foreach or the like, or access specific items, e.g.
var text1 = items.First().text;
Related
I am trying to get the values/contents of the "selected" check-boxes so that i can use it to get data from sqlite database in the back-end . But I am unable to get the value of the checkbox from the listview.
This is the listview -
<ListView x:Name="listview" Background="Azure" SelectionMode="Multiple"
ItemsSource="{Binding Strings}" RenderTransformOrigin="0.5,0.5" Width="343">
<ListView.ItemTemplate>
<DataTemplate x:Name="datatemplate">
<CheckBox x:Name="CheckBoxZone" IsChecked="{Binding RelativeSource={RelativeSource AncestorType=ListViewItem},Path=IsSelected}"
Content="{Binding que_text}" Margin="0,5,0,0"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<Button Style="{StaticResource ResourceKey=button_style }" x:Name="addToSurvey" Content="Add" Click="AddToSurvey_Click" />
this is the function-
private void AddToSurvey_Click(object sender, RoutedEventArgs e)
{
//foreach (var item in listview.SelectedItems)
for (int i=0;i< listview.SelectedItems.Count;i++)
{
string que = listview.Items[i].ToString(); //did not work
}
}
this is the Questions class -
public class Questions
{
public int que_id { get; set; }
public string que_text { get; set; }
}
the checkbox hold the que_text value which I need to retrieve for getting the que_id from the database.
In WPF, we use what we call MVVM. Instead of going and poking at the ListViewItem controls like in winforms, we'll put properties for the information we need on our viewmodel classes, and we'll use bindings to tell the UI how to update the viewmodel classes and vice versa.
So we'll add an IsSelected property to Question. We'll also rename that class from Questions to Question, and the collection of questions will now be named Questions instead of Strings.
public class Question
{
public int ID { get; set; }
public string Text { get; set; }
public bool IsSelected { get; set; }
}
Here's your ListView. We bind CheckBox.IsSelected to ListViewItem.IsSelected, so the user can check them just by clicking anywhere on the item. Then we bind Question.IsSelected to ListViewItem.IsSelected in an ItemContainerStyle.
<ListView
x:Name="listview"
Background="Azure"
SelectionMode="Multiple"
ItemsSource="{Binding Questions}"
>
<ListView.ItemTemplate>
<DataTemplate>
<CheckBox
IsChecked="{Binding RelativeSource={RelativeSource AncestorType=ListViewItem}, Path=IsSelected}"
Content="{Binding Text}" Margin="0,5,0,0"
/>
</DataTemplate>
</ListView.ItemTemplate>
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="IsSelected" Value="{Binding IsSelected}" />
</Style>
</ListView.ItemContainerStyle>
</ListView>
And here's how we do stuff with the selected questions in that event handler. I'm guessing that your Strings collection was a member of the Window or whatever view you have; let me know if that's not the case and we'll figure out how to get to it. Remember, we're calling that collection Questions now.
private void AddToSurvey_Click(object sender, RoutedEventArgs e)
{
string allQuestionsText = "";
foreach (var question in Questions.Where(q => q.IsSelected))
{
// I don't know what you really want to do in here, but it sounds like you do.
allQuestionsText += question.Text + "\n";
}
}
I'm new to wpf, I created a listbox it will create a dynamic listitems,Here I used datetemplate which contains two controls that is two textblocks, one textblocks contains binding a values form combobox(which is string datatype),The other one is, bind a value from code bind.
XAML
<ListBox ItemsSource="{Binding obj}" HorizontalContentAlignment="Left" x:Name="lstbxindex" SelectionMode="Extended" Foreground="White" FontSize="20px" Height="201" BorderBrush="#555555" Margin="80,40,0,0" VerticalAlignment="Top" Width="282" Background="#555555" >
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Margin="5" >
<TextBlock Height="40px" Width="80px" Text="{Binding roundedhourvalue, FontSize="24" Background="#555555" Foreground="White"></TextBlock>
<TextBlock x:Name="items" Text="{Binding}" Margin="35,0,0,0"></TextBlock>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
C# (Roundedhour.cs)
public class Roundedhour
{
public string hourvalue { get; set; }
public override string ToString()
{
return string.Format("{0}", hourvalue);
}
}
In this class create a property for hourvalue. For this class I created a object in codebehind file which I mentioned below.create a object and assign a value for hourvalue variable.
C# (Code Behind)
{
if (dispatcherTimer1.Interval == TimeSpan.FromSeconds(15))
{
//lstbxindex.Items.Add(lstbxindex.SelectedItem.ToString());
string hrvalue = Convert.ToString(hrvalueinitially);
obj = new Roundedhour();
obj.hourvalue = Convert.ToString(hrvalueinitially);
string roundedhourvalue =obj.hourvalue;
this.DataContext = this;
//lblprojectAhr.Content = string.Join(",", hrvalueinitially + "" + "hr");
}
}
Here, I created a object for Rounderhour class.Assign values to that property hour value. But I cannot be bind a value from codebind to XAML page.
Your ItemsSource should be of an CollectionType.
ListBox ItemsSource="{Binding obj}"
You should also start to give your variables and properties meaningful names. That makes it easier to read your code later on.
The second Problem is in your Binding itself.
You are binding like this: Text="{Binding roundedhourvalue}
So WPF is expecting a property roundedhourvalue on obj.
But as shown in your CodeBehind there is only obj.hourvalue.
So change your Binding to Text="{Binding hourvalue}
Check your Output-Window for details.
NOTE:
string roundedhourvalue = obj.hourvalue;
has no getter and is not accsessible since its private.
NOTE: You either use a Binding OR your set the ItemsSource in CodeBehind.
Try it like this:
Just remove all the formatting and stuff:
<ListBox ItemsSource="{Binding RoundedHours}" x:Name="ListBox">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Margin="5" >
<TextBlock Text="{Binding hourvalue}"></TextBlock>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
And change your code-behind to this:
private void UpdateDataContext(object hrvalueinitially)
{
List<Roundedhour> hours = new List<Roundedhour>();
hours.Add(new Roundedhour()
{
hourvalue = hrvalueinitially.ToString()
});
//Set the ItemsSource in code: => remove your ItemsSource Binding from XAML
listBox.ItemsSource = hours;
}
OR your can use an 'MVVM' approach:
public class MyViewModel : INotifyPropertyChanged
{
//IMPLEMENT INotifyPropertyChanged HERE PLS
public ObservableCollection<RoundedHour> Collection { get; set; } = new ObservableCollection<RoundedHour>();
private void AddToCollection(object hrvalueinitially)
{
Collection.Add(new RoundedHour()
{
hourvalue = hrvalueinitially.ToString()
});
OnPropertyChanged("Collection");
}
//Make sure to set your Windows DataContext to an Instance of this Class
}
Assign XAML object's "ItemsSource" property with your binding variable.
Also it's totally wrong binding object's itself into object's property like
this.DataTemplate = this;
Use:
List<yourobject> bindingObjectList = new List<yourobject>();
// insert your objects into the list
this.ItemsSource = bindingObjectList;
Here you can find an example:
Grid & Pivot Binding Example for multiple DataTemplates
when I bind data to the listpicker, I get name displayed in selected item, but when the dropdown shows the whole item will be myProject.MyClass....something
I am new to windows phone application development.. Can anyone help me with this?
here is my xaml code
<toolkit:ListPicker Header="Select Name" Name="listName" Tap="listName_Tap" VerticalAlignment="Center">
<toolkit:ListPicker.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding name}"/>
</StackPanel>
</DataTemplate>
</toolkit:ListPicker.ItemTemplate>
</toolkit:ListPicker>
Here is my c# code
class MyClass
{
public String name{ get; set; }
}
private void sendPostCompleted(object sender, UploadStringCompletedEventArgs e)
{
//e.result is my json string obtained from webservice([{name:hhh}{name:jkj}{name:jack}])
var data = JsonConvert.DeserializeObject<MyClass[]>(e.Result.ToString());
listName.ItemsSource = data;
}
Try this below code :
<toolkit:ListPicker Header="Select Name" Name="listName" Tap="listName_Tap" VerticalAlignment="Center" ItemsSource={Binding NamesList}>
<toolkit:ListPicker.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding name}"/>
</StackPanel>
</DataTemplate>
</toolkit:ListPicker.ItemTemplate>
</toolkit:ListPicker>
In Code behind, Add the following :
private ObservableCollection<MyClass> _NamesList = new ObservableCollection<MyClass>();
public ObservableCollection<MyClass> NamesList
{
get {return _NamesList}
set {_NamesList = value}
}
Add below code in constructor
this.DataContext = this;
Copy the array data to observablecollection
private void sendPostCompleted(object sender, UploadStringCompletedEventArgs e)
{
//e.result is my json string obtained from webservice([{name:hhh}{name:jkj}{name:jack}])
var data = JsonConvert.DeserializeObject<MyClass[]>(e.Result.ToString());
foreach (var item in data)
{
NamesList.Items.Add(item);
}
}
Note : Use ObservableCollection for binding list UI controls for updating UI data while property changes.
I am not so sure but I think the problem is with the binding. You're binding an Array, instead of it try List:
var data = JsonConvert.DeserializeObject<List<MyClass>>(e.Result.ToString());
You also need to add JsonProperty to your class property (ref):
class MyClass
{
[JsonProperty("name")]
public String name{ get; set; }
}
I submitted this accidently, I fixed it myself and wasn't going to submit after writing out the question. But have learnt from the comments, thanks!
I am trying to create a simple todo app in win8 and eventually want to hock it into ToDoIst API.
I have created a simple task class to try and get my head around the databinding however I just can not get it to do what I want to do. I have used listboxes and other basic form elements.
task.cs
class task
{
private string content;
private bool complete;
public string Content
{
get {return content;}
set { content = value; }
}
public bool Complete
{
get { return complete; }
set { complete = value; }
}
public task(string content)
{
Content = content;
Complete = false;
}
}
MainPage.xaml
And at the moment my XAML looks like this.
<GridView HorizontalAlignment="Left" Margin="482,190,0,0" VerticalAlignment="Top" Width="400" Height="500">
<ListView x:Name="LVtasks" HorizontalAlignment="Left" Height="500" VerticalAlignment="Top" Width="400" ItemsSource="{Binding}">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Content}"/>
<RadioButton/>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</GridView>
I have put in some dummy data, 4 elements and when I run it, it comes up with 4 boxes with radio buttons however no text (there is space for the text) I am not sure how I would bind the bool?
I can not see what I am doing wrong. If anyone could help and point me in the right direction, I have searched a fair amount of tutorials and just can not figure it out.
Your code looks a little strange, maybe this is what you want:
<ListView x:Name="LVtasks" HorizontalAlignment="Left" Height="500" VerticalAlignment="Top" Width="400" ItemsSource="{Binding ToDoItems}">
<ListView.ItemTemplate>
<DataTemplate>
<RadioButton GroupName="ToDos" Content="{Binding Content}" IsChecked="{Binding IsComplete}"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Do you really want radiobuttons? I think you want Checkboxes, the difference is that when you use radiobuttons only one in a group can be 'checked'
I used this code behind to have a datacontext:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
ToDoItems = new ObservableCollection<TodoItem>(new List<TodoItem>
{
new TodoItem("Content1"),
new TodoItem("Content2")
});
this.DataContext = this;
}
public ObservableCollection<TodoItem> ToDoItems { get; set; }
}
I changed the name of task to ToDoItem Task is already a class in the framework and might cause confusion.
For the RadioButton IsChecked is the property to bind to a bool property:
<RadioButton IsChecked="{Binding Path=Complete}"/>
Your text is most likely not showing up because you haven't set up any change notifications and the binding is happening before you set the Content values. Using the INotifyPropertyChanged interface is the most common and usually the easiest way to do this.
Like John already mentioned you should really let the window containing your listview implement the INotifyPropertyChanged interface. And to set the data context of your window like Johan said. It is important that you call the propertychanged method in each setter of a property. It is also useful to use an ObservableCollection as ItemSource of your listview. Try to create an instance of ObservableCollection, create a property for it calling propertychanged method in its setter an set rhe ItemSource of your listview to the property. Do not forget to also call propertychanged whenever you add or remove items from the collection
I'm databinding a listbox to an object that contains two array of strings. Each listbox item is set to a data template made up of a textbox and a combo box. The first string array is bound to the list, and the second string array is bound to the combo box. Well, at least that's I'm trying to achieve. The problem is that I can't figure out the binding syntax to set the second array to the combo box. Here's what I have:
The first thing is my class with my two string arrays. Pretty straightforward. Please note that the string array content is there for simplicity.
public class JobAssignments
{
public JobAssignments()
{
m_people.Add("John");
m_people.Add("Bill");
m_people.Add("Frank");
m_people.Add("Steve");
m_jobs.Add("Architect");
m_jobs.Add("Teacher");
m_jobs.Add("Carpenter");
m_jobs.Add("Plumber");
}
private List<string> m_people = new List<string>();
public List<string> People { get { return m_people; } set { m_people = value; } }
private List<string> m_jobs = new List<string>();
public List<string> Jobs { get { return m_jobs; } set { m_jobs = value; } }
};
In code, I set an instance of this class as the datacontext of this listbox:
<ListBox x:Name="listBox"
Grid.Row="0"
HorizontalContentAlignment="Stretch"
DataContext="{Binding}"
ItemsSource="{Binding People}"
ItemTemplate="{StaticResource JobAssignmentDataTemplate}">
</ListBox>
With a data template that looks like this:
<DataTemplate x:Key="JobAssignmentDataTemplate">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0"
Text="{Binding}"/>
<ComboBox Grid.Column="2"
SelectedIndex="0"
ItemsSource="{Binding Jobs ???? }"/>
</Grid>
</DataTemplate>
What I usually get out my experiments is a list box of People, but the combo box of each list item is empty.
I can get it to work if I use
ItemsSource="{Binding ElementName=listBox, Path=DataContext.Jobs }"/>
but I don't want to use ElementName as it hardcodes the source of the array a specific listbox which I'd like to avoid.
Trying something like
ItemsSource="{Binding RelativeSource={RelativeSource Self}, Path=Parent.Jobs}"/>
Doesn't seem to work either as it's looking for Jobs inside the Grid.
A little push in the right direction would help greatly.
Thanks!
I had roughly the same problem as you except I had a listbox within a tabcontrol. I was able to solve it by using getting the tab control that contained the listbox. Sample code as follows:
<TabControl ItemsSource="{Binding Groups, Mode=TwoWay}" SelectedItem="{Binding SelectedGroup, Mode=TwoWay}">
<TabControl.ContentTemplate>
<DataTemplate>
<ListBox ItemsSource="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=TabControl, AncestorLevel=1}, Path=DataContext.ItemsInGroup, Mode=TwoWay}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding ItemGroup}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
When you are at DataTemplate that represents just one People your JobAssignments instance is not there. Try the below
ItemsSource="{Binding ElementName= listBox, Path=Jobs}"/>
But I dont recommend the above step. You need to refactor your ViewModel logic. I guess 'Jobs' can be a static instance so that you can do a x:Static binding
ItemsSource="{Binding Source={x:Static JobAssignments}, Path=Jobs}"
You probably need to modify your object structure to work like this:
public class Person
{
public string Name;
public IEnumerable<string> Jobs;
}
public class JobAssignments
{
public JobAssignments()
{
Jobs.Add("Architect");
...
People.Add(new Person() { Name = "Bob", Jobs = Jobs });
...
}
private List<Person> m_people = new List<Person>();
public List<Person> People { get { return m_people; } }
private List<string> m_jobs = new List<string>();
public List<string> Jobs { get { return m_jobs; } }
}
Then, you can remove the question marks, and things should work.