TreeView Databinding - wpf

I want to add items in treeviewi n WPF.I have function as
public void SetTree(string Title,int Boxtype,int BoxNo )
{
sBoxType = "Group";
TreeList items = TreeList.Load(Title, sBoxType, BoxNo);
DataContext = items;
}
XAML Code of TreeView:
<TreeView Margin="16,275,18,312" x:Name="treeView1" ItemsSource="{Binding}" ItemTemplate="{StaticResource TreeItemTemplate}">
</TreeView>
<DataTemplate x:Key="TreeItemTemplate">
<WrapPanel>
<TextBlock Text="{Binding Path=Title}" />
<TextBlock Text="{Binding Path=Box}" />
</WrapPanel>
</DataTemplate>
Actually i wan to TreeView ot display lik
+Group (header)
Controllersgroup 5 (Child items).
As multicolumn child items.But it dislay like
Controllersgroup5

Instead of a regular DataTemplate you must use a HierarchicalDataTemplate and set it's ItemSource Property.
<HierarchicalDataTemplate ItemsSource="{Binding ChildItems}" />
like so.

Related

View does not update UIElement property

I have a MainView with TabControl, which is intended to display child Views, and a ComboBox to display some values
MainView has this XAML:
<TabControl ItemsSource="{Binding ViewModelsCollection, Mode=TwoWay}"
SelectedItem="{Binding ViewModelsSelectedItem, Mode=TwoWay}">
<TabControl.ItemTemplate>
<DataTemplate>
<TextBlock>
<TextBlock Text="{Binding Path=Title}"/>
</TextBlock>
</DataTemplate>
</TabControl.ItemTemplate>
</TabControl>
<ComboBox x:Name="cmbProfiles"
ItemsSource="{Binding Path=ProfileCollection}"
SelectedItem="{Binding Path=ProfileSelectedItem, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
DisplayMemberPath="Key">
</ComboBox>
Also, MainView has DataTemplates for child Views - to be used in the TabControl:
<Window.Resources>
<DataTemplate DataType="{x:Type vm:OrdersViewModel}">
<v:OrdersView/>
</DataTemplate>
<DataTemplate DataType="{x:Type vm:ShippingViewModel}">
<v:ShippingView/>
</DataTemplate>
</Window.Resources>
ChildViews are created in MainViewModel:
ObservableCollection<ViewModelBase> collection = new ObservableCollection<ViewModelBase>();
collection.Add(new OrdersViewModel());
collection.Add(new ShippingViewModel());
this.ViewModelsCollection = collection;
Each ChildView has a button, which IsEnabled property should depend on MainView's cmbProfiles selection:
<Button IsEnabled="{Binding Path=BtnServiceSetupIsEnabled}"
Content="Next ...">
</Button>
Code in MainView to handle that:
IOrdersViewModel ordersViewModel = (IOrdersViewModel)this.ViewModelsCollection.Where(x => x.GetType().Equals(typeof(OrdersViewModel))).FirstOrDefault();
if (profileItem.Key == "Custom")
{
ordersViewModel.BtnServiceSetupIsEnabled = true;
}
else
{
ordersViewModel.BtnServiceSetupIsEnabled = false;
}
The problem occurs when I change selection in cmbProfiles: ChildViewModel.BtnServiceSetupIsEnabled gets updated in code indeed, but the ChildView doesn't reflect that change, button stays disabled.
It does work fine if I don't use DataTemplates and simply add <v:OrdersView/> to my MainView, not dynamically filling the TabControl.
How can I fix that - and to have my TabControl's TabItems created dynamically?

MVVM WPF Combobox: creating a template for comboboxitem

I have a WPF combobox which is populated from code-behind.
Code-behind (xaml.cs):
namespace WpfApplication1
{
private ObservableCollection<TransportType> transportTypes = new ObservableCollection<TransportType>();
transportTypes.Add(new TransportType() {Icon = Properties.Resources.Air, ValueMember = "A100", DisplayMember = "By Air" });
transportTypes.Add(new TransportType() {Icon = Properties.Resources.Maritime, ValueMember = "M200", DisplayMember = "Maritime" });
this.ComboBoxTransportTypes.ItemsSource = transportTypes;
}
TransportType class:
namespace WpfApplication1
{
public class TransportType
{
public Image Icon
{
get;
set;
}
public string DisplayMember
{
get;
set;
}
public string ValueMember
{
get;
set;
}
}
}
View:
<ComboBox x:Name="ComboBoxTransportTypes"
Grid.Column="1"
ItemsSource="{Binding}"
DisplayMemberPath="DisplayMember"
SelectedValuePath="ValueMember"
SelectionChanged="ComboBoxTransportTypes_SelectionChanged">
<ComboBox.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel />
</ItemsPanelTemplate>
</ComboBox.ItemsPanel>
</ComboBox>
Now I am trying to apply a ComboBox ItemTemplate and bound to the "transportTypes" collection. I would like each combobox item to be as below:
<ComboBoxItem>
<StackPanel Orientation="Horizontal">
<Image Source="{Binding bind-icon-here}" />
<TextBlock Foreground="AliceBlue"
VerticalAlignment="Center"
Text="{Binding bind-DisplayMember-here}"/>
</StackPanel>
</ComboBoxItem>
So how can I create the above combobox item template bound to my collection in order to each item to be presented with an icon followed by a string?
I have tried below but it does not work. I also do not know how to bind each item in the collection to the image and textblock within stackpanel, I have done as below but only string is displayed and not icon.
<ComboBox x:Name="ComboBoxTransportTypes"
Grid.Column="1"
ItemsSource="{Binding}"
DisplayMemberPath="DisplayMember" <-- removed from here as I cannot define DisplayMemberPath and item template at the same time.
SelectedValuePath="ValueMember"
SelectionChanged="ComboBoxTransportTypes_SelectionChanged">
<ComboBox.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel />
</ItemsPanelTemplate>
</ComboBox.ItemsPanel>
<ComboBox.ItemTemplate>
<DataTemplate DataType="l:TransportType">
<StackPanel Orientation="Horizontal">
<Image Source="{Binding Icon}" />
<TextBlock Foreground="AliceBlue"
VerticalAlignment="Center"
Text="{Binding DisplayMember}"/>
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
Also, in MVVM is it better to populate combobox from code-behind as I have done here or from view model constructor?
The problem is that you're setting the ItemSource in both the XAML and in the code behind. If you remove ItemSource="{Binding}" from the XAML then it should work.
If you are using MVVM, the collection should be populated in the view model, not in the code behind. There should be very little code in your code behind - only things related to the view should go there (such as displaying a child window).
The problem is that Image.Source takes an ImageSource not an Image. Change ...
<Image Source="{Binding Icon}" />
to...
<Frame Content="{Binding Icon}"/>
and things will start working.
you must use bottom syntax for custom template ComboBox
<TextBlock Text="{Binding Path=DisplayMember}"/>
or
<Image Source="{Binding Path=Icon}" />
in wpf list tags like combobox,listbox,... for custom tamplate like DataTemplate you must use Path

How to copy Items from Datagrid to Listbox

I have a listbox, datagrid and a Button. The data grid is populated with data from MS SQL. I want to be able to copy selected item(s) from the datagrid to listbox using the button. The code behind the button is
private void btnAdd_click(object sender, RoutedEventArgs e)
{
lstSelected.Items.Add(iFacilitiesDataGrid.SelectedItem.ToString());
}
//List Box in xaml
<ListBox Grid.Column="2" Grid.Row="1" Grid.RowSpan="7" Height="258" HorizontalAlignment="Left" Margin="0,4,0,0" Name="lstSelected" VerticalAlignment="Top" Width="236" />
For the datagrid
<DataGrid AutoGenerateColumns="False" EnableRowVirtualization="True" Grid.Column="2" Grid.Row="1" Grid.RowSpan="7" Height="244" HorizontalAlignment="Left" ItemsSource="{Binding Source={StaticResource iLocationICategoriesIFacilitiesViewSource}}" Margin="291,5,0,0" Name="iFacilitiesDataGrid" RowDetailsVisibilityMode="VisibleWhenSelected" VerticalAlignment="Top" Width="247">
<DataGrid.Columns>
<DataGridTemplateColumn x:Name="facilityNameColumn" Header="Facility Name" Width="150">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=FacilityName}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTextColumn x:Name="priceColumn" Binding="{Binding Path=Price}" Header="Price" Width="100" />
</DataGrid.Columns>
</DataGrid>
Whenever I try to add item on the listbox, the item passed to the listbox is "HM.IFacility" Where HM is the project name and IFacility the Table Name .
If you want the instance of the object to enter the listbox, you cannot control the tostring method like you do:
lstSelected.Items.Add(iFacilitiesDataGrid.SelectedItem.ToString());
Instead, cast your selecteditem to the type:
lstSelected.Items.Add((HM.IFacility)iFacilitiesDataGrid.SelectedItem);
If you don't want the object to enter the listbox, but just some properties from that object, then you have to override the tostring in your object. If you don't do that, the tostring will give you the type of the object, like you said --> "HM.IFacility"
to override the tostring, put this in your object class:
public override string ToString()
{
return property1 + " " + property2
}
Where property1 and property2 are properties on your object class (like name, age, or id)
You need to create a datatemplate for listbox as well. as you have created for DataGrid. replace your listbox with below one and try again.
<ListBox Grid.Column="2" Grid.Row="1" Grid.RowSpan="7" Height="258" HorizontalAlignment="Left" Margin="0,4,0,0" Name="lstSelected" VerticalAlignment="Top" Width="236" >
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=FacilityName}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Condition: The data of DataGrid and ListBox must be same Type.

ObservableCollection Images in Listbox to Content Control master detail WPf

I have an observablecollection of Images that get populated via the following code:
<StackPanel Orientation="Horizontal" Grid.Column="0">
<ListBox ItemsSource="{Binding BigImageView}" IsSynchronizedWithCurrentItem="True"
SelectedIndex="0" SelectedItem="{Binding CurrentItem}" />
</StackPanel>
<ContentControl Name="Detail" Content="{Binding BigImageView, Mode=OneWay}"
Margin="9,0,0,0" Grid.Column="2" HorizontalAlignment="Left" VerticalAlignment="Top"/>
However the Content Control is supposed to bind to the BigImageView via an ObservableCollection
BigImage = new ObservableCollection<Image>();
_listView = CollectionViewSource.GetDefaultView(BigImage);
_listView.CurrentChanged += new EventHandler(OnCurrentChanged);
public System.ComponentModel.ICollectionView BigImageView
{
get
{
return _listView;
}
set
{
_listView = value;
OnPropertyChanged("BigImageView");
}
}
I want to return the image to the content control when I move the listbox. I have been racking my brain and trying everyhitn but it does not work. any help would be appreciated.
There is no need to bind the selecteditem, the collectionview should take care of that.
Try this:
<ListBox ItemsSource="{Binding BigImageView}" IsSynchronizedWithCurrentItem="True" />
<ContentControl Name="Detail" Content="{Binding BigImageView, Mode=OneWay}" VerticalAlignment="Top">
<ContentControl.ContentTemplate>
<DataTemplate>
<Image Source="{Binding}"/>
</DataTemplate>
<ContentControl.ContentTemplate>
1
Create a viewmodel with a list and a selected item:
public class BigImageViewModel : INotifyPropertyChanged
{
private string bigImage;
//string for path?
public ObservableCollection<string> BigImageView {get; set; } //Of course, make sure it has a value
public string SelectedBigImage
{
get { return bigImage; }
set { bigImage = values; NotifyPropertyChanged("SelectedBigImage"); }
}
}
Set this object on the DataContext of your control in the constructor:
DataContext = new BigImage(); //Make sure you initialize your list
Set the ListBox ItemsSource to your BigImage list, bind your SelectedItem to BigImageView
and use that in your content control:
<ListBox ItemsSource="{Binding BigImageView}" SelectedItem={Binding SelectedBigImage} />
ContentControl:
<ContentControl Name="Detail" Content="{Binding SelectedBigImage, Mode=OneWay}" VerticalAlignment="Top">
<ContentControl.ContentTemplate>
<DataTemplate>
<Image Source="{Binding}"/> <!-- Nice template for showing your string BigImage -->
</DataTemplate>
<ContentControl.ContentTemplate>
</ContentControl>
2
Or screw that view model:
Set the list directly in the constructor (after the InitializeComponent() ):
myListBox.ItemsSource = ObservableCollection<string>(); //Make sure you initialize your list with whatever your object is..
Give the list a name:
And bind with an ElementName binding to your selected item:
<ContentControl Name="Detail" Content="{Binding ElementName=myListBox, Path=SelectedItem}" VerticalAlignment="Top">
<ContentControl.ContentTemplate>
<DataTemplate>
<Image Source="{Binding}"/> <!-- Nice template for showing your string BigImage -->
</DataTemplate>
<ContentControl.ContentTemplate>
</ContentControl>

WPF: Treeview Item Root uses different template then child nodes

I currently am trying to bind my business object to a treeview as the root. And its collection property as the child. [I want to achieve this via BINDING]
Something like this.
public object MyBusinessObject
{
private int _number;
private bool _isSelected;
private ObservableCollection<AnotherObject> _other = new ObservableCollection<AnotherObject>();
public int Number { get {return _number;} set {_number = value;}}
public bool IsSelected{ get {return _isSelected;} set {_isSelected= value;}}
public ObservableCollection<AnotherObject> Children { get {return _other;}}
}
I want my treeview to be represented like this:
"CheckBox binded to IsSelected" "Text binded to Number"
List of child binded to my "Children"
List of child binded to my "Children"
List of child binded to my "Children"
"CheckBox binded to IsSelected" "Text binded to Number"
List of child binded to my "Children"
List of child binded to my "Children"
List of child binded to my "Children"
I have no idea how to do this in xaml:
<TreeView x:Name="_tv" ItemsSource="{Binding Path=MyBusinessObject}" >
<TreeView.Resources>
<HierarchicalDataTemplate>
<CheckBox Content="{Binding Path=Number} IsChecked="{Binding Path=IsSelected}" />
</HierarchicalDataTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Path=Children}">
<TextBlock Text="{Binding Path=Name}" />
</HierarchicalDataTemplate>
</TreeView.Resources>
</TreeView>
I know the above is not right, but i was wondering if there is a way to do this properly.
Thanks and Regards,
Sure, you can use the HierarchicalDataTemplate.ItemTemplate property to define the data template to be used for the collection of AnotherObject instances.
<TreeView ItemsSource="{Binding SomeCollectionOfObjects}">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Children}">
<!-- This is used for your AnotherObject instances -->
<HierarchicalDataTemplate.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}" />
</DataTemplate>
</HierarchicalDataTemplate.ItemTemplate>
<!-- This is used for your MyBusinessObject instances -->
<CheckBox Content="{Binding Number}" IsChecked="{Binding IsSelected}" />
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>

Resources