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
Related
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;
Edit: The basic problem is binding a List to ListBox(or any other control). So I am editing the question.
I bound a list of string to a ListBox as below. However when I change the contents of the textbox it is not changing the string in the source list.Why?
public partial class MainWindow : Window
{
List<string> _nameList = null;
public List<string> NameList
{
get
{
if (_nameList == null)
{
_nameList = new List<string>();
}
return _nameList;
}
set
{
_nameList = value;
}
}
public MainWindow()
{
NameList.Add("test1");
NameList.Add("test2");
InitializeComponent();
}
And the XAML
<ListBox Grid.Row="0" Grid.Column="0" DataContext="{Binding ElementName=main}" ItemsSource="{Binding NameList}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBox Text="{Binding .,Mode=OneWayToSource , UpdateSourceTrigger=PropertyChanged}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
The DataContext of each ListBoxItem is the string itself, so the path of your binding is empty (.). TwoWay and OneWayToSource bindings require a path, since you can't just replace the current DataContext. So you need to wrap your string in an object that exposes the string as a property:
public class StringItem
{
public string Value { get; set; }
}
Expose the strings as a list of StringItem:
public partial class MainWindow : Window
{
List<StringItem> _nameList = null;
public List<StringItem> NameList
{
get
{
if (_nameList == null)
{
_nameList = new List<StringItem>();
}
return _nameList;
}
set
{
_nameList = value;
}
}
public MainWindow()
{
NameList.Add(new StringItem { Value = "test1" });
NameList.Add(new StringItem { Value = "test2" });
InitializeComponent();
}
And bind to the Value property:
<ListBox Grid.Row="0" Grid.Column="0" DataContext="{Binding ElementName=main}" ItemsSource="{Binding NameList}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBox Text="{Binding Value, UpdateSourceTrigger=PropertyChanged}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Note that StringItem will also need to implement INotifyPropertyChanged so that bindings are automatically updated. You should also expose the list as an ObservableCollection<T> rather than a List<T>
May be it helsp?
<ListBox Name="lsbList">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBox Text="{Binding Path=Value}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
you can create a DataGridTemplateColumn.CellEditingTemplate with an itemscontrol and textboxes to edit your items
If I didn't misunderstand your question, it is pretty easy to implement. Look:
<ComboBox Text="My Comment 5 with addition." IsEditable="True" Height="25" Width="200">
<ComboBoxItem>My comment1</ComboBoxItem>
<ComboBoxItem>My comment2</ComboBoxItem>
</ComboBox>
The binding on my ItemsControl ItemsTemplate does not work. I've gone through some other similar stack overflow questions but I cannot figure out the problem with my binding. Can someone please show me what I am doing wrong with my binding?
Excerpt from my MainWindow's ViewModel;
private ObservableCollection<uint> words;
private uint word;
private int numberOfWords;
public ObservableCollection<uint> Words
{
get
{
return this.words;
}
set
{
this.words = value;
this.NotifyPropertyChanged(m => m.Words);
}
}
public uint Word
{
get
{
return this.word;
}
set
{
this.word = value;
this.NotifyPropertyChanged(m => m.Word);
}
}
public int NumberOfWords
{
get
{
return this.numberOfWords;
}
set
{
this.numberOfWords = value;
this.NotifyPropertyChanged(m => m.NumberOfWords);
this.Words.Clear();
for (uint x = 0; x < value; x++)
{
this.Words.Add(this.Word);
}
}
}
I have the below ItemsControl inside a user control. The MainWindow has its DataContext set to a ViewModel, which the ItemsControl uses. The ItemsSource binding works and I get however many textboxes I specify, but when putting a value in the TextBox, the binding does not work.
<ItemsControl Grid.Row="0" Grid.Column="1" Grid.RowSpan="8" ItemsSource="{Binding Words}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBox Text="{Binding Word}" Width="125" Height="25" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
I saw one post that talks about using this type of binding below, but apparently, I do not understand FindAncestor, so I do not know if I am on the right track or not with this.
Text="{Binding Path=Word, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ItemsControl}}}"
You cannot bind to elements in a collection and then change the element itself--you can only change properties of this element through the binding. In other words, given the following collection
[ "one", "two", "three" ]
through a binding such as
<TextBox Text="{Binding Words[0]} /> <!-- the word "one" is displayed in the tb -->
if you change "one" to "derp" you would not alter the collection to
[ "derp", "two", "three" ]
To apply this to your example, you would want to bind the collection to the ItemsControl, then in the template bind to each instance within the collection and change properties of this instance.
First, create your Model. This holds your data and is what you bind against in the UI.
public sealed class Word
{
public uint Value {get;set;}
}
Next, expose a collection of these on your View Model.
public sealed class ViewModel
{
//create and fill in ctor
public ObservableCollection<Word> WordsYo {get;private set;}
}
Next, bind your ItemsControl's ItemsSource to this property and bind elements in the template to the properties of Word:
<!-- Window.DataContext is set to an instance of ViewModel -->
<ItemsControl ItemsSource="{Binding WordsYo}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBox Text="{Binding Value}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
The Aristocrats.
I´m trying to bind a ListBox to a ObservableCollection. I wan´t to bind the Text Properties of the ListBox entrys and the Background of the ListBox entrys.
The ListBox is defined in an loaded loose xaml file:
<TextBox Margin="0,5,5,5" Text="{Binding Path=TB9P}" Background="LightBlue" Name="DetailsviewTB9" Height="20">
<TextBox.ToolTip>
<StackPanel>
<Label FontWeight="Bold" Background="Blue" Foreground="White">Daten</Label>
<ListBox ItemsSource="{Binding Source={StaticResource res_LB1P}}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=StringP}" Background="{Binding Path=SelectedItemP, Converter={StaticResource c_SelectedItemToBackgroundConverter}}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
</TextBox.ToolTip>
</TextBox>
The DataContext is set on class DetailsViewText
public class LBEntry
{
bool DetailsViewLBSelectedItem = true;
string DetailsViewLB = "test";
public LBEntry(bool selcected, string str)
{
DetailsViewLB = str;
DetailsViewLBSelectedItem = selcected;
}
public bool SelectedItemP
{
get { return DetailsViewLBSelectedItem; }
set { DetailsViewLBSelectedItem = value; }
}
public string StringP
{
get { return DetailsViewLB; }
set { DetailsViewLB = value; }
}
}
public class LBEntrysCollection : System.Collections.ObjectModel.ObservableCollection<LBEntry>
{
//
}
public class DetailsViewText
{
string[] DetailsViewTB1_Text = new string[20];
bool[] fDetailsViewCB = new bool[20];
LBEntrysCollection[] LBEntrys = new LBEntrysCollection[]{
new LBEntrysCollection{ new LBEntry(false, "test"), new LBEntry(true, "test") },
new LBEntrysCollection{ new LBEntry(true, "test") },
new LBEntrysCollection{ new LBEntry(false, "test") },
new LBEntrysCollection{ new LBEntry(false, "test") },
new LBEntrysCollection{ new LBEntry(false, "test") }
};
public LBEntrysCollection LB1P
{
get { return LBEntrys[0]; }
set { LBEntrys[0] = value; }
}
public string TB9P
{
get { return DetailsViewTB1_Text[8]; }
set { DetailsViewTB1_Text[8] = value; }
}
...
}
The resource res_LB1P is set in the mainWindow constructor:
// Resources
this.Resources.Add("res_LB1P", detailsViewFrameHandling.DetailsViewTextP.LB1P);
Basicly I just want to bind the ListBox to a LBEntrysCollection with SelectedItemP as switch for the background Color and StringP as the Text Property. But I need the DataContext on DetailsViewText for other Propertys.
I´m getting an Exception when the xaml File is loading the StaticResource res_LB1P.
How do I have to set my Binding on ListBox and TextBlock to get it right?
EDIT:
With this
<ListBox ItemsSource="{Binding Path=LB1P}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=LB1P.StringP}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Items are added, but there is no Text shown in the TextBox
Now I´m really confused. It does work like this:
<ListBox ItemsSource="{Binding Path=LB1P}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=StringP}" Background="{Binding Path=SelectedItemBrushP}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Simple enough, but I thought i had tried this before and it didn´t work...
Is it possible, that if one Binding does fail (the Background Binding) the other Binding (Text Property) does also not work?
I have always considered the ViewModel (the object the DataContext points to) to be just that: a Model of the View.
So to solve this, you need either one object that will be the ViewModel because there is only one DataContext property or you will need to add an extra DataContext-like property.
The first option (one ViewModel) can be realized by creating a new class that contains both the ObservableCollection and the DetailsViewText:
class ComposedViewModel: INotifyPropertyChanged
{
public LBEntrysCollection LBEntries
{
get { ... }
set { ... }
}
public DetailsViewText Details
{
get { ... }
set { ... }
}
}
The second option (extra DataContext-like property) can be realized by sub-classing the ListBox and adding another property.
Why not do this ?
<ListBox ItemsSource="{Binding ElementName=<TextBox's Name>, Path=DataContext">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=StringP}" Background="{Binding Path=SelectedItemP, Converter={StaticResource c_SelectedItemToBackgroundConverter}}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Correct me if I'm wrong with understanding your question. You want to bind the listbox's itemssource to the textbox's datacontext?
I have the following XAML:
...
<ListBox Name ="RoomsListBox" Height="100"
HorizontalAlignment="Left" Margin="12,41,0,0"
VerticalAlignment="Top" Width="120"></ListBox>
...
And the following C#-code:
protected override void OnNavigatedTo(NavigationEventArgs e)
{
RoomsListBox.ItemsSource = new[] { new { Name = "First1" },
new { Name = "First2" } };
RoomsListBox.DisplayMemberPath = "Name";
}
The problem is that my ListBox have items but they are empty. Why I don't see "First1" and "First2" instead?
The issue here isn't with the bindings nor the ItemTemplate nor the change notification. It's the Anonymous Type you're using that's causing it. try using a class or struct for your items
public class Item
{
public string Name { get; set; }
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
RoomsListBox.ItemsSource = new[] {
new Item { Name = "First1" },
new Item { Name = "First2" }};
RoomsListBox.DisplayMemberPath = "Name";
}
your xaml stays the same, or you can define a DataTemplate for the ListBox items if you want. Note that you can't set both the ItemTemplate and DisplayMemberPath at the same time (one has to be null). Also, make sure that the class representing your items has to be public.
Hope this helps :)
Just a thought..
Have you tried settings the DisplayMemberPath property in XAML? There might be an issue with the order of calls.
You have to set DisplayMemberPath property on your ListBox to Name.
Moving forward you might want to consider creating a DataTemplate for your items to have more control:
<ListBox x:Name ="RoomsListBox" Height="100"
HorizontalAlignment="Left" Margin="12,41,0,0"
VerticalAlignment="Top" Width="120">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Name}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
See this tutorial for more info: http://weblogs.asp.net/scottgu/pages/silverlight-tutorial-part-5-using-the-listbox-and-databinding-to-display-list-data.aspx
I would prefer that you define your binding in your xaml and for example in your Code-Behind you define a property for the items of your listbox.
Example: (xaml)
<ListBox Name ="RoomsListBox"
ItemsSource="{Binding MyItems}"
Height="100"
HorizontalAlignment="Left"
Margin="12,41,0,0"
VerticalAlignment="Top"
Width="120" />
Example: (C# in your code-behind)
//...
private ObservableCollection<string> _myItems;
public ObservableCollection<String> MyItems
{
get
{
return _myItems ?? (_myItems = new ObservableCollection<string> { "FirstItem", "SecondItem"});
}
set
{
_myItems = value;
}
}
Like ChrisF said you could use the INotifiyPropertyChanged Interface, there you would raise the PropertyChanged event in the setter of your property.
See --> http://msdn.microsoft.com/en-us/library/system.componentmodel.inotifypropertychanged.aspx