How to bind two ObservableCollection(s) to one ListBox? - wpf

Does anybody know how to binding two ObservableCollections in one ListBox?
these two ObservableCollections both have a Property string "name" to display in the ListBox,
int the ListBox top area, will display the ObservableCollection1 items and in the ListBox bottom area I want display the ObservableCollection2 items, how to do that?
<ListBox x:Name="m_CtrlMediaList" Grid.Column="2" AllowDrop="True" SelectionMode="Extended">
<ListBox.ItemsSource>
<CompositeCollection>
<CollectionContainer Collection="{Binding directorys}"/>
<CollectionContainer Collection="{Binding files}"/>
</CompositeCollection>
</ListBox.ItemsSource>
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical">
<TextBlock Text="{Binding name, Mode=OneWay}" FontWeight="Bold" FontSize="14"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
the data is like:
class ElementFile
{
...
string name (get;set;}
...
}
class ElementDirectory
{
...
string name (get;set;}
...
public ObservableCollection<ElementDirectory> directorys { get; set; }
public ObservableCollection<ElementFile> files { get; set; }
...
}
Why can not display the "name"?

The composite collection is what you are looking for. Example.

Related

wpf combobox default value to textBlock

I need to add a default value 'select' in the combobox.I cant add this value to the database.This location value is dynamic.It appears based upon the userrole. I tried different ways nothing worked.Please help.
<ComboBox Width="140" ItemsSource="{Binding SecurityContexts, Mode=OneWay}"
SelectedItem="{Binding ActiveSecurityContext, Mode=TwoWay}"
ToolTip="Working Location">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Location}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
The code behind is
SecurityContexts = new ObservableCollection(_currentUser.ApplicationSecurityContexts);
public interface IApplicationSecurityContext
{
IRole Role { get; }
string Location { get; }
IEnumerable<string> Budgets { get; }
}
public IApplicationSecurityContext ActiveSecurityContext
{
get { return this._currentUser.ActiveSecurityContext; }
set
{
if (this._currentUser.ActiveSecurityContext != value)
{
this._currentUser.ChangeActiveSecurityContext(value);
RaisePropertyChanged("CurrentUser");
LoadData();
}
}
}
You can achieve your goal using CompositeCollection
you can do this. Define resource in your grid/usercontrol/combobox:
<Grid.Resources>
<CollectionViewSource x:Key="cvs" Source="{Binding Binding SecurityContexts, Mode=OneWay}" />
<DataTemplate DataType="{x:Type c:SecurityContexts}">
<TextBlock Text="{Binding Location}"/>
</DataTemplate>
</Grid.Resources>
then your combobox itemsource will be:
<ComboBox.ItemsSource>
<CompositeCollection>
<ComboBoxItem>
<TextBlock Text="select"/>
</ComboBoxItem>
<CollectionContainer Collection="{Binding Source= {StaticResource cvs}}"/>
</CompositeCollection>
</ComboBox.ItemsSource>
It should work. You need to define your datatemplate for your collection in the resource too, to define how your item will be displayed
Note that c in c:SecurityContexts is the path where you defined your custom object

How can i add different images to combobox itemssource array

I would like to add different images next to each item in a combobox itemssource. Here's what i have at the moment.
<ComboBox x:Name="cmb" HorizontalAlignment="Left" Width="135" Height="22"
SelectedItem="{Binding myViewMode}" Margin="5,0,0,0">
<ComboBox.ItemsSource>
<x:Array Type="sys:String" xmlns:sys="clr-namespace:System;assembly=mscorlib">
<sys:String>Oranges</sys:String>
<sys:String>Mangoes</sys:String>
</x:Array>
</ComboBox.ItemsSource>
</ComboBox>
How should add the two diffent images using an itemtemplate. Thanks
Edit One
This is what i have tried with itemtemplate
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Image Source="{Binding OrangesImage}" Height="100"/>
<Image Source="{Binding MangoesImage}" />
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
It's here that am really stuck.
At the moment your item template contains only two images, so you will show two images and no text for each item!
I would suggest you change your ItemsSource to code behind so you can have text and image properties.
First make a simple Fruit class:
public class Fruit
{
public string FruitName { get; set; }
public string FruitImage { get; set; }
}
Then create a list of these fruits and set the ItemsSource of your combo box to this list:
var fruits = new List<Fruit>();
fruits.Add(new Fruit() { FruitName = "Mangos", FruitImage = #"C:\mangoimage.jpg" });
fruits.Add(new Fruit() { FruitName = "Oranges", FruitImage = #"C:\mangoimage.jpg" });
cmb.ItemsSource = fruits;
Then simplify your XAML thus:
<ComboBox x:Name="cmb" HorizontalAlignment="Left" Width="135" Height="22" SelectedItem="{Binding myViewMode}" Margin="5,0,0,0">
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding FruitName}"/>
<Image Source="{Binding FruitImage}" Height="100"/>
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
In your ItemSource your image should consists as Uri path with BitMapImage Class then only Images are accepted in ItemTemplate in ComboBox
Xaml Code
<ComboBox x:Name="cmb" HorizontalAlignment="Left" Width="135" Height="22"
SelectedItem="{Binding myViewMode}" Margin="5,0,0,0">
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Image Width="25" Height="25" Source="{Binding FruitName}"/>
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
Your Model Class
public class Fruit
{
public string FruitName { get; set; }
}
Your ItemSource should Consists as:
fruitCollection.Add(new Fruit() {FruitName= new BitmapImage(new Uri("C:\mangoimage.jpg", UriKind.Relative))});

ListBox Grouping issue

I am trying to Group my collection which is based on my following model:
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public Role PersonRole { get; set; }
}
public class Role
{
public int Id { get; set; }
public string RoleName { get; set; }
}
My PersonCollection,
public ObservableCollection<Person> PersonList;
The collection is populated with three Person object, two with identical roles.
I want to group all my persons as per their RoleName. I have the following XAML:
<Grid.Resources>
<CollectionViewSource x:Key="cvs" Source="{Binding PersonList}">
<CollectionViewSource.GroupDescriptions>
<PropertyGroupDescription PropertyName="PersonRole.RoleName"/>
</CollectionViewSource.GroupDescriptions>
</CollectionViewSource>
</Grid.Resources>
<ListBox ItemsSource="{Binding Source={StaticResource cvs}}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding FirstName}"/>
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<TextBlock Text="{Binding PersonRole.RoleName}" FontWeight="Bold" Background="ForestGreen" Margin="0,5,0,0"/>
</DataTemplate>
</GroupStyle.HeaderTemplate>
</GroupStyle>
</ListBox.GroupStyle>
</ListBox>
However the rendered UI is not displaying the grouped RoleName in the list box. Also I would like to show the grouping horizontally where the groups appear horizontally while the grouped items appear vertically. Appreciate any help in advance.
Here's the output I am seeing:
Since you have already provided GroupDescriptons at your CollectionViewSource, groupStyle will pick the property name from there only.
All you need is to bind with Name property of CollectionViewGroup class to access the value of the property on which grouping is applied. In group style, binding is against CollectionViewGroup class and not against your Model class.
So, this is how you will do it:
<TextBlock Text="{Binding Name}" FontWeight="Bold"
Background="ForestGreen" Margin="0,5,0,0"/>
And regarding to align groups horizontally, you can set ItemsPanelTemplate of Group to be VirtualizingStackPanel with Orientation set to Horizontal which makes your groups to be aligned horizontally.
<ListBox.GroupStyle>
<GroupStyle>
<GroupStyle.Panel>
<ItemsPanelTemplate>
<VirtualizingStackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</GroupStyle.Panel>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}" FontWeight="Bold"
Background="ForestGreen" Margin="0,5,0,0"/>
</DataTemplate>
</GroupStyle.HeaderTemplate>
</GroupStyle>
</ListBox.GroupStyle>

How to make custom control with ListBox?

I want to make horizontal ListBox with customized item template, so I make a basic template of it.
However, I couldn't find an example of binding 'things' to that WPF XAML, especially with ListBox filled with customized items.
I simply want to dynamically add/remove items in the ListBox with Image, Label, ComboBox with previously filled with number 1 to 10.
the ADD/REMOVE button will be placed outside WPF control, it means that the buttons will be on the Main Window Form.
Also, there are TextBox and picture selector in the Main Window Form so that I can change the text and image.
Below is code behind XAML :
Public Class listSequence
Public Sub New()
InitializeComponent()
listbox.Items.Add("hi")
listbox.Items.Add("there")
End Sub
End Class
Below is XAML :
<ListBox Name="listbox" VerticalContentAlignment="Stretch" ScrollViewer.VerticalScrollBarVisibility="Disabled" ScrollViewer.HorizontalScrollBarVisibility="Auto" ScrollViewer.CanContentScroll="True" >
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" VerticalAlignment="Stretch" />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<Border Padding="10" Margin="5" BorderThickness="1" BorderBrush="Aqua" CornerRadius="0" Width="120" VerticalAlignment="Stretch">
<StackPanel>
<Image />
<Label Content="{Binding}" />
<TextBlock Text="hi" />
<ComboBox x:Name="cboRepeat" ItemsSource="{Binding}" DisplayMemberPath="RepeatCounter" IsSynchronizedWithCurrentItem="True"/>
</StackPanel>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Let's say we have a basic class named Item:
public class Item : INotifyPropertyChanged
{
public string Text { get; set; } // Implement INotifyPropertyChanged
public string ImagePath { get; set; } // properly on these properties
}
And a collection of these in a view model:
public ObservableCollection<Item> Items { get; set; }
Now to display these items in the UI, we use a ListBox and set the ItemsSource property:
<ListBox ItemsSource="{Binding Items}">
</ListBox>
When it comes to defining the ListBox.ItemTemplate, you need to understand that this DataTemplate will be applied to each item and that it has access to all of the properties defined in the Item class:
<ListBox ItemsSource="{Binding Items}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<Image ImageSource="{Binding ImagePath}" />
<TextBlock Text="{Binding Text}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Therefore, you can access the properties in the collection class as shown above. You can find out the full story by looking at the ItemsControl.ItemTemplate Property page on MSDN.

WPF XCEED DataGrid multiple property in one column

I have a class which has two level of collections. The software is about salaries payment. The idea is a payment action consists of multiple paid employees. And each employees could have multiple salaries cuts. The Object would look like:
Payment -->Payment Object
Date
ID
Employees: -->ObservableCollection of EmpPayment Objects
Emp A -->And EmpPayment Object
Name
TotalCut --> An Integer Readonly Property that sums the Cuts.
Cuts --> Collection of Cut object
Cut1 --> Cut object 1
Cut2 --> Cut object 2
Emp B
Name
TotalCuts
Cuts
Cut1
Cut2
I am using a exceed DataGrid. So far so good except I want to display two values in one column using CellContentTemplate, that is the Cuts and the TotalCut. So the datagrid will look like:
Employee | Cuts
Emp A | [The Total Cut]
Cut 1
Cut 2
Emp B | [The Total Cut]
Cut 1
Cut 2
At the cuts column, i want to use a Xceed DropDownButton to show the total, and user can edit the cuts by editting the dropdowncontent. So far the XAML i made for the Employees ObservableCollection:
<xcdg:DataGridControl x:Name="GridEmployees" ItemsSource="{Binding Employees}" AutoCreateColumns="False">
<xcdg:DataGridControl.Columns>
<xcdg:Column FieldName="Name" Title="Employee"/>
<xcdg:Column FieldName="Cuts" Title="Cuts">
<xcdg:Column.CellContentTemplate>
<DataTemplate>
<xctk:DropDownButton Content="{Binding Path=TOTALCUT}">
<xctk:DropDownButton.DropDownContent>
<ListBox ItemsSource="{Binding}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBox Text="{Binding CutDescription}"/>
<TextBox Text="{Binding Amount}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</xctk:DropDownButton.DropDownContent>
</xctk:DropDownButton>
</DataTemplate>
</xcdg:Column.CellContentTemplate>
</xcdg:Column>
</xcdg:DataGridControl.Columns>
</xcdg:DataGridControl>
Binding to the Cuts ObservableCollection works well, but not the TotalCut. How do I bind the TotalCut [Intentionally written in all caps above] to that same column?
Using two columns is possible, but will not be pretty.
Forget the XCeed DataGridControl and welcome to standard DataGrid. Just use the DataGridTemplateColumn there.
The other alternative is just to use two columns in XCeed DataGridControl which is not preety.
All you have to do - provide your own cell editor and CellTemplate, which will bind to corresponding properties. Here's my working solution:
<xcdg:DataGridControl AutoCreateColumns="False" ItemsSource="{Binding Items}">
<xcdg:DataGridControl.View>
<xcdg:TableflowView ScrollingAnimationDuration="0" ContainerHeight="44"/>
</xcdg:DataGridControl.View>
<xcdg:DataGridControl.Resources>
<DataTemplate x:Key="EditDataTemplate" DataType="wpfApplication1:State">
<StackPanel>
<TextBox Text="{Binding Path=Name}"/>
<TextBox Text="{Binding Path=Post}"/>
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="ReadDataTemplate" DataType="wpfApplication1:State">
<StackPanel>
<TextBlock HorizontalAlignment="Right" Text="{Binding Path=Name}"/>
<TextBlock HorizontalAlignment="Right" Text="{Binding Path=Post}"/>
</StackPanel>
</DataTemplate>
</xcdg:DataGridControl.Resources>
<xcdg:DataGridControl.Columns>
<xcdg:Column FieldName="Zip" Title="Zip"/>
<xcdg:Column FieldName="Stat" Title="Zip2"
CellContentTemplate="{StaticResource ReadDataTemplate}">
<xcdg:Column.CellEditor>
<xcdg:CellEditor EditTemplate="{StaticResource EditDataTemplate}"/>
</xcdg:Column.CellEditor>
</xcdg:Column>
</xcdg:DataGridControl.Columns>
</xcdg:DataGridControl>
and codebehind of "data object":
public class User
{
private string _zip;
public string Zip
{
get { return _zip; }
set
{
_zip = value;
Stat = new State();
Stat.Name = "stat: " + value;
}
}
public State Stat { get; set; }
}
public class State
{
public string Name { get; set; }
public string Post { get; set; }
}
Entire solution code

Resources