I'm trying to each element I add a unique name which I get from the loop. How can I accomplish it? The line 2 is where is the error.
foreach (var station in stations) {
TextBlock station.name = new TextBlock(); // error !!!
}
Try this instead...
TextBlock station = new TextBlock() { Name="Something" };
Maybe I'm misunderstanding what you want to do... Are you trying to create controls for each member of a collection? If that's what you're doing, try looking at a ListBox, or a more generic ItemsPresenter control, and the ItemTemplate property of that element.
For example, add a ListBox to your XAML, and assign stations as it's ItemsSource, then add a DataTemplate to represent the items.
<ListBox ItemsSource="{Binding stations}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding name}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Your trying to create an new instance of textblock on the name property of the textblock instance station.
That is definitely not going to work.
Try:
TextBlock station = new TextBlock();
station.name = "Whatever name you want";
Related
There is list with columns to display. I am using ListView with data templates for cells. And my problem is to access both: row and column from template.
Below is demo, xaml:
<ListView x:Name="listView" ItemsSource="{Binding Items}">
<ListView.Resources>
<GridViewColumn x:Key="Column" x:Shared="False">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock>
<Run Text="{Binding WhatHere}" /> <!-- problem here -->
<Run Text="{Binding Mode=OneWay}" />
</TextBlock>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</ListView.Resources>
<ListView.View>
<GridView />
</ListView.View>
</ListView>
and the code:
public partial class MainWindow : Window
{
public List<string> Items { get; } = new List<string> { "1", "2", "3" };
public MainWindow()
{
InitializeComponent();
DataContext = this;
var a = (GridViewColumn)listView.FindResource("Column");
a.Header = "a";
((GridView)listView.View).Columns.Add(a);
var b = (GridViewColumn)listView.FindResource("Column");
b.Header = "b";
((GridView)listView.View).Columns.Add(b);
}
}
will produce
My aim is to have:
a b
a1 b1
a2 b2
a3 b3
Possible? How do I pass column to DataTemplate ? In fact I want to simply know to which column current cell belongs, but please consider following:
This is simplified case.
In reality data templates are more complicated: many elements with bindings, triggers, etc.
In reality column related data are more complicated than just header.
Columns will be generated at runtime with different headers, etc.
Adding columns and setting Header in code-behind is not a problem, DataTemplate is.
I was thinking to use attached property on GridViewColumn, however, it's not parent of cells in the visual tree:
If you want to pass parameter to data template, then you need more MVVM (c) unknown wpf programmer
#mm8, was right, my design lack one more abstraction to hold column information (column name). I've to create column view model (simplified again):
public class ViewModelColumn
{
public string Column { get; }
public ViewModelColumn(string column)
{
Column = column;
}
}
and the code to add column will become something like
var a = new FrameworkElementFactory(typeof(ContentControl));
a.SetValue(ContentControl.ContentProperty, new ViewModelColumn("a"));
((GridView)listView.View).Columns.Add(new GridViewColumn
{
Header = "a",
CellTemplate = new DataTemplate { VisualTree = a }
});
Cell data template is created in code behind. The idea is to supply ContentControl for all cells with column instance bound to Content, then the view needs another data template (this time fully defined in xaml), to know how to visualize it:
<DataTemplate DataType="{x:Type local:ViewModelColumn}">
<TextBlock>
<Run Text="{Binding Column, Mode=OneTime}" />
<Run Text="{Binding DataContext,RelativeSource={RelativeSource AncestorType={x:Type ListViewItem}}, Mode=OneWay}" />
</TextBlock>
</DataTemplate>
Such cell DataContext contains column information. To access row (access item from Items), we have to use ListViewItem.DataContext.
Now the view will looks like this:
I am pretty happy about this solution, mostly about combination of things what makes it working, but I guess it could be improved. Hopefully after posting the answer the question become clearer.
Let's say you have one Listbox in WPF with items such as 1,2,3,4,5 etc. How do you make another Listbox, right next to first one, that shows its items according to selection in the first Listbox? So if you select "item 2" in Listbox you'd get 2A, 2B,2C etc in Listbox2, if you select "item 3" you'd get 3A, 3B, 3C etc in Listbox3
Can't embed the picture yet but here's the example of what i need
There is an example of how to implement such cascading ComboBoxes according to the recommended MVVM design pattern available here: https://blog.magnusmontin.net/2013/06/17/cascading-comboboxes-in-wpf-using-mvvm/
You could bind the SelectedItem property of the first ListBox to a source property of your view model. In the setter of this one you then set another collection property that you bind the ItemsSource property of the second ListBox to, e.g.:
<ListBox ItemsSource="{Binding Numbers}" SelectedItem="{Binding SelectedNumber}" />
<ListBox ItemsSource="{Binding SubNumbers}" />
private object _selectedNumber;
public object SelectedNumber
{
get { return _selectedNumber; }
set
{
_selectedNumber = value;
NotifyPropertyChanged();
//set items
SubNumbers = new List<string> { "3A", "3B", "..." };
NotifyPropertyChanged("SubNumbers");
}
}
Make sure that your view model class implements the INotifyPropertyChanged interface and raises change notifications for this to work: https://msdn.microsoft.com/en-us/library/system.componentmodel.inotifypropertychanged(v=vs.110).aspx
Alternatively, if your model classes are defined in such a way that each item in the first ListBox has a collection property that returns its related items, you could bind the second ListBox directly to a property of the SelectedItem in the first one:
<ListBox x:Name="lb1" ItemsSource="{Binding Numbers}"/>
<ListBox x:Name="lb2" ItemsSource="{Binding SelectedItem.SubProperty, ElementName=lb1}" />
I bind my combobox from entityframework and when I try to get value from my combobox by selecting value it gives back text like this {NameOfCompany = Name } How can i get only the value Name?
Thats the code in xaml
<ComboBox SelectionChanged="ComboFirma_SelectionChanged" Name="ComboFirma" Margin="109,10,10,0" Height="28" VerticalAlignment="Top">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Name="txbCombo" Text="{Binding NameOfCompany}"></TextBlock>
</DataTemplate>
</ComboBox.ItemTemplate>
And I bind it like this.
var query2 = from f in model.Firmas
select new
{
f.NameOfCompany
};
ComboFirma.ItemsSource = query2.ToList();
I tried something like this to gets the selected value but always i get an exception.
var str = (TextBox)ComboFirma.Template.FindName("txbCombo", ComboFirma);
lblCompanyNameShow.Content = str.SelectedText;
ComboBox.SelectedItem will be of a item type. So normally you would need to cast SelectedItem to type of item in your collection. Now, because, in your case it's anonymous type, it's more difficult I think easiest way to get NameOfCompany is to use dynamic
dynamic selectedItem = ComboFirma.SelectedItem;
var name = selectedItem.NameOfCompany;
or you can use SelectedValue/SelectedValuePath
<ComboBox Name="ComboFirma" ... SelectedValuePath="NameOfCompany">
and in code
var name = (string)ComboFirma.SelectedValue;
Try like this
TextBlock tb1 = (TextBlock)ComboFirma.SelectedItem;
lblCompanyNameShow.Content = str.SelectedText;
I have a listboxitem with a data template that have something like this:
<TextBlock Text="{Binding Name}"/>
<TextBlock Text="{Binding Age}"/>
and i use this to add values to the bindings.
ListBox1.Items.Add(New User() With {.Name= "John Crooks", .Age = 42})
is it possible to retrieve these data programmatically, for example. i'm trying to get the age of the selected item programmatically. how can i do this?
You could cast the value of the SelectedItem property to your data item type and then access its properties.
In C#:
if (ListBox1.SelectedItem != null)
{
var myItem = (MyItem)ListBox1.SelectedItem;
var name = myItem.Name;
}
That should be something like this in VB:
Dim myItem As MyItem = CType(ListBox1.SelectedItem, MyItem)
Dim name As String = myItem.Name
You need declare in XAML:
xmlns:localData="YourAssembly.dll"
d:DataContext="{d:DesignInstance Type=localData:YourClass}"
I'm using WPF and the timer doesn't allow to use int for interval. Instead, it asks for TimeSpan
timer1.Interval = TimeSpan.FromMilliseconds(Convert.ToDouble(comboBox1.SelectedItem));
So I changed my code to this but at runtime it gives me an InvalidCastException, saying that the object cannot be converted from System.Windows.Controls.ComboboxItem to System.IConvertible.
How can I solve this?
You should use this
Convert.ToDouble(comboBox1.SelectedText)
The comboBox1.SelectedItem corresponds to the selected item of the ComboBox control and not with the text of it, which is that you want.
Specifically, the SelectedText property of a CombBox control
Gets or sets the text that is selected in the editable portion of a ComboBox.
as it is stated here.
Update
Please use this one:
((ComboBoxItem)comboBox1.SelectedItem).Content.ToString();
Or in two steps:
ComboBoxItem item = (ComboBoxItem)comboBox1.SelectedItem;
timer1.Interval = TimeSpan.FromMilliseconds(Convert.ToDouble(item.Content.ToString()));
For more information about the ComboBoxItem class, please have a look here.
It appears that you are adding ComboBoxItems directly to your ComboBox.
A cleaner and safer approach than parsing strings would be to continue binding to SelectedItem, but to also bind the ItemsSource to a collection of integers.
Then use the ItemTemplate property of the ComboBox to define how to render the integers if you are not satisfied with the default ToString() rendering.
<ComboBox ItemsSource="{Binding Intervals}" SelectedItem="{SelectedInterval}">
<ComboBox.ItemTemplate>
<DataTemplate TargetType="{x:Type Int64}">
<TextBlock Text="{Binding}" Background="Red"/>
</DataTemplate>
</ComboBox.ItemTemplate>
<ComboBox>
With properties looking something like this:
public int SelectedInterval {get;set;}
public List<int> Intervals {
get {
var lst = new List<int>();
for(var i = 1000; i <= 10000; i += 500)
{
lst.Add(i);
}
return lst;
}
}
Now you have strongly type properties that you can manipulate without parsing.