3

当使用WindowChrome可在此处下载)自定义窗口的非客户区时,一个自然的起点是制作一个看起来和行为与标准标题栏相同的标题栏。这需要添加“假”应用程序图标和标题栏,因为显然 WindowChrome 禁用了这些功能(最小化、最大化和关闭按钮仍然有效。)

这是我到目前为止所拥有的:

<Window x:Class="MyApp.MainWindow"
        x:Name="MainWindowItself"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:shell="clr-namespace:Microsoft.Windows.Shell;assembly=Microsoft.Windows.Shell"
        xmlns:local="clr-namespace:MyApp"
        Title="My Application" Icon="App.ico" Height="350" Width="525">
    <Window.Resources>
        <Style TargetType="{x:Type local:MainWindow}">
            <Setter Property="shell:WindowChrome.WindowChrome">
                <Setter.Value>
                    <shell:WindowChrome />
                </Setter.Value>
            </Setter>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type local:MainWindow}">
                        <Grid>
                            <Border Background="White" Margin="{Binding Source={x:Static shell:SystemParameters2.Current}, Path=WindowNonClientFrameThickness}">
                                <ContentPresenter Content="{TemplateBinding Content}" />
                            </Border>
                            <TextBlock Text="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Title}" 
                               VerticalAlignment="Top" HorizontalAlignment="Left" 
                               Margin="32,8,0,0"/>
                            <Image x:Name="SystemMenuIcon" Source="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Icon}"
                               VerticalAlignment="Top" HorizontalAlignment="Left"
                               Margin="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(shell:WindowChrome.WindowChrome).ResizeBorderThickness}" 
                               Width="{Binding Source={x:Static shell:SystemParameters2.Current}, Path=SmallIconSize.Width}"
                               shell:WindowChrome.IsHitTestVisibleInChrome="True" MouseDown="SystemMenuIcon_MouseDown">
                            </Image>
                        </Grid>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </Window.Resources>
    <Grid>
        <TextBlock Text="Client area content goes here"/>
    </Grid>
</Window>

后面的代码:

private void SystemMenuIcon_MouseDown(object sender, MouseButtonEventArgs e)
{
    var offs = SystemParameters2.Current.WindowNonClientFrameThickness;
    SystemCommands.ShowSystemMenu(this, new Point(Left + offs.Left, Top + offs.Top));
}

这非常接近工作。第一个问题是,在您单击应用程序图标并出现系统菜单后,如果您再次单击,菜单应该会消失——相反,菜单只是重新绘制。此外,如果您双击,则窗口应该关闭,但 Image 没有双击事件。您如何建议添加这些功能?

4

2 回答 2

3

CaptionHeight="0"要禁用标准 Chrome 按钮只需在您的 XAML 代码中添加一个额外的属性shell:WindowsChrome

所以会是这样

<Setter Property="shell:WindowChrome.WindowChrome">
    <Setter.Value>
        <shell:WindowChrome CaptionHeight="0" />
    </Setter.Value>
</Setter>

制作一个假 Chrome。修改模板如下:

<ControlTemplate TargetType="Window">
    <AdornerDecorator>
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="35" />
                <RowDefinition Height="*" />                
            </Grid.RowDefinitions>
            <Grid x:Name="PART_Chrome" shell:WindowChrome.IsHitTestVisibleInChrome="True">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="50" />
                    <ColumnDefinition Width="*" />
                    <ColumnDefinition Width="105" />
                </Grid.ColumnDefinitions>

                <Image Source="Application Favicon Path" />

                <TextBlock Grid.Column="1" Text="{TemplateBinding Title}" VerticalAlignment="Center" />

                <StackPanel Orientation="Horizontal" Grid.Column="3" >
                    <Button Command="{Binding Source={x:Static shell:SystemCommands.MinimizeWindowCommand}}" >
                        <Path Data="M0,6 L8,6 Z" Width="8" Height="7" VerticalAlignment="Center" HorizontalAlignment="Center"
                              Stroke="{Binding Foreground, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Button}}" StrokeThickness="2"  />
                    </Button>
                    <Button x:Name="MaximizeButton" Command="{Binding Source={x:Static shell:SystemCommands.MaximizeWindowCommand}}" >
                        <Path Data="M0,1 L9,1 L9,8 L0,8 Z" Width="9" Height="8" VerticalAlignment="Center" HorizontalAlignment="Center"
                              Stroke="{Binding Foreground, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Button}}" StrokeThickness="2"  />
                    </Button>
                    <Button x:Name="RestoreButton" Command="{Binding Source={x:Static shell:SystemCommands.RestoreWindowCommand}}" >
                        <Path Data="M2,0 L8,0 L8,6 M0,3 L6,3 M0,2 L6,2 L6,8 L0,8 Z" Width="8" Height="8" VerticalAlignment="Center" HorizontalAlignment="Center"
                              Stroke="{Binding Foreground, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Button}}" StrokeThickness="1"  />
                    </Button>
                    <Button Command="{Binding Source={x:Static shell:SystemCommands.CloseWindowCommand}}" >
                        <Path Data="M0,0 L8,7 M8,0 L0,7 Z" Width="8" Height="7" VerticalAlignment="Center" HorizontalAlignment="Center"
                              Stroke="{Binding Foreground, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Button}}" StrokeThickness="1.5"  />
                    </Button>
                </StackPanel>
            </Grid>
            <ContentPresenter Grid.Row="1" Content="{TemplateBinding Content}" />
        </Grid>
    </AdornerDecorator>
    <ControlTemplate.Triggers>
        <Trigger Property="WindowState" Value="Normal">            
            <Setter Property="Visibility" Value="Collapsed" TargetName="RestoreButton" />
            <Setter Property="Visibility" Value="Visible" TargetName="MaximizeButton" />
        </Trigger>
        <Trigger Property="WindowState" Value="Maximized">
            <Setter Property="Visibility" Value="Visible" TargetName="RestoreButton" />
            <Setter Property="Visibility" Value="Collapsed" TargetName="MaximizeButton" />
        </Trigger>
    </ControlTemplate.Triggers>
</ControlTemplate>

还为 Fake Chrome bar 的正常工作进行命令绑定

public MainWindow()
{
    this.CommandBindings.Add(new CommandBinding(SystemCommands.CloseWindowCommand, OnCloseWindow));
    this.CommandBindings.Add(new CommandBinding(SystemCommands.MaximizeWindowCommand, OnMaximizeWindow, OnCanResizeWindow));
    this.CommandBindings.Add(new CommandBinding(SystemCommands.MinimizeWindowCommand, OnMinimizeWindow, OnCanMinimizeWindow));
    this.CommandBindings.Add(new CommandBinding(SystemCommands.RestoreWindowCommand, OnRestoreWindow, OnCanResizeWindow));

}

private void OnCanMinimizeWindow(object sender, CanExecuteRoutedEventArgs e)
{
    e.CanExecute = this.ResizeMode != ResizeMode.NoResize;
}

private void OnCanResizeWindow(object sender, CanExecuteRoutedEventArgs e)
{
    e.CanExecute = this.ResizeMode == ResizeMode.CanResize || this.ResizeMode == ResizeMode.CanResizeWithGrip;
}

private void OnCloseWindow(object sender, ExecutedRoutedEventArgs e)
{
    Microsoft.Windows.Shell.SystemCommands.CloseWindow(this);
}

private void OnMaximizeWindow(object sender, ExecutedRoutedEventArgs e)
{
    Microsoft.Windows.Shell.SystemCommands.MaximizeWindow(this);
}

private void OnMinimizeWindow(object sender, ExecutedRoutedEventArgs e)
{
    Microsoft.Windows.Shell.SystemCommands.MinimizeWindow(this);
}

private void OnRestoreWindow(object sender, ExecutedRoutedEventArgs e)
{
    Microsoft.Windows.Shell.SystemCommands.RestoreWindow(this);
}
于 2014-01-28T13:54:02.260 回答
1

我的 xaml 并不完全相同(我不使用 WindowChrome,而是我自己的,并且我有一个标题栏模板),但是我遇到了完全相同的问题,并且该解决方案也应该对您有用。

首先是简单的:为了使双击工作只需使用 ClickCount。

然后,让菜单消失需要保持一些状态来判断它当前是否处于活动状态:诀窍是在第二次点击时会触发不同的事件(如使用Snoop计算出来的那样。第一次点击只是 MousweDown,第二次是MouseDown 后跟 MouseUp(我的猜测是第一次单击的向上由系统菜单处理)。

private bool inSysMenu = false;

void SystemMenuIcon_MouseDown( object sender, MouseButtonEventArgs e )
{
  if( e.ClickCount == 1 && !inSysMenu )
  {
    inSysMenu = true;
    ShowSystemMenu(); //replace with your code
  }
  else if( e.ClickCount == 2 && e.ChangedButton == MouseButton.Left )
  {
    window.Close();
  }
}

void SystemMenuIcon_MouseLeave( object sender, MouseButtonEventArgs e )
{
  inSysMenu = false;
}

void SystemMenuIcon_MouseUp( object sender, MouseButtonEventArgs e )
{
  inSysMenu = false;
}
于 2011-11-11T09:50:34.753 回答