zoukankan      html  css  js  c++  java
  • 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);
                }
            }
        }
    }



  • 相关阅读:
    【译】深入理解G1的GC日志(一)
    【译】深入理解G1的GC日志(一)
    【译】深入理解G1的GC日志(一)
    Java 8 Time Api 使用指南-珍藏限量版
    颠覆微服务认知:深入思考微服务的七个主流观点
    函数式编程让你忘记设计模式
    使用Optional摆脱NPE的折磨
    使用Optional摆脱NPE的折磨
    使用Optional摆脱NPE的折磨
    面试官:优化代码中大量的if/else,你有什么方案?
  • 原文地址:https://www.cnblogs.com/chyshx/p/12204594.html
Copyright © 2011-2022 走看看