WPF中遇到的一些问题总结

1.近日想实现一个功能,在tabcontrol中动态添加tabitem,每个tabitem中显示的数据模型一样,但是数据内容不一样。第一想法就是自定义一个tabitem的模板,然后这个模板中可以包含一个usercontrol来组织我的数据模型。当初的实现如图中注释代码所示:

 在ContentTemplate中设置一个DataTemplate,DataTemplate中包含一个自定义Usercontrol,名称为TabItemWithGraphic,主要是在Tabitem中实现绘图功能。通过测试发现每个TabItem都能根据数据绘图,但是当切换某个TabItem的数据值是,所有的TabItem都会同时改变,显然不符合预期。一点点琢磨并查找各种资料,终于在Stack Overflow上找到了问题的本质原因,那就是关于模板的使用。模板是一种资源,是可以供所有满足要求的元素公用共享的,运行时只有一份,如此一来若我们将Usercontrol放置在模板中,那岂不是这个Usercontrol是对所有Tabitem共享,可以想到当把其中一个Tabitem数据更改时,则Usercontrol显示内容发生变化,由此导致其他的Tabitem中显示数据也发生变化。
找到了问题的根本原因,问题就好解决了,那就是我们不能把Usercontrol直接放置在模板中,而是根据需要每个Tabitem中实例化一个自己的usercontrol,便可以解决问题,如果你用的是MVVM开发的话,发现会比较繁琐了。因为相比起来要自己写代码来初始化Usercontrol等操作而言,能直接定义在模板中,并将数据源绑定到Tabcontrol的Source上确实是要麻烦多了。可惜Stack Overflow的链接我自己目前找不到了,大概讲一下,就是给自定义一个附加属性CachedItemsSource,然后根据这个Source的变化来动态增加或减少包含Usercontrol的TabItem。最后附上参考的解决办法:

/*
*---------------------------------
*|        All rights reserved.
*|        author: lizhanping
*|        version:1.0
*|        File: TabControlExtension.cs
*|        Summary: 
*|        Date: 2020/1/9 15:28:40
*---------------------------------
*/
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;

namespace TabControlTest
{
    public static class TabControlExtension
    {      

        // Custom DependencyProperty for a CachedItemsSource
        public static readonly DependencyProperty CachedItemsSourceProperty =
            DependencyProperty.RegisterAttached("CachedItemsSource", typeof(IList), typeof(TabControlExtension), new PropertyMetadata(null, CachedItemsSource_Changed));

        // Get items
        public static IList GetCachedItemsSource(DependencyObject dependencyObject)
        {
            return dependencyObject?.GetValue(CachedItemsSourceProperty) as IList;
        }

        // Set items
        public static void SetCachedItemsSource(DependencyObject dependencyObject, IEnumerable value)
        {
            dependencyObject?.SetValue(CachedItemsSourceProperty, value);
        }

         
        // Change Event
        public static void CachedItemsSource_Changed(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
        {
            if (!(dependencyObject is TabControl))
                return;
            TabControl tabControl = dependencyObject as TabControl;
            var changeAction = new NotifyCollectionChangedEventHandler(
                (o, args) =>
                {
                    if (GetCachedItemsSource(tabControl) != null)
                        UpdateTabItems(tabControl);
                });

            // if the bound property is an ObservableCollection, attach change events
            if (e.OldValue is INotifyCollectionChanged)
            {
                INotifyCollectionChanged oldValue = e.OldValue as INotifyCollectionChanged;
                oldValue.CollectionChanged -= changeAction;
            }

            if (e.NewValue is INotifyCollectionChanged)
            {
                INotifyCollectionChanged newValue = e.NewValue as INotifyCollectionChanged;
                newValue.CollectionChanged += changeAction;
            }

            if (GetCachedItemsSource(dependencyObject) != null)
                UpdateTabItems(dependencyObject as TabControl);
    }

        private static void UpdateTabItems(TabControl tabControl)
        {
            if (tabControl == null)
                return;

            IList itemsSource = GetCachedItemsSource(tabControl);

            if (itemsSource == null || itemsSource.Count == 0)
            {
                if (tabControl.Items.Count > 0)
                    tabControl.Items.Clear();

                return;
            }


            // loop through items source and make sure datacontext is correct for each one
            for (int i = 0; i < itemsSource.Count; i++)
            {
                if (tabControl.Items.Count <= i)
                {
                    TabItem tabItem = new TabItem();
                    CustomTabItem Source = itemsSource[i] as CustomTabItem;
                    tabItem.Header = Source.Header;
                    TabItemWithGraphic content = new TabItemWithGraphic();
                    Binding binding = new Binding();
                    binding.Source = Source;
                    binding.Path = new PropertyPath("Content");
                    BindingOperations.SetBinding(content, TabItemWithGraphic.DataModelProperty, binding);
                    tabItem.Content = content;
                    tabControl.Items.Add(tabItem);
                    tabControl.SelectedItem = tabItem;
                    continue;
                }

               
                //current.DataContext = itemsSource[i];
            }

            for(int i=0;i< itemsSource.Count;i++)
            {
                TabItem current = tabControl.Items[i] as TabItem;
                if (!(tabControl.Items[i] is TabItem))
                    continue;

                if (current.Header.ToString() == (itemsSource[i] as CustomTabItem).Header)
                    continue;
                else
                {
                    tabControl.Items.Remove(current);
                    i--;
                }
            }

            // loop backwards and cleanup extra tabs
            for (int i = tabControl.Items.Count; i > itemsSource.Count; i--)
            {
                tabControl.Items.RemoveAt(i - 1);
            }
        }
    }
}



猜你喜欢

转载自www.cnblogs.com/chyshx/p/12204594.html