WPF: Treeview Item Root uses different template then child nodes - wpf

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>

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?

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 - Binding to a collection with different depths, and styling differently

Apologies for the long post -- Read a few threads about this, but still find it hard to implement. Basically, I have a collection of objects, defined as:
public class LibData
{
public string Name { get; set; }
ObservableCollection<LibObject> _list;
public ObservableCollection<LibObject> List { get { return _list; } }
public LibData(string name, LibDataType type)
{
this.Name = name;
_list = new ObservableCollection<LibObject>();
}
}
and the object:
public class LibObject
{
public string Name { get; set; }
public LibObject(string name)
{
this.Name = name;
}
}
My main problem is in the XAML, and styling this TreeView. I need to have a specific style for a "root" item, and a specific style for a "leaf". Thing is, that one item in the bound list is "Root->Leaf", and another is "Root->Child->Leaf".
I tried this:
<TreeView x:Name="myTree" ItemsSource="{x:Static local:myDataList}">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Path=List}" >
<Grid>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path=Name}" />
<CheckBox IsChecked="True" Content="HeaderCheckbox"/>
</StackPanel>
</Grid>
<HierarchicalDataTemplate.ItemTemplate >
<DataTemplate>
<Grid>
<StackPanel Orientation="Horizontal">
<CheckBox IsChecked="True" Content="LeafCheckbox" />
<TextBlock Text="{Binding Path=Name}"/>
</StackPanel>
</Grid>
</DataTemplate>
</HierarchicalDataTemplate.ItemTemplate>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
This obviously works fine for the "Root->Leaf" item, but not for the "Root-Child-Leaf".
The XAML implementation seems to be more of a "hard coded" solution, where I know that the item layout is always "Root->Leaf" - how do I make this dynamic?
Again, I have seen solutions to different levels (including using converters), but the problem i'm having is that I need specific styles to root and leaf and nothing for levels in between.
I'm wondering if I'm looking at this completely wrong ...
Easy way to do this. Pull the DataTemplates out of the TreeView and put them in the resources section. Specify the DataType property for each DataTemplate, but do not include a key. The ItemTemplateSelector (a property of type DataTemplateSelector) on the TreeView will do the magic of using whichever DataTemplate suits the correct item type.
Create a HierarchicalDataTemplate for types Root and Child, and a DataTemplate for type Leaf.
Something like this:
<Window.Resources>
<ResourceDictionary>
<DataTemplate DataType="{x:Type local:Leaf}">
<Grid>
<StackPanel Orientation="Horizontal">
<CheckBox IsChecked="True" Content="LeafCheckbox" />
<TextBlock Text="{Binding Path=SomeValue}"/>
</StackPanel>
</Grid>
</DataTemplate>
<HierarchicalDataTemplate DataType="{x:Type local:Child}"
ItemsSource="{Binding Children}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="Child " />
<TextBlock Text="{Binding Path=SomeValue}" />
</StackPanel>
</HierarchicalDataTemplate>
<HierarchicalDataTemplate DataType="{x:Type local:Root}"
ItemsSource="{Binding Children}">
<Grid>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Root " />
<TextBlock Text="{Binding Path=SomeValue}" />
</StackPanel>
</Grid>
</HierarchicalDataTemplate>
</ResourceDictionary>
</Window.Resources>
<Grid>
<TreeView x:Name="myTree" ItemsSource="{Binding}" />
</Grid>

How can I set my data binding in a WPF ItemsControl child to use a property on the parent data context?

I have a WPF ListView with a collection of RadioButtons. I want to set the GroupName of the child controls to be bound to a property on the parent data context. At the moment I am doing this by duplicating the property in each of the children's data context but that can't be right.
My XAML:
<ListView ItemsSource="{Binding OptionItems}" >
<ListView.ItemTemplate>
<DataTemplate DataType="{x:Type Logging:FilterOptionsRadioListViewModel}">
<RadioButton GroupName="{Binding GroupName}" Content="{Binding Option.Value}" Tag="{Binding Option.Key}" IsChecked="{Binding IsChecked}" Command="Logging:FilterOptionsRadioListViewModel.CheckedChangedCommand" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
GroupName is a property on the parent View Model. I currently pass this onto the child View Model (where it is also a property) in the child constructor:
var item = new FilterOptionsRadioListItemViewModel(option, this.GroupName);
What is the correct way of doing this?
<ListView ItemsSource="{Binding OptionItems}" >
<ListView.ItemTemplate>
<DataTemplate DataType="{x:Type Logging:FilterOptionsRadioListViewModel}">
<RadioButton GroupName="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListView}}, Path=DataContext.GroupName}" Content="{Binding Option.Value}" Tag="{Binding Option.Key}" IsChecked="{Binding IsChecked}" Command="Logging:FilterOptionsRadioListViewModel.CheckedChangedCommand" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
You certainly can do that, but if you don't want to have to copy the GroupName to every child Option instance, you could instead do something like the following
// I'm imagining your viewmodels look something like this
public class ParentViewModel
{
private ObservableCollection<Option> m_OptionItems;
public ObservableCollection<Option> OptionItems
{
get { return m_OptionItems; }
set { m_OptionItems = value; }
}
private string m_ParentGroupName;
public string ParentGroupName
{
get { return m_ParentGroupName; }
set
{
m_ParentGroupName = value;
}
}
}
public class Option
{
private string m_Value;
public string Value
{
get { return m_Value; }
set
{
m_Value = value;
}
}
}
Then you can use a relative binding so you can look up the control tree to find the right datacontext, so you don't have to copy the ParentGroupName to each child Option instance.
If you name your window, you can traverse the root DataContext.
<Window x:Class="MyNamespace.MainWindow"
Name="Window"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="500" Width="725">
<ListView ItemsSource="{Binding OptionItems}" >
<ListView.ItemTemplate>
<DataTemplate DataType="{x:Type Logging:FilterOptionsRadioListViewModel}">
<RadioButton GroupName="{Binding ElementName=Window, Path=DataContext.ParentGroupName}" Content="{Binding Option.Value}" Tag="{Binding Option.Key}" IsChecked="{Binding IsChecked}" Command="Logging:FilterOptionsRadioListViewModel.CheckedChangedCommand" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>

TreeView Databinding

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.

Resources