none
WPF TreeView и ObservableCollection RRS feed

  • Вопрос

  • Есть поле

    public ObservableCollection<ServerClientVM> ServerClientList { get; private set; }
    

    Которое биндится к TreeView и выглядит это примерно так:

    Нужно добавить 1 пункт который будет использоваться для добавления сервера, что бы стало примерно так:


    Проблема в том что по логике в ServerClientList я его добавить не могу, т.к. это список серверов.
    • Изменено skysniper777 20 октября 2011 г. 11:00
    20 октября 2011 г. 10:16

Ответы

  • можно изменить шаблон TreeView.
    примерно так ...
    <Window x:Class="WpfApplication1.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            Width="400" Height="400"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
        <Grid>
            <Grid.Resources>
                <Style TargetType="TreeView">
                    <Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Auto"/>
                    <Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto"/>
                    <Setter Property="Template">
                        <Setter.Value>
                            <ControlTemplate TargetType="TreeView">
                                <ScrollViewer  Focusable="False">
                                    <StackPanel>
                                        <ItemsPresenter/>
                                        <Label Content="Добавить сервер" />
                                    </StackPanel>
                                </ScrollViewer>
                            </ControlTemplate>
                        </Setter.Value>
                    </Setter>
                </Style>
            </Grid.Resources>
            <TreeView x:Name="tw" ItemsSource="{Binding}" />
        </Grid>
    </Window>
    
    

    • Предложено в качестве ответа Malobukv 22 октября 2011 г. 18:22
    • Помечено в качестве ответа skysniper777 26 октября 2011 г. 10:13
    20 октября 2011 г. 12:14
  • > Спасибо, это почти то что надо, но я кое что забыл указать :( В итоге должно быть вот так: ...
     

    в таком случае можно использовать Converter (который добавит экземпляр типа None) и два шаблона для Item и None:

    <Window x:Class="WpfApplication1.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            Width="800" Height="400"
            xmlns:local="clr-namespace:WpfApplication1"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
        <Grid>
            <Grid.Resources>
                <local:ChildsConverter x:Key="cc"  />
            </Grid.Resources>
            <TreeView ItemsSource="{Binding}" x:Name="tw">
                <TreeView.Resources>
                    <DataTemplate DataType="{x:Type local:None}">
                        <Button Content="Добавить" />
                    </DataTemplate>
                    <HierarchicalDataTemplate DataType="{x:Type local:Item}" ItemsSource="{Binding Childs, Converter={StaticResource cc}}">
                        <TextBlock Text="{Binding Name}" />
                    </HierarchicalDataTemplate>
                </TreeView.Resources>
            </TreeView>
        </Grid>
    </Window>
    
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Windows;
    using System.Windows.Data;
    
    namespace WpfApplication1
    {
        public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
                var rnd = new Random();
                tw.DataContext = Enumerable
                    .Range(0, 10)
                    .Select(i => new Item
                    {
                        Name = "item" + i,
                        Childs = Enumerable
                            .Range(0, rnd.Next(2, 5))
                            .Select(c => new Item { Name = "child" + c })
                    });
            }
        }
    
        public class Item
        {
            public string Name { get; set; }
            public IEnumerable<Item> Childs { get; set; }
        }
    
        public class None {}
    
        public class ChildsConverter : IValueConverter
        {
            public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
            {
                var en = value as IEnumerable<Item>;
                if (en != null)
                {
                    var lst = new List<object>(en);
                    lst.Add(new None());
                    return lst;
                }
                return value;
            }
            public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
            {
                throw new NotImplementedException();
            }
        }
    }
    
    • Предложено в качестве ответа Malobukv 22 октября 2011 г. 18:21
    • Помечено в качестве ответа skysniper777 25 октября 2011 г. 7:38
    • Снята пометка об ответе skysniper777 25 октября 2011 г. 13:22
    • Помечено в качестве ответа skysniper777 26 октября 2011 г. 10:13
    22 октября 2011 г. 18:04
  • другой вариант без None, на основе ItemTemplateSelector:
     

    <Window x:Class="WpfApplication1.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            Width="800" Height="400"
            xmlns:local="clr-namespace:WpfApplication1"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
        <Grid>
            <Grid.Resources>
                <local:ChildsConverter x:Key="cc"  />
                <DataTemplate x:Key="itm" >
                    <TextBlock Text="{Binding Name}" />
                </DataTemplate>
                <DataTemplate x:Key="ctrl">
                    <TextBlock Text="Добавить" />
                </DataTemplate>
                <local:TemplateSelector x:Key="ts" 
                    Item="{StaticResource itm}" Control="{StaticResource ctrl}" />
                <HierarchicalDataTemplate x:Key="ht" 
                    ItemsSource="{Binding Childs, Converter={StaticResource cc}}"
                    ItemTemplateSelector="{StaticResource ts}">
                    <TextBlock Text="{Binding Name}" />
                </HierarchicalDataTemplate>
            </Grid.Resources>
            <TreeView ItemsSource="{Binding}" x:Name="tw" ItemTemplate="{StaticResource ht}" />
        </Grid>
    </Window>
    
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Windows;
    using System.Windows.Data;
    using System.Windows.Controls;
    
    namespace WpfApplication1
    {
        public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
                var rnd = new Random();
                tw.DataContext = Enumerable
                    .Range(0, 10)
                    .Select(i => new Item
                    {
                        Name = "item" + i,
                        Childs = Enumerable
                            .Range(0, rnd.Next(2, 5))
                            .Select(c => new Item { Name = "child" + c })
                    });
            }
        }
    
        public class Item
        {
            public string Name { get; set; }
            public IEnumerable<Item> Childs { get; set; }
        }
    
        public class TemplateSelector : DataTemplateSelector
        {
            public DataTemplate Item { get; set; }
            public DataTemplate Control { get; set; }
            public override DataTemplate SelectTemplate(object item, DependencyObject container)
            {
                return (item is Item) ? Item : Control;
            }
        }
    
        public class ChildsConverter : IValueConverter
        {
            public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
            {
                var en = value as IEnumerable<Item>;
                if (en != null)
                {
                    var lst = new List<object>(en);
                    lst.Add(new object());
                    return lst;
                }
                return value;
            }
            public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
            {
                throw new NotImplementedException();
            }
        }
    }
    


    • Предложено в качестве ответа Malobukv 22 октября 2011 г. 18:21
    • Помечено в качестве ответа skysniper777 25 октября 2011 г. 7:38
    • Снята пометка об ответе skysniper777 25 октября 2011 г. 13:22
    • Помечено в качестве ответа skysniper777 26 октября 2011 г. 10:13
    22 октября 2011 г. 18:09
  • и еще один вариант - перехват TreeViewItem.ExpandedEvent и изменение TreeViewItem.ItemsSource

     

    <Window x:Class="WpfApplication1.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            Width="800" Height="400"
            xmlns:local="clr-namespace:WpfApplication1"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
        <Grid>
            <Grid.Resources>
                <DataTemplate x:Key="itm" >
                    <TextBlock Text="{Binding Name}" />
                </DataTemplate>
                <DataTemplate x:Key="ctrl">
                    <TextBlock Text="Добавить" />
                </DataTemplate>
                <local:TemplateSelector x:Key="ts" 
                    Item="{StaticResource itm}" Control="{StaticResource ctrl}" />
                <HierarchicalDataTemplate x:Key="ht" 
                    ItemsSource="{Binding Childs}"
                    ItemTemplateSelector="{StaticResource ts}">
                    <TextBlock Text="{Binding Name}" />
                </HierarchicalDataTemplate>
            </Grid.Resources>
            <TreeView ItemsSource="{Binding}" x:Name="tw" ItemTemplate="{StaticResource ht}" />
        </Grid>
    </Window>
    
    
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Windows;
    using System.Windows.Data;
    using System.Windows.Controls;
    using System.Windows.Media;
    using System.Windows.Controls.Primitives;
    
    namespace WpfApplication1
    {
        public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
                var rnd = new Random();
                tw.DataContext = Enumerable
                    .Range(0, 10)
                    .Select(i => new Item
                    {
                        Name = "item" + i,
                        Childs = Enumerable
                            .Range(0, rnd.Next(2, 5))
                            .Select(c => new Item { Name = "child" + c })
                    });
    
                tw.AddHandler(TreeViewItem.ExpandedEvent, new RoutedEventHandler(TreeViewItemExpanded));
            }
    
            private void TreeViewItemExpanded(object sender, RoutedEventArgs e)
            {
                var ti = e.OriginalSource as TreeViewItem;
                if ((ti != null) && (ti.ItemContainerGenerator.Status != GeneratorStatus.ContainersGenerated))
                {
                    var lst = new List<object>(ti.ItemsSource.OfType<object>());
                    lst.Add(new object());
                    ti.ItemsSource = lst;
                }
            }
        }
    
        public class Item
        {
            public string Name { get; set; }
            public IEnumerable<Item> Childs { get; set; }
        }
    
        public class TemplateSelector : DataTemplateSelector
        {
            public DataTemplate Item { get; set; }
            public DataTemplate Control { get; set; }
            public override DataTemplate SelectTemplate(object item, DependencyObject container)
            {
                return (item is Item) ? Item : Control;
            }
        }
    }
    

    • Предложено в качестве ответа Malobukv 22 октября 2011 г. 18:21
    • Помечено в качестве ответа skysniper777 25 октября 2011 г. 7:38
    • Снята пометка об ответе skysniper777 25 октября 2011 г. 13:22
    • Помечено в качестве ответа skysniper777 26 октября 2011 г. 10:13
    22 октября 2011 г. 18:15
  • > var en = value as IEnumerable<ServerClientVM>;
    if (en != null) { 
        var lst = new List<object>(en);
        ...
        return lst;


    этот код подменяет ObservableCollection на List; из-за этого перестает работать привязка TreeView;
    можно сделать так:
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        var lst = value as ObservableCollection<ServerClientVM>;
        if (lst != null)
        {
            ServerClientVM sc = new ServerClientVM { DisplayName = "Новый сервер" };
            lst.Add(sc);
            return lst;
        }
        return value;
    }
    
    • Помечено в качестве ответа skysniper777 26 октября 2011 г. 13:23
    26 октября 2011 г. 13:16
  • > жаль что в итоге пришли к тому что изменяется сам ServerClientList [...] по логике в ServerClientList я его добавить не могу, т.к. это список серверов


    пример который не меняет коллекции серверов и устройств.

    <Window x:Class="WpfApplication1.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            Width="300" Height="600"
            xmlns:sys="clr-namespace:System;assembly=mscorlib"
            xmlns:local="clr-namespace:WpfApplication1" 
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
        <Window.Resources>
            <local:WrapperConverter x:Key="w"/>
        </Window.Resources>
        <TreeView x:Name="tv" ItemsSource="{Binding ServerClientList, Converter={StaticResource w}, ConverterParameter='Добавить сервер'}">
            <TreeView.Resources>
                <DataTemplate DataType="{x:Type sys:String}">
                    <TextBlock Text="{Binding}" MouseUp="Add_MouseUp" />
                </DataTemplate>
                <DataTemplate DataType="{x:Type local:Device}">
                    <TextBlock Text="{Binding DisplayName}" />
                </DataTemplate>
                <HierarchicalDataTemplate DataType="{x:Type local:Server}" ItemsSource="{Binding Childs, Converter={StaticResource w}, ConverterParameter='Добавить камеру'}">
                    <TextBlock Text="{Binding DisplayName}" />
                </HierarchicalDataTemplate>
            </TreeView.Resources>
            <TreeView.ItemContainerStyle>
                <Style TargetType="{x:Type TreeViewItem}">
                    <Setter Property="IsExpanded" Value="True"/>
                </Style>
            </TreeView.ItemContainerStyle>
        </TreeView>
    </Window>
    
    using System;
    using System.Collections;
    using System.Collections.ObjectModel;
    using System.Collections.Specialized;
    using System.Globalization;
    using System.Linq;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Media;
    
    namespace WpfApplication1
    {
        public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
                var model = new Model();
                model.ServerClientList.Add(new Server
                {
                    DisplayName = "dn",
                    Childs = new ObservableCollection<Device> 
                    { 
                        new Device { DisplayName="d1" }
                    }
                });
                this.DataContext = model;
            }
            private void Add_MouseUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
            {
                switch ((e.OriginalSource as TextBlock).Text)
                {
                    case "Добавить сервер":
                        var model = this.DataContext as Model;
                        model.ServerClientList.Add(new Server
                        {
                            DisplayName = "dn",
                            Childs = new ObservableCollection<Device>()
                        });
                        break;
                    case "Добавить камеру":
                        var ti = FindAncestor<TreeViewItem>(e.OriginalSource as DependencyObject);
                        var ri = FindAncestor<TreeViewItem>(ti);
                        (ri.DataContext as Server).Childs.Add(new Device { DisplayName = "nd" });
                        break;
                }
            }
            private T FindAncestor<T>(DependencyObject o) where T : class
            {
                DependencyObject cur = o;
                while (true)
                {
                    cur = VisualTreeHelper.GetParent(cur);
                    if (cur == null) break;
                    if (cur.GetType() == typeof(T))
                        return cur as T;
                }
                return default(T);
            }
        }
        public class Server
        {
            public string DisplayName { get; set; }
            public ObservableCollection<Device> Childs { get; set; }
        }
        public class Device
        {
            public string DisplayName { get; set; }
        }
        class Model
        {
            public ObservableCollection<Server> ServerClientList { get; private set; }
            public Model()
            {
                this.ServerClientList = new ObservableCollection<Server>();
            }
        }
        public class WrapperConverter : IValueConverter
        {
            public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
            {
                if (value is ObservableCollection<Server> || value is ObservableCollection<Device>)
                {
                    var res = new Wrapper(value as INotifyCollectionChanged);
                    res.Add(parameter);
                    return res;
                }
                return value;
            }
            public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
            {
                throw new NotImplementedException();
            }
        }
        public class Wrapper : Collection<object>, INotifyCollectionChanged
        {
            public event NotifyCollectionChangedEventHandler CollectionChanged;
            public object Original {get; private set;}
            public Wrapper(INotifyCollectionChanged col)
            {
                foreach (var o in (IEnumerable)col)
                    this.Add(o);
                col.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(col_CollectionChanged);
                this.Original = col;
            }
            void col_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
            {
                if (e.Action == NotifyCollectionChangedAction.Add)
                {
                    var last = this.Last();
                    this.Remove(last);
                    foreach (var o in e.NewItems)
                        this.Add(o);
                    this.Add(last);
                }
                var eh = this.CollectionChanged;
                if (eh != null)
                    eh(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
            }
        }
    }
    


    • Помечено в качестве ответа skysniper777 27 октября 2011 г. 10:13
    27 октября 2011 г. 8:09
  • в предыдущем примере можно использовать другой вариант WrapperConverter:
     
    public class WrapperConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return (value is INotifyCollectionChanged)
                ? new CollectionExtention<object>(value as INotifyCollectionChanged, parameter)
                : value;
        }
        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { throw new NotImplementedException(); }
    }
    class CollectionExtention<T> : IEnumerable, INotifyCollectionChanged
    {
        public event NotifyCollectionChangedEventHandler CollectionChanged;
        private IEnumerable Head;
        private IEnumerable Tail;
        public CollectionExtention(INotifyCollectionChanged col, params T[] parr)
        {
            col.CollectionChanged += (s, e) =>
            {
                var eh = this.CollectionChanged;
                if (eh != null) eh(this, e);
            };
            this.Head = (IEnumerable)col;
            this.Tail = parr;
        }
        IEnumerator IEnumerable.GetEnumerator()
        {
            return Enumerable.Concat(this.Head.OfType<object>(), this.Tail.OfType<object>()).GetEnumerator();
        }
    }



    • Изменено Malobukv 27 октября 2011 г. 9:43
    • Помечено в качестве ответа skysniper777 27 октября 2011 г. 10:47
    27 октября 2011 г. 9:08

Все ответы

  • можно изменить шаблон TreeView.
    примерно так ...
    <Window x:Class="WpfApplication1.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            Width="400" Height="400"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
        <Grid>
            <Grid.Resources>
                <Style TargetType="TreeView">
                    <Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Auto"/>
                    <Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto"/>
                    <Setter Property="Template">
                        <Setter.Value>
                            <ControlTemplate TargetType="TreeView">
                                <ScrollViewer  Focusable="False">
                                    <StackPanel>
                                        <ItemsPresenter/>
                                        <Label Content="Добавить сервер" />
                                    </StackPanel>
                                </ScrollViewer>
                            </ControlTemplate>
                        </Setter.Value>
                    </Setter>
                </Style>
            </Grid.Resources>
            <TreeView x:Name="tw" ItemsSource="{Binding}" />
        </Grid>
    </Window>
    
    

    • Предложено в качестве ответа Malobukv 22 октября 2011 г. 18:22
    • Помечено в качестве ответа skysniper777 26 октября 2011 г. 10:13
    20 октября 2011 г. 12:14
  • Спасибо, это почти то что надо, но я кое что забыл указать :(

    В итоге должно быть вот так:

    Вот текущий XAML:

                    <ResourceDictionary>
                        <!-- DeviceList TEMPLATE -->
                        <DataTemplate x:Key="DeviceListTemplate">
                            <TextBlock>
                                <TextBlock Text="{Binding Path=DisplayName}" />
                            </TextBlock>
                        </DataTemplate>
                        <!-- ServerClientList TEMPLATE -->
                        <HierarchicalDataTemplate x:Key="ServerClientListTemplate" ItemsSource="{Binding Path=DeviceList}" ItemTemplate="{StaticResource DeviceListTemplate}" >
                            <Border Background="LightGray" CornerRadius="10" BorderThickness="2">
                                <StackPanel ToolTip="{Binding Path=DisplayName}" Orientation="Horizontal">
                                    <!--<Image Margin="4,4,4,4" Height="32" Source="/IPRecord;component/Pictures/back_blue_32.png" ></Image>-->
                                    <TextBlock Margin="4" VerticalAlignment="Center" Text="{Binding Path=DisplayName}"/>
                                    <TextBlock Margin="4" VerticalAlignment="Center" Text="{Binding Path=IP, StringFormat=({0})}"/>
                                </StackPanel>
                            </Border>
                        </HierarchicalDataTemplate>
                    </ResourceDictionary>
    


     

    • Изменено skysniper777 20 октября 2011 г. 13:24
    20 октября 2011 г. 13:19
  • Тогда меняйте Template в ServerClientListTemplate так же как было вам показано выше.
    21 октября 2011 г. 7:49
    Отвечающий
  • Тогда меняйте Template в ServerClientListTemplate так же как было вам показано выше.

     

    В том то и проблема, я незнаю как.

    Можно пример?

    21 октября 2011 г. 8:07
  • Пардон, нужно использовать в шаблоне для TreeViewItem.
    21 октября 2011 г. 8:28
    Отвечающий
  • Нет видимо сам я с этим не справлюсь, не дорос еще :(

    Может кто то конкретно к моей задаче XAML TreeViewItem сделать?

    21 октября 2011 г. 11:47
  • > Спасибо, это почти то что надо, но я кое что забыл указать :( В итоге должно быть вот так: ...
     

    в таком случае можно использовать Converter (который добавит экземпляр типа None) и два шаблона для Item и None:

    <Window x:Class="WpfApplication1.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            Width="800" Height="400"
            xmlns:local="clr-namespace:WpfApplication1"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
        <Grid>
            <Grid.Resources>
                <local:ChildsConverter x:Key="cc"  />
            </Grid.Resources>
            <TreeView ItemsSource="{Binding}" x:Name="tw">
                <TreeView.Resources>
                    <DataTemplate DataType="{x:Type local:None}">
                        <Button Content="Добавить" />
                    </DataTemplate>
                    <HierarchicalDataTemplate DataType="{x:Type local:Item}" ItemsSource="{Binding Childs, Converter={StaticResource cc}}">
                        <TextBlock Text="{Binding Name}" />
                    </HierarchicalDataTemplate>
                </TreeView.Resources>
            </TreeView>
        </Grid>
    </Window>
    
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Windows;
    using System.Windows.Data;
    
    namespace WpfApplication1
    {
        public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
                var rnd = new Random();
                tw.DataContext = Enumerable
                    .Range(0, 10)
                    .Select(i => new Item
                    {
                        Name = "item" + i,
                        Childs = Enumerable
                            .Range(0, rnd.Next(2, 5))
                            .Select(c => new Item { Name = "child" + c })
                    });
            }
        }
    
        public class Item
        {
            public string Name { get; set; }
            public IEnumerable<Item> Childs { get; set; }
        }
    
        public class None {}
    
        public class ChildsConverter : IValueConverter
        {
            public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
            {
                var en = value as IEnumerable<Item>;
                if (en != null)
                {
                    var lst = new List<object>(en);
                    lst.Add(new None());
                    return lst;
                }
                return value;
            }
            public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
            {
                throw new NotImplementedException();
            }
        }
    }
    
    • Предложено в качестве ответа Malobukv 22 октября 2011 г. 18:21
    • Помечено в качестве ответа skysniper777 25 октября 2011 г. 7:38
    • Снята пометка об ответе skysniper777 25 октября 2011 г. 13:22
    • Помечено в качестве ответа skysniper777 26 октября 2011 г. 10:13
    22 октября 2011 г. 18:04
  • другой вариант без None, на основе ItemTemplateSelector:
     

    <Window x:Class="WpfApplication1.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            Width="800" Height="400"
            xmlns:local="clr-namespace:WpfApplication1"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
        <Grid>
            <Grid.Resources>
                <local:ChildsConverter x:Key="cc"  />
                <DataTemplate x:Key="itm" >
                    <TextBlock Text="{Binding Name}" />
                </DataTemplate>
                <DataTemplate x:Key="ctrl">
                    <TextBlock Text="Добавить" />
                </DataTemplate>
                <local:TemplateSelector x:Key="ts" 
                    Item="{StaticResource itm}" Control="{StaticResource ctrl}" />
                <HierarchicalDataTemplate x:Key="ht" 
                    ItemsSource="{Binding Childs, Converter={StaticResource cc}}"
                    ItemTemplateSelector="{StaticResource ts}">
                    <TextBlock Text="{Binding Name}" />
                </HierarchicalDataTemplate>
            </Grid.Resources>
            <TreeView ItemsSource="{Binding}" x:Name="tw" ItemTemplate="{StaticResource ht}" />
        </Grid>
    </Window>
    
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Windows;
    using System.Windows.Data;
    using System.Windows.Controls;
    
    namespace WpfApplication1
    {
        public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
                var rnd = new Random();
                tw.DataContext = Enumerable
                    .Range(0, 10)
                    .Select(i => new Item
                    {
                        Name = "item" + i,
                        Childs = Enumerable
                            .Range(0, rnd.Next(2, 5))
                            .Select(c => new Item { Name = "child" + c })
                    });
            }
        }
    
        public class Item
        {
            public string Name { get; set; }
            public IEnumerable<Item> Childs { get; set; }
        }
    
        public class TemplateSelector : DataTemplateSelector
        {
            public DataTemplate Item { get; set; }
            public DataTemplate Control { get; set; }
            public override DataTemplate SelectTemplate(object item, DependencyObject container)
            {
                return (item is Item) ? Item : Control;
            }
        }
    
        public class ChildsConverter : IValueConverter
        {
            public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
            {
                var en = value as IEnumerable<Item>;
                if (en != null)
                {
                    var lst = new List<object>(en);
                    lst.Add(new object());
                    return lst;
                }
                return value;
            }
            public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
            {
                throw new NotImplementedException();
            }
        }
    }
    


    • Предложено в качестве ответа Malobukv 22 октября 2011 г. 18:21
    • Помечено в качестве ответа skysniper777 25 октября 2011 г. 7:38
    • Снята пометка об ответе skysniper777 25 октября 2011 г. 13:22
    • Помечено в качестве ответа skysniper777 26 октября 2011 г. 10:13
    22 октября 2011 г. 18:09
  • и еще один вариант - перехват TreeViewItem.ExpandedEvent и изменение TreeViewItem.ItemsSource

     

    <Window x:Class="WpfApplication1.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            Width="800" Height="400"
            xmlns:local="clr-namespace:WpfApplication1"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
        <Grid>
            <Grid.Resources>
                <DataTemplate x:Key="itm" >
                    <TextBlock Text="{Binding Name}" />
                </DataTemplate>
                <DataTemplate x:Key="ctrl">
                    <TextBlock Text="Добавить" />
                </DataTemplate>
                <local:TemplateSelector x:Key="ts" 
                    Item="{StaticResource itm}" Control="{StaticResource ctrl}" />
                <HierarchicalDataTemplate x:Key="ht" 
                    ItemsSource="{Binding Childs}"
                    ItemTemplateSelector="{StaticResource ts}">
                    <TextBlock Text="{Binding Name}" />
                </HierarchicalDataTemplate>
            </Grid.Resources>
            <TreeView ItemsSource="{Binding}" x:Name="tw" ItemTemplate="{StaticResource ht}" />
        </Grid>
    </Window>
    
    
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Windows;
    using System.Windows.Data;
    using System.Windows.Controls;
    using System.Windows.Media;
    using System.Windows.Controls.Primitives;
    
    namespace WpfApplication1
    {
        public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
                var rnd = new Random();
                tw.DataContext = Enumerable
                    .Range(0, 10)
                    .Select(i => new Item
                    {
                        Name = "item" + i,
                        Childs = Enumerable
                            .Range(0, rnd.Next(2, 5))
                            .Select(c => new Item { Name = "child" + c })
                    });
    
                tw.AddHandler(TreeViewItem.ExpandedEvent, new RoutedEventHandler(TreeViewItemExpanded));
            }
    
            private void TreeViewItemExpanded(object sender, RoutedEventArgs e)
            {
                var ti = e.OriginalSource as TreeViewItem;
                if ((ti != null) && (ti.ItemContainerGenerator.Status != GeneratorStatus.ContainersGenerated))
                {
                    var lst = new List<object>(ti.ItemsSource.OfType<object>());
                    lst.Add(new object());
                    ti.ItemsSource = lst;
                }
            }
        }
    
        public class Item
        {
            public string Name { get; set; }
            public IEnumerable<Item> Childs { get; set; }
        }
    
        public class TemplateSelector : DataTemplateSelector
        {
            public DataTemplate Item { get; set; }
            public DataTemplate Control { get; set; }
            public override DataTemplate SelectTemplate(object item, DependencyObject container)
            {
                return (item is Item) ? Item : Control;
            }
        }
    }
    

    • Предложено в качестве ответа Malobukv 22 октября 2011 г. 18:21
    • Помечено в качестве ответа skysniper777 25 октября 2011 г. 7:38
    • Снята пометка об ответе skysniper777 25 октября 2011 г. 13:22
    • Помечено в качестве ответа skysniper777 26 октября 2011 г. 10:13
    22 октября 2011 г. 18:15
  • Уважаемый пользователь, пожалуйста, не забудьте отметить сообщение или сообщения, которые являются решением вашей проблемы, даже если это ваше собстевенное сообщение. Это можно сделать с помощью кнопки 'Пометить как ответ', которая есть под каждым сообщением.

    Спасибо.


    Для связи [mail]
    24 октября 2011 г. 7:24
  • К сожалению у меня так и не получилось заставить обновляться TreeView при добавлении в ObservableCollection<ServerClientVM> ServerClientList элемента.

    Попробовал все три метода. Как быть?

    25 октября 2011 г. 13:24
  • > К сожалению у меня так и не получилось заставить обновляться TreeView при добавлении в ObservableCollection<ServerClientVM> ServerClientList элемента. Попробовал все три метода. Как быть?


    мой код работает. вы внесли какие-то изменения? покажите код.
    давайте уточним ...
    вначале был вопрос: как сделать кнопку "Добавить сервер"?  -- есть ответ.
    затем появился вопрос: как в подузлах сделать кнопки "Добавить камеру"? -- есть ответ.
    теперь вопрос: как обновлять TreeView?  -- так?



    • Изменено Malobukv 25 октября 2011 г. 13:52
    25 октября 2011 г. 13:28
  • > К сожалению у меня так и не получилось заставить обновляться TreeView при добавлении в ObservableCollection<ServerClientVM> ServerClientList элемента. Попробовал все три метода. Как быть?


    мой код работает. вы внесли какие-то изменения? покажите код.
    давайте уточним ...
    вначале был вопрос: как сделать кнопку "Добавить сервер"?  -- есть ответ.
    затем появился вопрос: как в подузлах сделать кнопки "Добавить камеру"? -- есть ответ.
    теперь вопрос: как обновлять TreeView?  -- так?




    Все верно, это моя ошибка что изначально указал недостаточно данных.

    Если в кратце то у вас, насколько я понимаю, заменяется ItemsSource у TreeView, тогда как у меня ItemsSource="{Binding Path=ServerClientList}"

    • Изменено skysniper777 26 октября 2011 г. 11:20
    25 октября 2011 г. 14:16
  • > ...заставить обновляться TreeView при добавлении в ObservableCollection<ServerClientVM> ServerClientList элемента.


    надо указать DataContext и привязки шаблонов.

    <Window x:Class="WpfApplication1.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            Width="300" Height="300"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    
        <StackPanel>
            <Button Content="Text" Click="Button_Click" HorizontalAlignment="Left" VerticalAlignment="Top" />
            <TreeView x:Name="tv" ItemsSource="{Binding}" ItemTemplate="{DynamicResource ht}">
                <TreeView.Resources>
                    <DataTemplate x:Key="dt">
                        <TextBlock Text="{Binding}" />
                    </DataTemplate>
                    <HierarchicalDataTemplate ItemsSource="{Binding Childs}" ItemTemplate="{StaticResource dt}" x:Key="ht">
                        <TextBlock Text="{Binding DisplayName}" />
                    </HierarchicalDataTemplate>
                </TreeView.Resources>
            </TreeView>
        </StackPanel>
    </Window>
    
    using System.Collections.ObjectModel;
    using System.Windows;
    using System.Collections.Generic;
    
    namespace WpfApplication1
    {
        public partial class MainWindow : Window
        {
            ObservableCollection<ServerClientVM> ServerClientList;
            public MainWindow()
            {
                InitializeComponent();
                this.ServerClientList = new ObservableCollection<ServerClientVM>();
                tv.DataContext = this.ServerClientList;
            }
            private void Button_Click(object sender, RoutedEventArgs e)
            {
                this.ServerClientList.Add(new ServerClientVM
                {
                    DisplayName = "dn",
                    Childs = new List<int> { 1, 2, 3 }
                });
            }
        }
    
        public class ServerClientVM
        {
            public string DisplayName { get; set; }
            public object Childs { get; set; }
        }
    }
    


      
    > Использование TempServer один из вариантов добавления сервера в список, нужно только как то забиндить (или еще что то сделать, что тоже является для меня вопросом) его к последнему элементу в списке.


    т.е. в ServerClientList надо добавить элемент (ServerClientBaseVM); изменения должно отобразиться в TreeView?




    26 октября 2011 г. 11:43
  • > Если в кратце то у вас, насколько я понимаю, заменяется ItemsSource у TreeView, тогда как у меня ItemsSource="{Binding Path=ServerClientList}"


    в такой ситуации так

    <Window x:Class="WpfApplication1.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            Width="300" Height="300"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
        <StackPanel>
            <Button Content="Text" Click="Button_Click" HorizontalAlignment="Left" VerticalAlignment="Top" />
            <TreeView x:Name="tv" ItemsSource="{Binding ServerClientList}" ItemTemplate="{DynamicResource ht}">
                <TreeView.Resources>
                    <DataTemplate x:Key="dt">
                        <TextBlock Text="{Binding}" />
                    </DataTemplate>
                    <HierarchicalDataTemplate ItemsSource="{Binding Childs}" ItemTemplate="{StaticResource dt}" x:Key="ht">
                        <TextBlock Text="{Binding DisplayName}" />
                    </HierarchicalDataTemplate>
                </TreeView.Resources>
            </TreeView>
        </StackPanel>
    </Window>
    
    
    using System.Collections.ObjectModel;
    using System.Windows;
    using System.Collections.Generic;
    
    namespace WpfApplication1
    {
        public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
                this.DataContext = new Model();
            }
    
            private void Button_Click(object sender, RoutedEventArgs e)
            {
                var model = this.DataContext as Model;
                model.ServerClientList.Add(new ServerClientVM
                {
                    DisplayName = "dn",
                    Childs = new List<int> { 1, 2, 3 }
                });
            }
        }
    
        class ServerClientVM
        {
            public string DisplayName { get; set; }
            public object Childs { get; set; }
        }
    
        class Model
        {
            public ObservableCollection<ServerClientVM> ServerClientList { get; private set; }
            public Model()
            {
                this.ServerClientList = new ObservableCollection<ServerClientVM>();
            }
        }
    }
    


    26 октября 2011 г. 12:13
  • Я немного другое имел ввиду, то что вы выше указали у меня прекрасно работает, не работает вот что:

    <Window x:Class="WpfApplication1.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:local="clr-namespace:WpfApplication1" 
            Title="MainWindow" Height="350" Width="525">
        <StackPanel>
            <StackPanel.Resources>
                <local:ChildsConverter x:Key="servercc"/>
            </StackPanel.Resources>
    
            <Button Content="Text" Click="Button_Click" HorizontalAlignment="Left" VerticalAlignment="Top" />
            <TreeView x:Name="tv" ItemsSource="{Binding ServerClientList, Converter={StaticResource servercc}}">
                <TreeView.Resources>
                    <DataTemplate x:Key="dt">
                        <TextBlock Text="{Binding}" />
                    </DataTemplate>
                    <HierarchicalDataTemplate ItemsSource="{Binding Childs}"  ItemTemplate="{StaticResource dt}" DataType="{x:Type local:ServerClientVM}">
                        <TextBlock Text="{Binding DisplayName}" />
                    </HierarchicalDataTemplate>
                </TreeView.Resources>
            </TreeView>
        </StackPanel>
    
    
    </Window>
    
    

     

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using System.Windows.Navigation;
    using System.Windows.Shapes;
    using System.Collections.ObjectModel;
    using System.Windows.Controls.Primitives;
    
    namespace WpfApplication1
    {
        public partial class MainWindow : Window
        {
            ObservableCollection<ServerClientVM> ServerClientList;
            public MainWindow()
            {
                InitializeComponent();
                this.DataContext = new Model();
                var model = this.DataContext as Model;
                model.ServerClientList.Add(new ServerClientVM
                {
                    DisplayName = "dn",
                    Childs = new List<int> { 1, 2, 3 }
                });
    //            tv.AddHandler(TreeViewItem.ExpandedEvent, new RoutedEventHandler(TreeViewItemExpanded));
            }
    
            //private void TreeViewItemExpanded(object sender, RoutedEventArgs e)
            //{
            //    var ti = e.OriginalSource as TreeViewItem;
            //    if ((ti != null) && (ti.ItemContainerGenerator.Status != GeneratorStatus.ContainersGenerated) && (ti.ItemsSource != null))
            //    {
            //        var lst = new List<object>(ti.ItemsSource.OfType<object>());
            //        lst.Add(new Object());
            //        ti.ItemsSource = lst;
            //    }
            //}
    
            private void Button_Click(object sender, RoutedEventArgs e)
            {
                var model = this.DataContext as Model;
                model.ServerClientList.Add(new ServerClientVM
                {
                    DisplayName = "dn",
                    Childs = new List<int> { 1, 2, 3 }
                });
            }
        }
    
        public class ServerClientVM
        {
            public string DisplayName { get; set; }
            public object Childs { get; set; }
        }
    
        class Model
        {
            public ObservableCollection<ServerClientVM> ServerClientList { get; private set; }
            public Model()
            {
                this.ServerClientList = new ObservableCollection<ServerClientVM>();
            }
        }
    
    
        public class ChildsConverter : IValueConverter
        {
            public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
            {
                var en = value as IEnumerable<ServerClientVM>;
                if (en != null)
                {
                    var lst = new List<object>(en);
                    ServerClientVM sc = new ServerClientVM();
                    sc.DisplayName = "Новый сервер";
                    lst.Add(sc);
                    return lst;
                }
                return value;
            }
            public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
            {
                throw new NotImplementedException();
            }
        }
    }
    
    
    

    С добавлением элемента в своей задаче справился через команду и передачу параметра команды.


    • Изменено skysniper777 26 октября 2011 г. 12:50
    26 октября 2011 г. 12:50
  • > var en = value as IEnumerable<ServerClientVM>;
    if (en != null) { 
        var lst = new List<object>(en);
        ...
        return lst;


    этот код подменяет ObservableCollection на List; из-за этого перестает работать привязка TreeView;
    можно сделать так:
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        var lst = value as ObservableCollection<ServerClientVM>;
        if (lst != null)
        {
            ServerClientVM sc = new ServerClientVM { DisplayName = "Новый сервер" };
            lst.Add(sc);
            return lst;
        }
        return value;
    }
    
    • Помечено в качестве ответа skysniper777 26 октября 2011 г. 13:23
    26 октября 2011 г. 13:16
  • Malobukv спасибо за помощь, очень помогли в освоении WPF.

    Хотя очень жаль что в итоге пришли к тому что изменяется сам ServerClientList.

    В первом посте я писал что "Проблема в том что по логике в ServerClientList я его добавить не могу, т.к. это список серверов."

    И например код foreach  чтобы исключить ненужный последний элемент из списка, не будет работать

    foreach (ServerClientVM scm in ServerClientList)
    {
         _testString = _testString + scm.DisplayName;
    }
    26 октября 2011 г. 14:03
  • > Хотя очень жаль что в итоге пришли к тому что изменяется сам ServerClientList.


    можно сделать обертку для ServerClientList


    > И например код foreach чтобы исключить ненужный последний элемент из списка, не будет работать foreach (ServerClientVM scm in ServerClientList)
     
     
    выбрать элементы определенного типа:

    foreach(var itm in ServerClientList.OfType<ServerClientVM>())
    {
    }
    

    26 октября 2011 г. 20:29
  • > жаль что в итоге пришли к тому что изменяется сам ServerClientList [...] по логике в ServerClientList я его добавить не могу, т.к. это список серверов


    пример который не меняет коллекции серверов и устройств.

    <Window x:Class="WpfApplication1.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            Width="300" Height="600"
            xmlns:sys="clr-namespace:System;assembly=mscorlib"
            xmlns:local="clr-namespace:WpfApplication1" 
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
        <Window.Resources>
            <local:WrapperConverter x:Key="w"/>
        </Window.Resources>
        <TreeView x:Name="tv" ItemsSource="{Binding ServerClientList, Converter={StaticResource w}, ConverterParameter='Добавить сервер'}">
            <TreeView.Resources>
                <DataTemplate DataType="{x:Type sys:String}">
                    <TextBlock Text="{Binding}" MouseUp="Add_MouseUp" />
                </DataTemplate>
                <DataTemplate DataType="{x:Type local:Device}">
                    <TextBlock Text="{Binding DisplayName}" />
                </DataTemplate>
                <HierarchicalDataTemplate DataType="{x:Type local:Server}" ItemsSource="{Binding Childs, Converter={StaticResource w}, ConverterParameter='Добавить камеру'}">
                    <TextBlock Text="{Binding DisplayName}" />
                </HierarchicalDataTemplate>
            </TreeView.Resources>
            <TreeView.ItemContainerStyle>
                <Style TargetType="{x:Type TreeViewItem}">
                    <Setter Property="IsExpanded" Value="True"/>
                </Style>
            </TreeView.ItemContainerStyle>
        </TreeView>
    </Window>
    
    using System;
    using System.Collections;
    using System.Collections.ObjectModel;
    using System.Collections.Specialized;
    using System.Globalization;
    using System.Linq;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Media;
    
    namespace WpfApplication1
    {
        public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
                var model = new Model();
                model.ServerClientList.Add(new Server
                {
                    DisplayName = "dn",
                    Childs = new ObservableCollection<Device> 
                    { 
                        new Device { DisplayName="d1" }
                    }
                });
                this.DataContext = model;
            }
            private void Add_MouseUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
            {
                switch ((e.OriginalSource as TextBlock).Text)
                {
                    case "Добавить сервер":
                        var model = this.DataContext as Model;
                        model.ServerClientList.Add(new Server
                        {
                            DisplayName = "dn",
                            Childs = new ObservableCollection<Device>()
                        });
                        break;
                    case "Добавить камеру":
                        var ti = FindAncestor<TreeViewItem>(e.OriginalSource as DependencyObject);
                        var ri = FindAncestor<TreeViewItem>(ti);
                        (ri.DataContext as Server).Childs.Add(new Device { DisplayName = "nd" });
                        break;
                }
            }
            private T FindAncestor<T>(DependencyObject o) where T : class
            {
                DependencyObject cur = o;
                while (true)
                {
                    cur = VisualTreeHelper.GetParent(cur);
                    if (cur == null) break;
                    if (cur.GetType() == typeof(T))
                        return cur as T;
                }
                return default(T);
            }
        }
        public class Server
        {
            public string DisplayName { get; set; }
            public ObservableCollection<Device> Childs { get; set; }
        }
        public class Device
        {
            public string DisplayName { get; set; }
        }
        class Model
        {
            public ObservableCollection<Server> ServerClientList { get; private set; }
            public Model()
            {
                this.ServerClientList = new ObservableCollection<Server>();
            }
        }
        public class WrapperConverter : IValueConverter
        {
            public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
            {
                if (value is ObservableCollection<Server> || value is ObservableCollection<Device>)
                {
                    var res = new Wrapper(value as INotifyCollectionChanged);
                    res.Add(parameter);
                    return res;
                }
                return value;
            }
            public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
            {
                throw new NotImplementedException();
            }
        }
        public class Wrapper : Collection<object>, INotifyCollectionChanged
        {
            public event NotifyCollectionChangedEventHandler CollectionChanged;
            public object Original {get; private set;}
            public Wrapper(INotifyCollectionChanged col)
            {
                foreach (var o in (IEnumerable)col)
                    this.Add(o);
                col.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(col_CollectionChanged);
                this.Original = col;
            }
            void col_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
            {
                if (e.Action == NotifyCollectionChangedAction.Add)
                {
                    var last = this.Last();
                    this.Remove(last);
                    foreach (var o in e.NewItems)
                        this.Add(o);
                    this.Add(last);
                }
                var eh = this.CollectionChanged;
                if (eh != null)
                    eh(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
            }
        }
    }
    


    • Помечено в качестве ответа skysniper777 27 октября 2011 г. 10:13
    27 октября 2011 г. 8:09
  • в предыдущем примере можно использовать другой вариант WrapperConverter:
     
    public class WrapperConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return (value is INotifyCollectionChanged)
                ? new CollectionExtention<object>(value as INotifyCollectionChanged, parameter)
                : value;
        }
        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { throw new NotImplementedException(); }
    }
    class CollectionExtention<T> : IEnumerable, INotifyCollectionChanged
    {
        public event NotifyCollectionChangedEventHandler CollectionChanged;
        private IEnumerable Head;
        private IEnumerable Tail;
        public CollectionExtention(INotifyCollectionChanged col, params T[] parr)
        {
            col.CollectionChanged += (s, e) =>
            {
                var eh = this.CollectionChanged;
                if (eh != null) eh(this, e);
            };
            this.Head = (IEnumerable)col;
            this.Tail = parr;
        }
        IEnumerator IEnumerable.GetEnumerator()
        {
            return Enumerable.Concat(this.Head.OfType<object>(), this.Tail.OfType<object>()).GetEnumerator();
        }
    }



    • Изменено Malobukv 27 октября 2011 г. 9:43
    • Помечено в качестве ответа skysniper777 27 октября 2011 г. 10:47
    27 октября 2011 г. 9:08
  • Еще раз спасибо.

    Велик и могуч WPF.

    Я даже не совсем понимаю как работают последние варианты, но они мне абсолютно подходят.

    27 октября 2011 г. 10:50