源项目地址:https://github.com/Microsoft/...
以下是把样例转换为简要说明,同时给出实际运行效果及关键代码:

自定义窗口

通过Thumb控件移动无窗口工作区的可控大小,及可拖动窗体。
clipboard.png

private void Window_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
    DragMove();
}

private void ResizeThumb_DragDelta(object sender, DragDeltaEventArgs e)
{
    // Resize window width (honoring minimum width)
    var desiredWidth = (int) (ActualWidth + e.HorizontalChange);
    var minWidth = (int) (MinWidth + resizeThumb.Width + resizeThumb.Margin.Right);
    Width = Math.Max(desiredWidth, minWidth);

    // Resize window height (honoring minimum height)
    var desiredHeight = (int) (ActualHeight + e.VerticalChange);
    var minHeight = (int) (MinHeight + resizeThumb.Height + resizeThumb.Margin.Bottom);
    Height = Math.Max(desiredHeight, minHeight);
}

模拟系统txt软件的一系列功能。

clipboard.png
查找关键代码:

private void findNextButton_Click(object sender, RoutedEventArgs e)
{
    // Find matches
    if (_matches == null)
    {
        var pattern = findWhatTextBox.Text;

        // Match whole word?
        if ((bool) matchWholeWordCheckBox.IsChecked) pattern = @"(?<=\W{0,1})" + pattern + @"(?=\W)";

        // Case sensitive
        if (!(bool) caseSensitiveCheckBox.IsChecked) pattern = "(?i)" + pattern;

        // Find matches
        _matches = Regex.Matches(_textBoxToSearch.Text, pattern);
        _matchIndex = 0;

        // Word not found?
        if (_matches.Count == 0)
        {
            MessageBox.Show("'" + findWhatTextBox.Text + "' not found.", "Find");
            _matches = null;
            return;
        }
    }

    // Start at beginning of matches if the last find selected the last match
    if (_matchIndex == _matches.Count)
    {
        var result = MessageBox.Show("Nmore matches found. Start at beginning?", "Find",
            MessageBoxButton.YesNo);
        if (result == MessageBoxResult.No) return;

        // Reset
        _matchIndex = 0;
    }

    // Return match details to client so it can select the text
    var match = _matches[_matchIndex];
    if (TextFound != null)
    {
        // Text found
        Index = match.Index;
        Length = match.Length;
        OnTextFound();
    }
    _matchIndex++;
}

public event TextFoundEventHandler TextFound;//定义事件

protected virtual void OnTextFound()
{
var textFound = TextFound;
textFound?.Invoke(this, EventArgs.Empty);
}

//主界面调用
private void editFindMenuItem_Click(object sender, RoutedEventArgs e)
{
// Instantiate the dialog box
var dlg = new FindDialogBox(documentTextBox) {Owner = this};

// Configure the dialog box
dlg.TextFound += dlg_TextFound;

// Open the dialog box modally
dlg.Show();
}

private void dlg_TextFound(object sender, EventArgs e)
{
// Get the find dialog box that raised the event
var dlg = (FindDialogBox) sender;

// Get find results and select found text
documentTextBox.Select(dlg.Index, dlg.Length);
documentTextBox.Focus();
}

显示消息框的各种样式及参数

clipboard.png
关键代码:

// Show message box, passing the window owner if specified
MessageBoxResult result;
if (owner == null)
{
    result = System.Windows.MessageBox.Show(messageBoxText, caption, button, icon, defaultResult, options);
}
else
{
    result = System.Windows.MessageBox.Show(owner, messageBoxText, caption, button, icon, defaultResult,
        options);
}
ps:一个小bug,当owner为this/null时,options使用DefaultDesktopOnly与ServiceNotification参数时,显示 报错/移动窗口残影,建议过滤掉这两个参数。

无边框窗口

代码见图片内
clipboard.png

托盘区通知显示

clipboard.png

private void Click(object sender, RoutedEventArgs e)
{
    // Configure and show a notification icon in the system tray
    _notifyIcon = new NotifyIcon
    {
        BalloonTipText = @"Hello, NotifyIcon!",
        Text = @"Hello, NotifyIcon!",
        Icon = new Icon("NotifyIcon.ico"),
        Visible = true
    };
    _notifyIcon.ShowBalloonTip(1000);
}

保存窗口位置,当在此启动程序时,还原上次关闭时位置

ps:调用GetWindowPlacement/SetWindowPlacement

protected override void OnSourceInitialized(EventArgs e)
{
    base.OnSourceInitialized(e);
    try
    {
        // Load window placement details for previous application session from application settings
        // Note - if window was closed on a monitor that is now disconnected from the computer,
        //        SetWindowPlacement will place the window onto a visible monitor.
        var wp = Settings.Default.WindowPlacement;
        wp.length = Marshal.SizeOf(typeof (WindowPlacement));
        wp.flags = 0;
        wp.showCmd = (wp.showCmd == SwShowminimized ? SwShownormal : wp.showCmd);
        var hwnd = new WindowInteropHelper(this).Handle;
        SetWindowPlacement(hwnd, ref wp);
    }
    catch
    {
        // ignored
    }
}

// WARNING - Not fired when Application.SessionEnding is fired
protected override void OnClosing(CancelEventArgs e)
{
    base.OnClosing(e);

    // Persist window placement details to application settings
    WindowPlacement wp;
    var hwnd = new WindowInteropHelper(this).Handle;
    GetWindowPlacement(hwnd, out wp);
    Settings.Default.WindowPlacement = wp;
    Settings.Default.Save();
}

#region Win32 API declarations to set and get window placement

[DllImport("user32.dll")]
private static extern bool SetWindowPlacement(IntPtr hWnd, [In] ref WindowPlacement lpwndpl);

[DllImport("user32.dll")]
private static extern bool GetWindowPlacement(IntPtr hWnd, out WindowPlacement lpwndpl);

private const int SwShownormal = 1;
private const int SwShowminimized = 2;

#endregion
}

ShowWindowWithoutActivation

打开模式/非模式窗口是是否激活,是否引发其 Activated 事件

private void ShowWindowActivateButton_Click(object sender, RoutedEventArgs e)
{
    var tw = new ChildWindow();
    // tw.ShowActivated = true; // true is the default value
    tw.Show();
}

private void ShowWindowNoActivateButton_Click(object sender, RoutedEventArgs e)
{
    var tw = new ChildWindow {ShowActivated = false};
    tw.Show();
}

窗口关闭时检查是否关闭活动

clipboard.png

WindowHiding关闭窗口时隐藏窗口,以保存之前记录,再次显示时触发IsVisibleChanged

private void Window_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
{
    // Get date/time the window is shown now (ie when it becomes visible)
    if ((bool) e.NewValue)
    {
        shownThisTimeTextBlock.Text = DateTime.Now.ToString(CultureInfo.InvariantCulture);
    }
}

private void Window_Closing(object sender, CancelEventArgs e)
{
    // If Close() was called, close the window (instead of hiding it)
    if (_close) return;

    // Hide the window (instead of closing it)
    e.Cancel = true;
    Hide();
}

动态设置窗口属性

clipboard.png

Wizard导航窗口及返回值

clipboard.pngclipboard.png

1 主函数判断导航窗口返回值及接收数据显示结果,

private void RunWizardButton_Click(object sender, RoutedEventArgs e)
{
    var wizard = new WizardDialogBox();
    var showDialog = wizard.ShowDialog();
    var dialogResult = showDialog != null && (bool) showDialog;
    MessageBox.Show(
        dialogResult
            ? $"{wizard.WizardData.DataItem1}\n{wizard.WizardData.DataItem2}\n{wizard.WizardData.DataItem3}"
            : "Canceled.");
}

2 DialogBox加载wizardLauncher向导启动器导航窗口、数据、委托事件、返回函数等

public class WizardDialogBox : NavigationWindow
{
    public WizardDialogBox()
    {
        InitializeComponent();

        // Launch the wizard
        var wizardLauncher = new WizardLauncher();
        wizardLauncher.WizardReturn += wizardLauncher_WizardReturn;
        Navigate(wizardLauncher);
    }

    public WizardData WizardData { get; private set; }

    private void wizardLauncher_WizardReturn(object sender, WizardReturnEventArgs e)
    {
        // Handle wizard return
        WizardData = e.Data as WizardData;
        if (DialogResult == null)
        {
            DialogResult = (e.Result == WizardResult.Finished);
        }
    }
}

3 启动器代码

public class WizardLauncher : PageFunction<WizardResult>
{
    private readonly WizardData _wizardData = new WizardData();
    public event WizardReturnEventHandler WizardReturn;

    protected override void Start()
    {
        base.Start();

        // So we remember the WizardCompleted event registration
        KeepAlive = true;

        // Launch the wizard
        var wizardPage1 = new WizardPage1(_wizardData);
        wizardPage1.Return += wizardPage_Return;
        NavigationService?.Navigate(wizardPage1);
    }

    public void wizardPage_Return(object sender, ReturnEventArgs<WizardResult> e)
    {
        // Notify client that wizard has completed
        // NOTE: We need this custom event because the Return event cannot be
        // registered by window code - if WizardDialogBox registers an event handler with
        // the WizardLauncher's Return event, the event is not raised.
        WizardReturn?.Invoke(this, new WizardReturnEventArgs(e.Result, _wizardData));
        OnReturn(null);
    }
}

4 Page1代码,绑定、下一页、取消、返回事件功能

public partial class WizardPage1 : PageFunction<WizardResult>
{
    public WizardPage1(WizardData wizardData)
    {
        InitializeComponent();

        // Bind wizard state to UI
        DataContext = wizardData;
    }

    private void nextButton_Click(object sender, RoutedEventArgs e)
    {
        // Go to next wizard page
        var wizardPage2 = new WizardPage2((WizardData) DataContext);
        wizardPage2.Return += wizardPage_Return;
        NavigationService?.Navigate(wizardPage2);
    }

    private void cancelButton_Click(object sender, RoutedEventArgs e)
    {
        // Cancel the wizard and don't return any data
        OnReturn(new ReturnEventArgs<WizardResult>(WizardResult.Canceled));
    }

    public void wizardPage_Return(object sender, ReturnEventArgs<WizardResult> e)
    {
        // If returning, wizard was completed (finished or canceled),
        // so continue returning to calling page
        OnReturn(e);
    }
}

李志玮
22 声望34 粉丝

求索~~