简体   繁体   English

WPF MVVM管理多个窗口

[英]WPF MVVM Managing multiple windows

Looking to write a note application in WPF/C# MVVM, not because we need another one but because it'll help me go over a few things I'm trying to become more familiar with. 想要在WPF / C#MVVM中编写笔记应用程序,不是因为我们需要另一个,而是因为它可以帮助我完成一些我想变得更加熟悉的事情。 My question is regarding some guidance on how to handle multiple windows. 我的问题是关于如何处理多个窗口的一些指导。 For example there will be multiple notes not tied to a main window. 例如,将有多个注释未绑定到主窗口。 I'd like to keep track of all open windows, for example if one received focus, I may want to bring the other note windows to the front, but not remove focus from the one I selected, not looking for anyone to give me the code, just some guidance on how to handle it. 我想跟踪所有打开的窗口,例如,如果一个窗口获得焦点,我可能希望将其他笔记窗口置于最前面,但不要将焦点从我选择的窗口中移开,而不是寻找任何人来给我代码,只是一些有关如何处理它的指导。

Maybe this can help you in some way: http://kentb.blogspot.nl/2011/11/application-im-currently-working-on-top.html 也许这可以在某种程度上帮助您: http : //kentb.blogspot.nl/2011/11/application-im-currently-working-on-top.html

The important parts from the article: 文章中的重要部分:

What I did instead was had the WindowItemsControl create WindowItemsControlItem instances as containers. 相反,我所做的是让WindowItemsControl创建WindowItemsControlItem实例作为容器。 These containers are really just surrogates for the Window they represent. 这些容器实际上只是它们所代表的窗口的替代。 When they're initialized, they display the Window. 初始化后,它们将显示窗口。 When they're destroyed, they close the Window. 当它们被销毁时,它们会关闭窗户。 In addition, if a Window is closed ahead of time, the corresponding data item is removed from the underlying collection and thus too the surrogate from the visual tree. 另外,如果提前关闭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;
        }
    }
}  
  • it declares some properties (ShowDialog, Owner, WindowStartupLocation) that assist it in the display of child Windows 它声明了一些属性(ShowDialog,Owner,WindowStartupLocation),以帮助其在子Windows的显示中
  • it declares a RemoveDataItemWhenWindowClosed property that can be used to prevent the control from removing data items when a window is closed. 它声明一个RemoveDataItemWhenWindowClosed属性,该属性可用于防止控件在关闭窗口时删除数据项。 This can be useful in shutdown or other situations where windows are being closed programmatically rather than by the user 这在关机或其他以编程方式而不是由用户关闭窗口的情况下很有用
  • I don't apply the ItemContainerStyle to the containers themselves, but instead hold out so that I can apply them to the Windows they represent 我没有将ItemContainerStyle应用于容器本身,而是坚持使用,以便可以将它们应用于它们所代表的Windows
  • I also make sure that any change of Owner is applied to any existing Windows 我还要确保将所有者的任何更改应用于任何现有Windows
  • the default style is overridden to remove unnecessary stuff like the Border, because the WindowItemsControl will never actually be visible on screen 覆盖默认样式以删除不必要的内容,例如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;
    }
}
  • relevant properties on the WindowItemsControl are bound to the correct properties on the Windows themselves WindowItemsControl上的相关属性绑定到Windows本身上的正确属性
  • Windows are displayed when the surrogate is initialized, and closed when the surrogate is unloaded 代理初始化时显示窗口,而代理被卸载时关闭窗口
  • as mentioned earlier, Windows that are closed before the surrogate is destroyed (perhaps by the user clicking the close button) result in the related data item in the underlying collection being removed (unless the RemoveDataItemWhenWindowClosed property has been set to false). 如前所述,在销毁代理之前关闭的Windows(可能是用户单击关闭按钮)导致基础集合中的相关数据项被删除(除非RemoveDataItemWhenWindowClosed属性设置为false)。 This, in turn, will cause the surrogate to be removed from the visual tree. 反过来,这将导致从可视树中删除代理。 In other words, if I close a widget Window, the corresponding WidgetViewModel will be removed from my collection of widget view models. 换句话说,如果我关闭小部件窗口,则相应的WidgetViewModel将从我的小部件视图模型集合中删除。 Then, the ItemsControl will remove the related surrogate container from the visual tree. 然后,ItemsControl将从视觉树中删除相关的代理容器。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM