C#WPF如何强制执行单个windows实例

bia*_*bit 11 c# wpf singleton window

我想知道在WPF中为每个应用程序提供给定Window的单个实例的最佳方法(阅读最优雅)是什么.

我是.NET和WPF的新手,我想出的东西看起来很蹩脚.

private static readonly Object MUTEX = new Object();
private static AboutWindow INSTANCE;

public static AboutWindow GetOrCreate() {
    lock (MUTEX) {
        if (INSTANCE == null) {
            INSTANCE = new AboutWindow();
        }
        INSTANCE.Show();
        return INSTANCE;
    }
}

private AboutWindow() {
    InitializeComponent();
}

private void AboutWindow_Closed(object sender, EventArgs e) {
    // the Closed events are handy for me to update values across
    // different windows.
    lock (MUTEX) {
        INSTANCE = null;
    }
}
Run Code Online (Sandbox Code Playgroud)

事情是......这看起来像完全废话.必须有一些方法以更优雅的方式实现同​​一目标,对吗?

PS:我经常使用该Closed事件来更改其他打开窗口中的值.例如,我有SettingsWindow和"帐户"按钮.当我按下该按钮时,弹出AccountWindow.当我关闭AcountWindow时,我想要在SettingsWindow中更改(标签).因此不断创建窗口.
此外,由于窗框上的X按钮,Close总是需要处理的...

Mua*_*Dib 15

有可能更好的方法来做到这一点,但这是一个相对简单的方法....在你的窗口类上放置一个静态bool来标记它是否打开.然后,在load()事件中将其设置为true,并在close事件上将其设置为false.然后,在打开窗口的代码中,检查标志.

这里有一些伪代码可以给你一个想法......

public class AboutWindow
{

    public static bool IsOpen {get;private set;}

    onLoadEvent(....) 
    {
        IsOpen = true;
    }

    onUnloadEvent(...) 
    {
        IsOpen = false;
    }

}


public void OpenAbout()
{
    if ( AboutWindow.IsOpen ) return;
    AboutWindow win = new AboutWindow();
    win.Show();

}
Run Code Online (Sandbox Code Playgroud)

  • 比这更好的整个单身与互斥的东西.是否可以为打开多个窗口留出一些空间,但在基于UI的应用程序中发生这种情况的可能性很小甚至没有 - 我是服务器老兄,不能停止考虑并发中所有最糟糕的情况:) (2认同)

Won*_*ane 7

如果你真的需要强制执行窗口的单个实例,那么使用工厂创建方法的静态实例(你所拥有的某些东西)当然是一个可行的选择,就像使用数据库时的单个DataContext实例一样.

您也可以编写自己的WindowManager类,虽然这看起来有点过分,但基本上是相同的(除了Factory方法将在单个类中).

然而,重新阅读你的帖子,我想知道这是否是一个错过森林树木的案例.你提到你的SettingsWindow,它反过来调用AccountWindow,让我觉得你应该只使用ShowDialog().这将以模态方式打开一个窗口,这意味着不能与调用窗口(或应用程序中的任何其他窗口)进行交互.您只需在该对话框中设置属性,在按下确定按钮时将DialogResult设置为true,并在父窗口中读取该属性.

基本上,你只需使用这样的ShowDialog.关于控件的绑定与硬编码,我省略了很多实现细节.这些细节并不像看到ShowDialog如何工作那么重要.

为简单起见,假设您有一个名为MyAppOptions的类,它反映了应用程序的选项.为简单起见,我将省略大部分实现细节,但它可能会实现INotifyPropertyChanged,具有方法,字段和属性等.

public class MyAppOptions
{
    public MyAppOptions()
    {
    }

    public Boolean MyBooleanOption
    {
        get;
        set;
    }

    public String MyStringOption
    {
        get;
        set;
    }
}
Run Code Online (Sandbox Code Playgroud)

然后,让我们简单一点,并假设您想在某个窗口上按下按钮时显示"选项"对话框.此外,我将假设已经使用您的选项设置了变量,这些变量在启动时加载.

void btnOptions_Click(object sender, RoutedEventArgs e)
{
    MyAppOptions options = new MyAppOptions();
    options.MyBooleanOption = mSomeBoolean;
    options.MyStringOption = mSomeString;

    OptionsDialog optionsDialog = new optionsDialog(options);
    if (optionsDialog.ShowDialog() == true)
    {
        // Assume this function saves the options to storage
        // and updates the application (binding) appropriately
        SetAndSaveOptions(optionsDialog.AppOptions);
    }
}
Run Code Online (Sandbox Code Playgroud)

现在假设OptionsDialog是你在项目中创建的一个窗口,它上面有一个与MyBooleanOption相关的CheckBox和一个用于MyStringOption的TextBox.它还有一个Ok按钮和Cancel按钮.代码隐藏可能会使用Binding,但是现在我们将对这些值进行硬编码.

public class OptionsDialog : Window
{
    public OptionsDialog(MyAppOptions options)
    {
        chkBooleanOption.IsChecked = options.SomeBooleanOption;
        txtStringOption.Text = options.SomeStringOption;
        btnOK.Click += new RoutedEventHandler(btnOK_Click);
        btnCancel.Click += new RoutedEventHandler(btnCancel_Click);
    }

    public MyAppOptions AppOptions
    {
        get;
        set;
    }

    void btnOK_Click(object sender, RoutedEventArgs e)
    {
        this.AppOptions.SomeBooleanOption = (Boolean) chkBooleanOption.IsChecked;
        this.AppOptions.SomeStringOption = txtStringOption.Text;

        // this is the key step - it will close the dialog and return 
        // true to ShowDialog
        this.DialogResult = true;
    }

    void btnClose_Click(object sender, RoutedEventArgs e)
    {
        // this will close the dialog and return false to ShowDialog
        // Note that pressing the X button will also return false to ShowDialog
        this.DialogResult = false;
    }
}
Run Code Online (Sandbox Code Playgroud)

就实现细节而言,这是一个非常基本的例子.在线搜索ShowDialog以获取更多详细信息.要记住的重要关键是:

  • ShowDialog以模态方式打开一个窗口,这意味着它是应用程序中唯一可以与之交互的窗口.
  • 将DialogResult设置为true将关闭对话框,可以从调用父对象中检查该对话框.
  • 将DialogResult设置为false也将关闭对话框,在这种情况下,您将跳过更新调用窗口中的值.
  • 按下窗口上的X按钮会自动将DialogResult设置为false
  • 您可以在对话框窗口中拥有可以在执行ShowDialog之前设置的公共属性,并且可以在对话框消失后从中获取值.当对话框仍在范围内时,它将可用.