Treeview with checkbox bind by different lists
I have a class like this :
public class Project
{
List<Object> list1;
List<Object> list2;
}
I want to show this in a treeview control like as follows :
Checkbox + "Listing1"
--> Checkbox + Object 1 of list1
--> Checkbox + Object 2 of list1
Checkbox + "Listing2"
--> Checkbox + Object 1 of list2
-->Checkbox + Object 2 of list2
My biggest problem is making the difference between the 2 lists + some extra : if list2 does not contain any objects, the "Listing2开发者_StackOverflow" header may not be shown.
Does anybody have any good idea how I can do this ?
You can create one class TreeViewItemWithCheckbox by extending TreeViewItem class like below :
public class TreeViewItemWithCheckbox : TreeViewItem
{
#region Variable Declaration
CheckBox chkBox = new CheckBox();
StackPanel stpContent = new StackPanel();
#endregion
#region Properties
public string HeaderText
{
get { return chkBox.Content.ToString(); }
set { chkBox.Content = value; }
}
public bool IsChecked
{
get { return chkBox.IsChecked.Value; }
set { chkBox.IsChecked = value; }
}
#endregion
#region Constructor
public TreeViewItemWithCheckbox()
{
stpContent.Orientation = Orientation.Horizontal;
chkBox = new CheckBox();
chkBox.VerticalAlignment = VerticalAlignment.Center;
chkBox.Click += new RoutedEventHandler(SetCheckboxes);
chkBox.Margin = new Thickness(0, 0, 0, 0);
stpContent.Children.Add(chkBox);
Header = stpContent;
}
#endregion
#region Event Handlers
private void SetCheckboxes(object sender, RoutedEventArgs e)
{
TreeViewItemWithCheckbox selectedItem = ((TreeViewItemWithCheckbox)((StackPanel)((CheckBox)sender).Parent).Parent);
if (selectedItem != null)
{
/* Set checkboxes for all child items */
if (selectedItem.Items.Count > 0)
{
SetChildItemCheckboxes(selectedItem, selectedItem.IsChecked);
}
/* Check if all childs checked then check/uncheck parent accoringly */
if (selectedItem.Parent.GetType() == typeof(TreeViewItemWithCheckbox))
{
TreeViewItemWithCheckbox parentItem = (TreeViewItemWithCheckbox)selectedItem.Parent;
bool bIsAllChecked = true;
foreach (TreeViewItemWithCheckbox item in parentItem.Items)
{
if (!item.IsChecked)
{
bIsAllChecked = false;
break;
}
}
parentItem.IsChecked = bIsAllChecked;
}
}
}
private void SetChildItemCheckboxes(TreeViewItemWithCheckbox item, bool IsChecked)
{
if (item.Items.Count > 0)
{
foreach (TreeViewItemWithCheckbox childItem in item.Items)
{
SetChildItemCheckboxes(childItem, IsChecked);
item.IsChecked = IsChecked;
}
}
else
item.IsChecked = IsChecked;
}
#endregion
}
Then you need to add treeview nodes from 2 list like below :
trvTest.Items.Clear();
//Add default root element
TreeViewItemWithCheckbox rootNode = new TreeViewItemWithCheckbox();
rootNode.HeaderText = "Root";
rootNode.IsExpanded = true;
trvTest.Items.Add(rootNode);
if (_project.list1.Count > 0)
{
TreeViewItemWithCheckbox nodeHead1 = new TreeViewItemWithCheckbox();
nodeHead1.HeaderText = "Listing 1";
rootNode.Items.Add(nodeHead1);
TreeViewItemWithCheckbox node1;
for (int i = 0; i < _project.list1.Count; i++)
{
node1 = new TreeViewItemWithCheckbox();
node1.HeaderText = _project.list1[i].Name;
nodeHead1.Items.Add(node1);
}
}
if (_project.list2.Count > 0)
{
TreeViewItemWithCheckbox nodeHead2 = new TreeViewItemWithCheckbox();
nodeHead2.HeaderText = "Listing 2";
rootNode.Items.Add(nodeHead2);
TreeViewItemWithCheckbox node2 = new TreeViewItemWithCheckbox();
for (int i = 0; i < _project.list2.Count; i++)
{
node2 = new TreeViewItemWithCheckbox();
node2.HeaderText = _project.list2[i].Name;
nodeHead2.Items.Add(node2);
}
}
This can be solved without TreeView - Just 2 CheckBoxes and 2 ItemsControl with specific ItemTemplate.
I prefer this way of solving this problem:
<StackPanel>
<StackPanel.Resources>
<DataTemplate x:Key="MyTemplate">
<StackPanel Orientation="Horizontal">
<CheckBox Content="{Binding SomeProperty}" IsChecked="{Binding SomeBooleanProperty}" />
</StackPanel>
</DataTemplate>
</StackPanel.Resources>
<CheckBox Content="List number 1" />
<ItemsControl ItemsSource="{Binding list1}" ItemTemplate="{StaticResource MyTemplate}" />
<CheckBox Content="List number 2" />
<ItemsControl ItemsSource="{Binding list2}" ItemTemplate="{StaticResource MyTemplate}" />
</StackPanel>
As for your extra: you can bind Visibility to the property in your Project
class, which will be looks like:
public class Project
{
public List<Object> list1;
public List<Object> list2;
public Visibility Visuality
{
get
{
return this.list2.Any() ? Visibility.Visible : Visibility.Colapsed;
}
}
}
and than in the code:
<ItemsControl Visibility="{Binding Visuality}" ... />
<CheckBox Visibility="{Binding Visuality}" ... />
...if I understand you right...
If your first "Listing" items are static, you can do something like this
<TreeView x:Name="tv">
<TreeViewItem Header="Listing 1" ItemsSource="{Binding list1}"/>
<TreeViewItem Header="Listing 2" ItemsSource="{Binding list2}"/>
</TreeView>
To hide elements without children you need a bit of code.
var view = CollectionViewSource.GetDefaultView(_project.list1);
view.Filter = myFilter;
view.Refresh();
tv.DataContext = _project;
For both lists of course.
精彩评论