簡體   English   中英

WPF MVVM管理多個窗口

[英]WPF MVVM Managing multiple windows

想要在WPF / C#MVVM中編寫筆記應用程序,不是因為我們需要另一個,而是因為它可以幫助我完成一些我想變得更加熟悉的事情。 我的問題是關於如何處理多個窗口的一些指導。 例如,將有多個注釋未綁定到主窗口。 我想跟蹤所有打開的窗口,例如,如果一個窗口獲得焦點,我可能希望將其他筆記窗口置於最前面,但不要將焦點從我選擇的窗口中移開,而不是尋找任何人來給我代碼,只是一些有關如何處理它的指導。

也許這可以在某種程度上幫助您: http : //kentb.blogspot.nl/2011/11/application-im-currently-working-on-top.html

文章中的重要部分:

相反,我所做的是讓WindowItemsControl創建WindowItemsControlItem實例作為容器。 這些容器實際上只是它們所代表的窗口的替代。 初始化后,它們將顯示窗口。 當它們被銷毀時,它們會關閉窗戶。 另外,如果提前關閉Window,則相應的數據項將從基礎集合中刪除,因此也從可視樹中替代。

public class WindowItemsControl : ItemsControl
{
    public static readonly DependencyProperty ShowDialogProperty = DependencyProperty.Register(
        "ShowDialog",
        typeof(bool),
        typeof(WindowItemsControl));
 
    public static readonly DependencyProperty OwnerProperty = DependencyProperty.Register(
        "Owner",
        typeof(Window),
        typeof(WindowItemsControl),
        new FrameworkPropertyMetadata(OnOwnerChanged));
 
    public static readonly DependencyProperty WindowStartupLocationProperty = DependencyProperty.Register(
        "WindowStartupLocation",
        typeof(WindowStartupLocation),
        typeof(WindowItemsControl));
 
    public static readonly DependencyProperty RemoveDataItemWhenWindowClosedProperty = DependencyProperty.Register(
        "RemoveDataItemWhenWindowClosed",
        typeof(bool),
        typeof(WindowItemsControl),
        new FrameworkPropertyMetadata(true));
 
    static WindowItemsControl()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(WindowItemsControl), new FrameworkPropertyMetadata(typeof(WindowItemsControl)));
    }
 
    public bool ShowDialog
    {
        get { return (bool)this.GetValue(ShowDialogProperty); }
        set { this.SetValue(ShowDialogProperty, value); }
    }
 
    public Window Owner
    {
        get { return this.GetValue(OwnerProperty) as Window; }
        set { this.SetValue(OwnerProperty, value); }
    }
 
    public WindowStartupLocation WindowStartupLocation
    {
        get { return (WindowStartupLocation)this.GetValue(WindowStartupLocationProperty); }
        set { this.SetValue(WindowStartupLocationProperty, value); }
    }
 
    public bool RemoveDataItemWhenWindowClosed
    {
        get { return (bool)this.GetValue(RemoveDataItemWhenWindowClosedProperty); }
        set { this.SetValue(RemoveDataItemWhenWindowClosedProperty, value); }
    }
 
    protected override DependencyObject GetContainerForItemOverride()
    {
        return new WindowItemsControlItem(this);
    }
 
    protected override bool IsItemItsOwnContainerOverride(object item)
    {
        return item is WindowItemsControlItem;
    }
 
    protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
    {
        (element as WindowItemsControlItem).Window.Content = item;
    }
 
    protected override bool ShouldApplyItemContainerStyle(DependencyObject container, object item)
    {
        // the item container style will be applied to the windows, not to the containers (which are surrogates for the window)
        return false;
    }
 
    private static void OnOwnerChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
    {
        var windowItemsControl = (WindowItemsControl)dependencyObject;
        var owner = (Window)e.NewValue;
 
        for (var i = 0; i < windowItemsControl.Items.Count; ++i)
        {
            var container = windowItemsControl.ItemContainerGenerator.ContainerFromIndex(i) as WindowItemsControlItem;
 
            if (container == null)
            {
                continue;
            }
 
            container.Window.Owner = owner;
        }
    }
}  
  • 它聲明了一些屬性(ShowDialog,Owner,WindowStartupLocation),以幫助其在子Windows的顯示中
  • 它聲明一個RemoveDataItemWhenWindowClosed屬性,該屬性可用於防止控件在關閉窗口時刪除數據項。 這在關機或其他以編程方式而不是由用戶關閉窗口的情況下很有用
  • 我沒有將ItemContainerStyle應用於容器本身,而是堅持使用,以便可以將它們應用於它們所代表的Windows
  • 我還要確保將所有者的任何更改應用於任何現有Windows
  • 覆蓋默認樣式以刪除不必要的內容,例如Border,因為WindowItemsControl實際上不會在屏幕上可見
public class WindowItemsControlItem : FrameworkElement
{
    private readonly WindowItemsControl windowItemsControl;
    private readonly Window window;
 
    static WindowItemsControlItem()
    {
        // there is no need for these items to be visible as they are simply surrogates for the windows that they display
        VisibilityProperty.OverrideMetadata(typeof(WindowItemsControlItem), new FrameworkPropertyMetadata(Visibility.Collapsed));
    }
 
    public WindowItemsControlItem(WindowItemsControl windowItemsControl)
    {
        windowItemsControl.AssertNotNull("windowItemsControl");
 
        this.windowItemsControl = windowItemsControl;
        this.window = this.CreateWindow(windowItemsControl);
 
        this.Loaded += delegate
        {
            if (this.windowItemsControl.ShowDialog)
            {
                this.window.ShowDialog();
            }
            else
            {
                this.window.Show();
            }
        };
 
        this.Unloaded += delegate
        {
            this.window.Close();
        };
    }
 
    public Window Window
    {
        get { return this.window; }
    }
 
    private Window CreateWindow(WindowItemsControl windowItemsControl)
    {
        var window = new Window
        {
            Owner = windowItemsControl.Owner,
            WindowStartupLocation = windowItemsControl.WindowStartupLocation
        };
 
        BindingOperations.SetBinding(window, Window.DataContextProperty, new Binding("Content") { Source = window });
        BindingOperations.SetBinding(window, Window.StyleProperty, new Binding("ItemContainerStyle") { Source = windowItemsControl });
        BindingOperations.SetBinding(window, Window.ContentTemplateProperty, new Binding("ItemTemplate") { Source = windowItemsControl });
        BindingOperations.SetBinding(window, Window.ContentTemplateSelectorProperty, new Binding("ItemTemplateSelector") { Source = windowItemsControl });
 
        window.Closed += delegate
        {
            // orphan the content because it might be hosted somewhere else later (including in another window)
            window.Content = null;
 
            // if the window closes, attempt to remove the original item from the underlying collection, which will result in this surrogate being removed too
            if (windowItemsControl.RemoveDataItemWhenWindowClosed)
            {
                var editableItems = windowItemsControl.Items as IEditableCollectionView;
 
                if (editableItems != null && editableItems.CanRemove)
                {
                    editableItems.Remove(this.DataContext);
                }
            }
        };
 
        return window;
    }
}
  • WindowItemsControl上的相關屬性綁定到Windows本身上的正確屬性
  • 代理初始化時顯示窗口,而代理被卸載時關閉窗口
  • 如前所述,在銷毀代理之前關閉的Windows(可能是用戶單擊關閉按鈕)導致基礎集合中的相關數據項被刪除(除非RemoveDataItemWhenWindowClosed屬性設置為false)。 反過來,這將導致從可視樹中刪除代理。 換句話說,如果我關閉小部件窗口,則相應的WidgetViewModel將從我的小部件視圖模型集合中刪除。 然后,ItemsControl將從視覺樹中刪除相關的代理容器。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM