开发者

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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜