[Wpf] كيفية الحفاظ على حالة التحكم ضمن عناصر علامة التبويب في تابكونترول


Answers

حصلت على حلها مع هذا غيض WPF TabControl: Turning Off Tab Virtualization في http://www.codeproject.com/Articles/460989/WPF-TabControl-Turning-Off-Tab-Virtualization هذا فئة تابكونتنت مع الملكية إسكاشد.

Question

أنا الوافد الجديد ل وف، في محاولة لبناء مشروع يتبع توصيات مقال ممتاز جوش سميث يصف نموذج-عرض-فيوموديل تصميم نمط .

باستخدام كود عينة جوش كقاعدة، لقد قمت بإنشاء تطبيق بسيط يحتوي على عدد من "مساحات العمل"، يمثل كل منها علامة تبويب في تابكونترول. في طلبي، مساحة العمل هي محرر مستندات يسمح للمستند الهرمي بالتلاعب عبر عنصر تحكم تريفيو.

على الرغم من أنني قد نجحت في فتح مساحات عمل متعددة وعرض محتوياتها في عنصر تحكم تريفيو ملزمة، أجد أن تريفيو "ينسى" حالته عند التبديل بين علامات التبويب. على سبيل المثال، إذا تم توسيع تريفيو في Tab1 جزئيا، فسيتم عرضه كما انهارت تماما بعد التبديل إلى Tab2 والعودة إلى Tab1. يبدو أن هذا السلوك ينطبق على كافة جوانب حالة التحكم لجميع عناصر التحكم.

بعد بعض التجارب، أدركت أنني يمكن الحفاظ على الدولة داخل تابيتم عن طريق ملزمة صراحة كل ملكية الدولة السيطرة إلى خاصية مخصصة على فيوموديل الأساسية. ومع ذلك، هذا يبدو وكأنه الكثير من العمل الإضافي، عندما أريد ببساطة كل الضوابط بلدي أن نتذكر دولتهم عند التبديل بين مساحات العمل.

أفترض أنني في عداد المفقودين شيء بسيط، ولكن أنا لست متأكدا من أين للبحث عن الجواب. أي دليل سيكون محل تقدير.

شكرا، تيم

تحديث:

كما طلب، سأحاول نشر بعض التعليمات البرمجية التي توضح هذه المشكلة. ومع ذلك، منذ البيانات التي تكمن وراء تريفيو معقدة، وسوف نشر مثال مبسط الذي يحمل نفس التعاطف. هنا هو زمل من النافذة الرئيسية:

<TabControl IsSynchronizedWithCurrentItem="True" ItemsSource="{Binding Path=Docs}">
    <TabControl.ItemTemplate>
        <DataTemplate>
            <ContentPresenter Content="{Binding Path=Name}" />
        </DataTemplate>
    </TabControl.ItemTemplate>

    <TabControl.ContentTemplate>
        <DataTemplate>
            <view:DocumentView />
        </DataTemplate>
    </TabControl.ContentTemplate>
</TabControl>

يرتبط زمل أعلاه بشكل صحيح إلى أوبسيرفابلكولكتيون دوكومنتفيوديل، حيث يتم تقديم كل عضو عبر دوكومنتفيو.

لسهولة هذا المثال، قمت بإزالة تريفيو (المذكورة أعلاه) من دوكومنتفيو واستبداله مع تابكونترول تحتوي على 3 علامات تبويب ثابتة:

<TabControl>
    <TabItem Header="A" />
    <TabItem Header="B" />
    <TabItem Header="C" />
</TabControl>

في هذا السيناريو، لا يوجد ارتباط بين دوكومنتفيو و دوكومنتفيوموديل. عند تشغيل التعليمات البرمجية، تابكونترول الداخلية غير قادر على تذكر اختيارها عندما يتم تبديل تابكونترول الخارجي.

ومع ذلك، إذا ربطت صراحة خاصية تابكونترول الداخلية سيلكتديندكس ...

<TabControl SelectedIndex="{Binding Path=SelectedDocumentIndex}">
    <TabItem Header="A" />
    <TabItem Header="B" />
    <TabItem Header="C" />
</TabControl>

... إلى خاصية وهمية المقابلة على دوكومنتفيوموديل ...

public int SelecteDocumentIndex { get; set; }

... علامة التبويب الداخلية هي قادرة على تذكر اختيارها.

وأنا أفهم أنني يمكن أن تحل بشكل فعال مشكلتي من خلال تطبيق هذه التقنية على كل الملكية البصرية من كل عنصر تحكم، ولكن أنا آمل أن يكون هناك حل أكثر أناقة.




باستخدام فكرة واف أنا جئت إلى هذا الحل البسيط الذي يبدو أن حل هذه المسألة.

يمكنني استخدام السلوك التفاعلي، ولكن الشيء نفسه يمكن القيام به مع الخاصية المرفقة إذا لم يتم الرجوع مكتبة التفاعل

/// <summary>
/// Wraps tab item contents in UserControl to prevent TabControl from re-using its content
/// </summary>
public class TabControlUcWrapperBehavior 
    : Behavior<UIElement>
{
    private TabControl AssociatedTabControl { get { return (TabControl) AssociatedObject; } }

    protected override void OnAttached()
    {
        ((INotifyCollectionChanged)AssociatedTabControl.Items).CollectionChanged += TabControlUcWrapperBehavior_CollectionChanged;
        base.OnAttached();
    }

    protected override void OnDetaching()
    {
        ((INotifyCollectionChanged)AssociatedTabControl.Items).CollectionChanged -= TabControlUcWrapperBehavior_CollectionChanged;
        base.OnDetaching();
    }

    void TabControlUcWrapperBehavior_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        if (e.Action != NotifyCollectionChangedAction.Add) 
            return;

        foreach (var newItem in e.NewItems)
        {
            var ti = AssociatedTabControl.ItemContainerGenerator.ContainerFromItem(newItem) as TabItem;

            if (ti != null && !(ti.Content is UserControl)) 
                ti.Content = new UserControl { Content = ti.Content };
        }
    }
}

والاستخدام

<TabControl ItemsSource="...">
    <i:Interaction.Behaviors>
        <controls:TabControlUcWrapperBehavior/>
    </i:Interaction.Behaviors>
</TabControl>



لقد نشرت جوابا عن سؤال مماثل. في حالتي يدويا إنشاء تابيتمز قد حل مشكلة إنشاء عرض مرارا وتكرارا. تحقق هنا