WPF MVVM管理多个窗口

时间:2014-08-09 18:55:44

标签: wpf windows mvvm

想在WPF / C#MVVM中编写一个笔记应用程序,不是因为我们需要另一个,而是因为它会帮助我解决一些我想要更熟悉的事情。 我的问题是关于如何处理多个窗口的一些指导。例如,将有多个未连接到主窗口的注释。我想跟踪所有打开的窗口,例如,如果一个人获得了焦点,我可能想将其他笔记窗口放在前面,但不能从我选择的窗口移除焦点,而不是寻找任何人给予我的代码,只是一些如何处理它的指导。

1 个答案:

答案 0 :(得分:0)

也许这可以通过某种方式帮助您:http://kentb.blogspot.nl/2011/11/application-im-currently-working-on-top.html

文章的重要部分:

  

我所做的是让WindowItemsControl创建WindowItemsControlItem实例作为容器。这些容器实际上只是它们代表的Window的代理。当它们被初始化时,它们会显示窗口。当它们被摧毁时,它们会关闭窗口。此外,如果一个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),可以帮助它显示子窗口
  •   
  • 它声明了一个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,在卸载代理时关闭Windows
  •   
  • 如前所述,在代理被销毁之前关闭的Windows(可能是用户单击关闭按钮)导致基础集合中的相关数据项被删除(除非RemoveDataItemWhenWindowClosed属性已设置为false)。反过来,这将导致代理从可视树中移除。换句话说,如果我关闭窗口小部件窗口,将从我的窗口小部件视图模型集合中删除相应的WidgetViewModel。然后,ItemsControl将从可视树中删除相关的代理容器。