1

Возник вопрос касательно возможности сделать связанные окна(не знаю,как это еще назвать),подразумевается,что изначально существует одно окно ,к примеру Window1,на котором расположена триггер формата On-Off или же кнопка.Необходимо ,чтобы по нажатию на триггер справа появлялось второе окно с независимой информацией(Window2),пусть там раз в 10 секунд выводит время,при этом при перемещении основного окна,второе двигалось вместе с ним.А по повторному нажатию триггера окно пропадало.Пробовал отслеживать позицию окна и менять его положение через и т.п.

Window1 window1Form = new Window1();
window1Form.Top=...;
window1Form.Left=...;

Возможно ли это как-то реализовать и в каком направлении стоит копать?Заранее спасибо за советы) Примерный вид

XupypG
  • 143
  • А почему это не сделать в рамках одного окна? Ведь не удобно, когда открывается не пойми где отдельное окно. – EvgeniyZ Jul 10 '20 at 15:47
  • @EvgeniyZ Из серии сделай кучу gridов и навешать свойств видимости? – XupypG Jul 10 '20 at 15:51
  • 1
    Ну это уже зависит от ваших навыков. Я бы разделил окно одной сеткой на две части, в левой поместил эти переключатели, а справа ContentPresenter, который менял бы свой вид под мои нужды, или если там несколько отображений, то ItemsControl. Привязал бы это дело по правилам MVVM и все, в одном окне у меня разное содержимое при выборе переключателей. – EvgeniyZ Jul 10 '20 at 15:55
  • @EvgeniyZ Благодарю,неплохой вариант.А так было чисто интересна реальность воплощения такой извращенной идеи)) – XupypG Jul 10 '20 at 16:06
  • Вы странно отзываетесь о вполне здравом совете. Я понимаю, что вы можете быть не знакомы с MVVM и не до конца понимать, что вам предложили, но заведомо утверждать, что основной для WPF подход к реализации подобных задач - извращение, это похоже на плевок в лицо практически каждому более-менее опытному в данном вопросе программисту. – aepot Jul 10 '20 at 17:10

1 Answers1

1

Если два "окна" должны двигаться вместе, то проще всего их сделать не отдельными окнами, а элементами управления на одном физическом окне.

  • Создаем полностью прозрачное родительское окно со свойствами WindowStyle="None" AllowsTransparency="True" Background="Transparent"
  • В нем создаем window1 и window2 допустим как Grid-ы
  • Воссоздаем в родительском окне нужный функционал обычного окна (перетаскивание за заголовок, изменение размера рамкой, кнопки сворачивания-разворачивания-закрытия)

В результате это выглядит как два окна, которые перемещаются вместе. Пример (у меня реализовано только перетаскивание за заголовок и кнопка закрытия):

<Window x:Class="WpfTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d" 
        WindowStyle="None" AllowsTransparency="True" Background="Transparent"
        Height="450" Width="600" Loaded="Window_Loaded">
&lt;Grid x:Name=&quot;grid&quot;&gt;

    &lt;Grid x:Name=&quot;window1&quot; HorizontalAlignment=&quot;Left&quot; Width=&quot;250&quot; Margin=&quot;0,0,0,0&quot; VerticalAlignment=&quot;Stretch&quot;  
              Background=&quot;AliceBlue&quot;&gt;
        &lt;Button x:Name=&quot;bClose&quot; Content=&quot;X&quot; HorizontalAlignment=&quot;Right&quot; Height=&quot;36&quot; VerticalAlignment=&quot;Top&quot; Width=&quot;36&quot; 
                Margin=&quot;0,0,0,0&quot; Click=&quot;Button_Click&quot; /&gt;
        &lt;Label x:Name=&quot;labelTitle&quot; Content=&quot;Window 1&quot; HorizontalAlignment=&quot;Stretch&quot; Height=&quot;36&quot; Margin=&quot;0,0,36,0&quot; 
                   VerticalAlignment=&quot;Top&quot; &gt;
            &lt;Label.Background&gt;
                &lt;SolidColorBrush Color=&quot;{DynamicResource {x:Static SystemColors.ActiveCaptionColorKey}}&quot;/&gt;
            &lt;/Label.Background&gt;
        &lt;/Label&gt;
        &lt;RadioButton Content=&quot;On&quot; HorizontalAlignment=&quot;Left&quot; Height=&quot;22&quot; Margin=&quot;25,60,0,0&quot; 
                         VerticalAlignment=&quot;Top&quot; Click=&quot;On_Click&quot;/&gt;
        &lt;RadioButton Content=&quot;Off&quot; HorizontalAlignment=&quot;Left&quot; Height=&quot;22&quot; Margin=&quot;70,60,0,0&quot; 
                         VerticalAlignment=&quot;Top&quot; IsChecked=&quot;True&quot; Click=&quot;Off_Click&quot;/&gt;
    &lt;/Grid&gt;
    &lt;Grid x:Name=&quot;window2&quot; HorizontalAlignment=&quot;Left&quot; Height=&quot;200&quot; Margin=&quot;251,0,0,0&quot; VerticalAlignment=&quot;Top&quot; Width=&quot;250&quot; 
              Background=&quot;AliceBlue&quot; &gt;
            &lt;Label Content=&quot;Window 2&quot; HorizontalAlignment=&quot;Left&quot; Height=&quot;27&quot; Margin=&quot;0,0,0,0&quot; 
                   VerticalAlignment=&quot;Top&quot; Width=&quot;120&quot;/&gt;
        &lt;/Grid&gt;
    &lt;/Grid&gt;    

</Window>


using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Interop;
using System.Runtime.InteropServices;
using System.Windows.Media;

namespace WpfTest { public partial class MainWindow : Window { [DllImport("user32.dll", SetLastError = true)] static extern bool GetWindowRect(IntPtr hwnd, out RECT lpRect);

    const uint HTCAPTION = 2;        
    const uint HTNOWHERE = 0;        

    const uint WM_NCHITTEST = 0x0084;

    const uint WS_OVERLAPPED = 0x00000000;
    const uint WS_CAPTION = 0x00C00000;
    const uint WS_SYSMENU = 0x00080000;
    const uint WS_THICKFRAME = 0x00040000;
    const uint WS_MINIMIZEBOX = 0x00020000;
    const uint WS_MAXIMIZEBOX = 0x00010000;
    const uint WS_OVERLAPPEDWINDOW = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU |
          WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX;

    static int GET_X_LPARAM(IntPtr lp)
    {
        short loword = (short)((ulong)lp &amp; 0xffff);
        return loword;
    }

    static int GET_Y_LPARAM(IntPtr lp)
    {
        short hiword = (short)((((ulong)lp) &gt;&gt; 16) &amp; 0xffff);
        return hiword;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct RECT
    {
        public int left, top, right, bottom;
    }

    //обработка координат мыши для неклиентской области
    IntPtr HitTestNCA(IntPtr hWnd, IntPtr wParam, IntPtr lParam)
    {
        Point ptMouse = new Point(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));                        
        RECT rcWindow;
        GetWindowRect(hWnd, out rcWindow);

        if (ptMouse.Y &gt;= rcWindow.top &amp;&amp; ptMouse.Y &lt; rcWindow.top + labelTitle.ActualHeight &amp;&amp;
            ptMouse.X&gt;= rcWindow.left &amp;&amp; ptMouse.X &lt; rcWindow.left + labelTitle.ActualWidth)
        {
            return (IntPtr)HTCAPTION;
        }
        else
        {
            return (IntPtr)HTNOWHERE;
        }
    }

    //обработчик сообщений для окна
    private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
    {
        IntPtr lRet = IntPtr.Zero;

        if (msg == WM_NCHITTEST)
        {
            //обработка нажатий мыши
            lRet = HitTestNCA(hwnd, wParam, lParam);

            if (lRet != (IntPtr)HTNOWHERE)
            {
                handled = true;
            }
        }

        return lRet;
    }

    public MainWindow()
    {

    }

    private void Window_Loaded(object sender, RoutedEventArgs e)
    {
        WindowInteropHelper h = new WindowInteropHelper(this);
        HwndSource source = HwndSource.FromHwnd(h.Handle);
        source.AddHook(new HwndSourceHook(WndProc));//регистрируем обработчик сообщений
        window2.Visibility = Visibility.Hidden;
    }

    private void Off_Click(object sender, RoutedEventArgs e)
    {
        window2.Visibility = Visibility.Hidden;
    }

    private void On_Click(object sender, RoutedEventArgs e)
    {
        window2.Visibility = Visibility.Visible;
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        this.Close();
    }
}

}

screenshot