I have the following collection which i would like to bind to a combobox:
public ObservableCollection<Parameter> Values
{ get; set; }
public class Parameter
{
public String Text { get; set; }
public String Value { get; set; }
}
I need to bind the display text of the combobox to the Text property of the Parameter class, I've tried the following ways below but all to no avail:
<ComboBox ItemsSource="{Binding Values}" DisplayMemberPath="Parameter.Text"
<ComboBox ItemsSource="{Binding Values}" DisplayMemberPath="Parameter\Text"
<ComboBox ItemsSource="{Binding Values}" DisplayMemberPath="Text"
When I try the 3 methods above the [assembly name].Parameter is displayed in the combobox for each parameter.
The 2 methods above don't display anything in the combobox
<ComboBox ItemsSource="{Binding Values, Path=Text}"
<ComboBox ItemsSource="{Binding Values, Path=Values.Text}"
And this one takes the text of the first parameter,splits it into characters and displays each character as a seperate item in the combobox:
<ComboBox ItemsSource="{Binding Values, Path=Values/Text}"
UPDATE:
This is the complete XAML code as requested
<ListBox BorderBrush="{x:Null}" Grid.Column="0" Height="100" Grid.ColumnSpan="2" Grid.Row="1" ItemsSource="{Binding ItemParams}" ScrollViewer.VerticalScrollBarVisibility="Auto" Margin="2" HorizontalContentAlignment="Stretch">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock TextTrimming="CharacterEllipsis" Grid.Column="0" Margin="2" Text="{Binding Name}" Background="{Binding ElementName=cmbColors, Path=SelectedItem}"/>
<ComboBox ItemsSource="{Binding Values}" DisplayMemberPath="Text" SelectedIndex="0" HorizontalAlignment="Left" Grid.Column="1" Margin="2" Width="150" Name="cmbColors" >
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Grid.Column="1" Margin="2, 1" Text="{Binding}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Params class:
public class Params
{
public Params(String name, ObservableCollection<Parameter> values)
{
Name = name;
Values = values;
}
public String Name
{ get; set; }
public ObservableCollection<Parameter> Values
{ get; set; }
}
The correct formulation is one of those you already mention:
<ComboBox ItemsSource="{Binding Values}" DisplayMemberPath="Text"
Please check again, and if it does not work post the XAML that you have verbatim.
You can do directly :
<ComboBox ItemsSource="{Binding Values}" DisplayMemberPath="Text" />
For WPF every element of the ComboBox (ComboBoxItem) is a of type T, thus it will look for public properties on the T, this why just putting Text will work.
Had to simply remove the combobox item template or set Text="{Binding Text}"
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Grid.Column="1" Margin="2, 1" Text="{Binding}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
Related
I have following XAML:
<ItemsControl x:Name="TextComboPairItemsControl" Grid.Row="1" Grid.ColumnSpan="2"
ItemsSource="{Binding Path=AllHeaders.Fields}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<TextBlock x:Name="TextBlock1" Text="{Binding}"
Grid.Column="0" Margin ="2"/>
<ComboBox x:Name="ComboBox1" ItemsSource="{Binding ElementName=MainGrid, Path=DataContext.Tags}"
SelectedItem="{Binding ElementName=MainGrid, Path=DataContext.TextComboPairList.Combo}"
Grid.Column="1" Margin ="2" SelectedIndex="0" IsEditable="True"/>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Now, in my code I want to be able to read what the user has chosen in each ComboBox. For that I created a class:
public class TextComboPair
{
public string TextContent { get; set; }
public string ComboContent { get; set; }
}
Every pair of TextBlock and ComboBox would have its own object of the above class.
I also created a list to store all those pairs of data:
public List<TextComboPair> TextComboPairList
{
get;
set;
}
It is defined in my DataContext.
So, if, for example, there was displayed a list of three TextBlock-ComboBox pairs on the screen and user would choose what he needs in each ComboBox, I'd like to have the above List populated with that data.
As you can see in XAML I bound Selected Item to this List, but I must have done it wrong.
Hwo can I fix this?
Try this :
<ComboBox x:Name="ComboBox1" ItemsSource="{Binding Path=DataContext.Tags, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl }}}"
SelectedItem="{Binding RelativeSource={RelativeSource AncestorType={x:Type ItemsControl }}, Path=DataContext.TextComboPairList.Combo}"
Grid.Column="1" Margin ="2" SelectedIndex="0" IsEditable="True"/>
In my application I have a window which contain a ListBox, and controls that should show different properties of its currently selected item. Those controls are:
TextBox that should show 'Name' property.
TextBox that should show 'DataFile` property.
DataGrid that should show 'TItems property, which is an ObservableCollection.
I tried to bind SelectedItem to an object, and then bind different properties of that object to the controls mentioned above, with no success.
The window:
My View:
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:ReportMaker"
xmlns:ViewModel="clr-namespace:ReportMaker.ViewModel" x:Class="ReportMaker.MainWindow"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<ViewModel:MainViewModel/>
</Window.DataContext>
<Grid>
<Button x:Name="button" Content="Create" HorizontalAlignment="Right" Margin="0,0,10,10" VerticalAlignment="Bottom" Width="75"/>
<ComboBox x:Name="comboBox" HorizontalAlignment="Left" Margin="10,0,0,10" VerticalAlignment="Bottom" Width="120"/>
<ListBox x:Name="listBox" HorizontalAlignment="Left" Margin="10,10,0,36.667" Width="119" ItemsSource="{Binding ReportItems}" >
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<StackPanel HorizontalAlignment="Left" Height="274" Margin="134,10,0,0" VerticalAlignment="Top" Width="375" DataContext="{Binding SelectedReportItem}">
<StackPanel.Resources>
<Style x:Key="ControlBaseStyle" TargetType="{x:Type Control}">
<Setter Property="Margin" Value="0, 10, 0, 0" />
</Style>
</StackPanel.Resources>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Name:"/>
<TextBox Width="150" Text="{Binding Name}"/>
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Data File:"/>
<TextBox Width="150" Text="{Binding ID}"/>
</StackPanel>
<DataGrid Height="190" VerticalAlignment="Bottom" ItemsSource="{Binding TItems}"/>
</StackPanel>
<Button x:Name="button_Copy" Content="Save" HorizontalAlignment="Right" Margin="0,0,92,10" VerticalAlignment="Bottom" Width="75"/>
</Grid>
</Window>
My ViewModel:
public class MainViewModel
{
public ObservableCollection<ReportItem> ReportItems { get; set; }
public object SelectedReportItem { get; set; }
public MainViewModel()
{
ReportItems = new ObservableCollection<ReportItem>();
ReportItems.Add(Example);
}
public ReportItem Example = new TextReportItem() { Name = "John", DataFile = "try.txt"};
}
ReportItem:
public class ReportItem
{
public int Id { get; set; }
public string Name { get; set; }
public string DataFile { get; set; }
}
TextReportItem:
public class TextReportItem : ReportItem
{
public ObservableCollection<TextParcel> TItems { get; set; }
}
public class TextParcel
{
char Delimiter { get; set; }
string LineExp { get; set; }
string Result { get; set; }
string IgnoreLine { get; set; }
int DesiredResultIndexInLine { get; set; }
}
EDIT: as I use MVVM, I prefer to use only XAML in the View, with no code behind.
EDIT 2:
Thanks to S.Akbari I succeeded to view the desired properties in the TextBox controls, with the following code:
<StackPanel Orientation="Horizontal">
<TextBlock Text="Name:"/>
<TextBox Width="150" Text="{Binding ElementName=listBox, Path=SelectedItem.Name}"/>
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Data File:"/>
<TextBox Width="150" Text="{Binding ElementName=listBox, Path=SelectedItem.DataFile}"/>
</StackPanel>
But when the same logic is applied to my DataGrid, it fails for some reason:
<DataGrid Height="190" VerticalAlignment="Bottom" ItemsSource="{Binding ElementName=listBox, Path=SelectedItem.TItmes}" />
I also tried:
<DataGrid Height="190" VerticalAlignment="Bottom" DataContext="{Binding ElementName=listBox, Path=SelectedItem}" ItemsSource="{Binding TItems}"/>
And also:
<DataGrid Height="190" VerticalAlignment="Bottom" DataContext="{Binding ElementName=listBox, Path=SelectedItem}">
<DataTemplate>
<TextBlock Text="{Binding TItems}" />
</DataTemplate>
</DataGrid>
if you use MVVM your view model should raise property changed events
You should implement INotifyPropertyChanged
and change the selected item to be a full property
see :How to: Implement Property Change Notification
I have a trouble with displaying properties of instance of external class. There is ListView markup:
<ListView
x:Name="transportListView"
SelectionMode="None"
ItemsSource="{Binding MyModel}">
<ListView.ItemTemplate>
<DataTemplate>
<Border Padding="15" HorizontalAlignment="Center" Margin="0,0,0,10" Background="Gray">
<StackPanel Margin="0,0,0,0">
<TextBlock
Text="{Binding ItemName}"
Margin="0,0,0,0"/>
<TextBlock
Text="{Binding ItemCount}"
Margin="0,0,0,0"/>
</StackPanel>
</Border>
</DataTemplate>
</ListView.ItemTemplate>
MyModel is the page property:
...
public ObservableCollection<ExternalClass> MyModel { get; set; }
...
ExternalClass is the class in some referenced library:
namespace Library.Entities
{
public class ExternalClass
{
public string ItemName { get; set; }
public int ItemCount { get; set; }
}
}
So when I run my application I see list items because I set grey color, but ItemName and ItemCount is not displaying, why? I adding items to collection correctly and binding works for internal classes perfectly.
Change your ListView's ItemsSource to ItemsSource="{Binding}". Like this:
<ListView x:Name="transportListView" ItemsSource="{Binding}">
....
Also in the code behind add this.DataContext = MyModel; below the InitializeComponent();:
public Window1()
{
InitializeComponent();
this.DataContext = MyModel;
}
To Use ListView you also need to Define View (GridView) for it:
<ListView ItemsSource="{Binding MyModel}">
<ListView.View>
<GridView>
<GridViewColumn Width="140" Header="Name" DisplayMemberBinding="{Binding ItemName}"/>
<GridViewColumn Width="140" Header="Count" DisplayMemberBinding="{Binding ItemCount}" />
</GridView>
</ListView.View>
</ListView>
If you want to define template for each row then you can use a ListBox instead of ListView:
<ListBox ItemsSource="{Binding MyModel}">
<ListBox.ItemTemplate>
<DataTemplate>
<Border Padding="15" HorizontalAlignment="Center" Margin="0,0,0,10" Background="Gray">
<StackPanel Margin="0,0,0,0">
<TextBlock Text="{Binding ItemName}" Margin="0,0,0,0"/>
<TextBlock Text="{Binding ItemCount}" Margin="0,0,0,0"/>
</StackPanel>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
I have a WPF application. It contains OrderBlock object which contains other objects, plesase see a brief view of the class.
public class OrderBlocks
{
private List<Order> _orders;
[XmlElement("tF_Transactions")]
public List<Order> Orders { get { return _orders; } set { _orders = value; OnPropertyChanged("Orders"); } }
}
public class Order : INotifyPropertyChanged
{
[XmlIgnore]
public List<Duplications> DuplicateHolder { get; set; }
}
public class Duplications
{
public string ID { get; set; }
public string Name { get; set; }
public Duplications(string newID, string newName)
{
ID = newID;
Name = newName;
}
}
I have a datagrid that is bound to my object Orders of type List Orders. My datagrid has a row detail so that when a user clicks on a row further details are displayed. I have added a listbox to this row detail. I want this row detail to show a listbox which displays my object DuplicateHolder of type List Duplications.
At the moment the listbox is empty. Please see my attempted XAML code below. Any help would be great as always.
<ListBox Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="3" Name="lbIdentifier" SelectionMode="Single" DataContext="{Binding OrderBlock}" HorizontalContentAlignment="Stretch">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid Margin="0,2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="{Binding Path=DuplicateHolder.ID}" FontSize="10" HorizontalAlignment="Left" Margin="5,0,0,0"/>
<TextBlock Grid.Column="1" Text="{Binding Path=DuplicateHolder.Name}" FontSize="10" HorizontalAlignment="Left" Margin="5,0,0,0"/>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Try this
<Listbox ItemSource = {Binding DuplicateHolder}/>
and
<TextBlock Grid.Column="0" Text="{Binding Path=ID}".../>
t seems like you did not set the bindings correctly because the listbox Context should be a list of Duplications and the ItemTemplate should be for one Duplication instance from the list of duplicates. So if the global datacontext is an instance of OrderBlocks the listbox will be bound to the DuplicateHolder of an Order:
<ListBox Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="3" Name="lbIdentifier" SelectionMode="Single" DataContext="{Binding Path=DuplicateHolder}" HorizontalContentAlignment="Stretch">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid Margin="0,2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="{Binding Path=ID}" FontSize="10" HorizontalAlignment="Left" Margin="5,0,0,0"/>
<TextBlock Grid.Column="1" Text="{Binding Path=Name}" FontSize="10" HorizontalAlignment="Left" Margin="5,0,0,0"/>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
So I have a ComboBox with data in it and it works how they want:
<ComboBox Grid.Column="1" x:Name="MyComboBox" Margin="2, 0, 2, 0"
ItemsSource="{Binding Path=MySamples}" DisplayMemberPath="SampleName" SelectedValue="{Binding Path=MySample}"
SelectionChanged="OnComboBoxChanged" FontSize="11" FontFamily="Arial"/>
However, now they want the ItemsSource to be indexed. So it should be something like:
some #: SampleName
Is there an easy way to make this change just for the ComboBox drop down without changing the architecture? I cannot change the List itself since in other areas of the map, it's just the SampleName without the index. Thanks.
If your ItemsSource is a complex type:
public class MyClass
{
public int Index { get; set; }
public string Name { get; set; }
}
Then use the DisplayMemberPath property of the ComboBox to control what gets displayed. In this case you'd add:
DisplayMemberPath="SampleName"
to the ComboBox definition.
If instead you want to display both the index and name then you'll need to define an ItemTemplate for the ComboBox:
<ComboBox ....>
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Index}" />
<TextBlock Text=" : " />
<TextBlock Text="{Binding Name}" />
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>