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>
Related
i have MyPage.xaml and MyPage.xaml.cs files.
Into .xaml file i written a data template like this:
<DataTemplate x:Key="MyDataTemplate" x:DataType="local:MyClass">
...
<TextBlock Text="{x:Bind name}" HorizontalAlignment="Left" TextWrapping="Wrap"/>
...
</DataTemplate>
I can bind name attribute of MyClass correctly.
Now i need to bind an attribute of .xaml.cs file but DataTemplate show me only MyClass data. How can i bind data from .xaml.cs page? Outside DataTemplate (but in the same xaml file) i can see any attribute of .xaml.cs file.
I need to bind a List of objects to a combobox like this:
<ComboBox ItemsSource="{x:Bind myList}" HorizontalAlignment="Left"></ComboBox>
but myList is an .xaml.cs attribute.
I want to view a string name attribute of objects of the list.
Thank you for your help
uwp: how to bind data inside DataTemplate outside of x:DataType?
For your recrement, we suggest you use Binding to replace x:Bind, You could use Binding to access current root DataContext with ElementName.
For example
<Grid x:Name="GridRoot">
<ListView ItemsSource="{Binding Items}">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name}" />
<ComboBox ItemsSource="{Binding ElementName=GridRoot, Path=DataContext.Options}" />
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
Code Behind
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
this.DataContext = this;
}
public List<string> Options { get; set; } = new List<string>() {"One","Two","Three" };
public List<Item> Items { get; set; } = new List<Item>()
{
new Item { Name = "HH" },
new Item { Name = "ZZ" },
new Item { Name = "MM" }
};
}
public class Item
{
public string Name { get; set; }
}
I have the ListBox on my MainView.xaml, selecting the Item forces the ContentControl to display different UserControls. I use Caliburn.Micro library in this propgram. Here's some code:
<ListBox Grid.Row="1" Grid.Column="1" x:Name="ItemsListBox" SelectedItem="0" ItemsSource="{Binding Items}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<TextBlock Grid.Row="2" Grid.Column="1" Text="{Binding TextBlock1Text}" x:Name="TextBlock1"/>
<ContentControl Grid.Row="3" Grid.Column="1" Content="{Binding ElementName=ItemsListBox, Path=SelectedItem.Content}" />
The MainViewModel.cs:
private string _name;
public string Name
{
get => _name;
set
{
_name = value;
NotifyOfPropertyChange(() => Name);
}
}
private string _textBlock1Text;
public string TextBlock1Text
{
get => _textBlock1Text;
set
{
_textBlock1Text = value;
NotifyOfPropertyChange(() => TextBlock1Text);
}
}
public MainViewModel()
{
TextBlock1Text = "Test";
Items = new ObservableCollection<ItemsModel>()
{
new ItemsModel { Name="Useless", Content=null },
new ItemsModel { Name="TextChangerViewModel", Content=new TextChangerViewModel(TextBlock1Text) }
};
}
public ObservableCollection<ItemsModel> Items { get; set; }
The ItemsModel.cs:
public class ItemsModel
{
public string Name { get; set; }
public object Content { get; set; }
}
And finally the TextChangerViewModel.cs:
public class TextChangerViewModel : Conductor<object>
{
private string _textBlock1Text;
public string TextBlock1Text
{
get => _textBlock1Text;
set
{
_textBlock1Text = value;
NotifyOfPropertyChange(() => TextBlock1Text);
}
}
public TextChangerViewModel(string textBlock1Text) //passing parameter from another ViewModel
{
TextBlock1Text = textBlock1Text;
}
}
So, the main question is how to change the TextBlock1Text (and the Text value of TextBlock in .xaml as well) in the MainViewModel.cs from the TextChangerViewModel.cs? I was thinking about using something like NotifyCollectionChanged on my Items ObservableCollection, but it work with collection of ItemsModel, not with the VM's, so I'm stuck here.
I'm also not sure if having public object Content { get; set; } in ItemsModel.cs is a good thing if I'm targeting the MVVM pattern, but I don't know the other way to do it (I'm very new to MVVM).
UPD
I'm looking for the property-changing way because I need to change the TextBlock1Text Text from another UserControl. Suppose I have the button on my TextChangerView.xaml: <Button Grid.Row="0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Content="Change da text" cal:Message.Attach="ChangeTextButton"/>
And after the click on it I want the text on the parental MainView.xaml to change. But the thing is, I don't know how to change properties in this case, as I wrote above why.
Change the the binding of textblox1 to reference the selected item.
<TextBlock Grid.Row="2" Grid.Column="1" Text="{Binding ElementName=ItemsListBox, Path=SelectedItem.Name}" x:Name="TextBlock1"/>
or
<TextBlock Grid.Row="2" Grid.Column="1" Text="{Binding ElementName=ItemsListBox, Path=SelectedItem.Content.TextBlock1Text}" x:Name="TextBlock1"/>
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
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'm completely new to WPF.
I'm making a simple application in the MVVM pattern.
I have a viewmodel with a model referenced in it. The model contains some netelements I want to put in a combobox.
Here is the relevant part of the viewmodel:
public class MainWindowVM : ViewModelBase
{
private Model _model = null;
public Model Model
{
get
{
return _model;
}
}
#region ActiveElement
private NetElement _activeElement = null;
public NetElement ActiveElement
{
get
{
return _activeElement;
}
set
{
if (_activeElement != value)
{
_activeElement = value;
RaisePropertyChanged("ActiveElement");
if (ActiveElementChanged != null)
ActiveElementChanged(this, EventArgs.Empty);
}
}
}
}
I would like to be able to select a NetElement in a combobox and set the ActiveElement to it.
here is the relevant part of my current XAML:
<ItemsControl Background="White" IsTabStop="True" ItemsSource="{Binding Path=Model.RootNet.Elements}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Margin="2,6">
<Hyperlink Command="{Binding Path=I'm not able to figure out what to write here}">
<TextBlock Text="{Binding Path=Name}" />
</Hyperlink>
</TextBlock>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
This is not a combobox but a list of TextBlocks, but you can see where it is going.
How can I set the ActiveElement from the view?
Create a binding for the SelectedItem property of the ComboBox to your ActiveElement property:
<ComboBox SelectedItem="{Binding Path=ActiveElement}" ... />
then set the DataContext property of the view to your view model.