XAML WPF中调整弹出控件大小的方向及其内容

11dmarpk  于 2023-09-28  发布在  其他
关注(0)|答案(1)|浏览(143)

在我的解决方案中,我有一个自定义弹出控件,根据个人要求设置,当我将应用程序移动到屏幕右侧,然后定义自定义宽度(这很好)时,我唯一的问题发生了,但我的内容在左侧调整了大小,我的CustomPopupPlacementCallback不起作用(附加剪辑)。最后,为了确认,我希望我的内容从弹出窗口的右侧调整大小,而不将弹出窗口移动到它附近定义的网格上。有什么建议可以解释一下吗?
我的弹出窗口有一个边框,里面有一个堆栈面板,我有一些texblocks控件,就是这样。

<Popup>
<Border BorderThickness="0" Background="{DynamicResource RegularButtonBrush}" Padding="3,15,0,0" FlowDirection="LeftToRight">
  <StackPanel x:Name="popupSideMenuLabels" Orientation="Vertical" CanHorizontallyScroll="False" FlowDirection="LeftToRight">

    <TextBlock x:Name="tblogbook" Text="Loogout"/>
    <TextBlock x:Name="tblogbook" Text="Manage"/>
    <TextBlock x:Name="tblogbook" Text="Logbook"/>
    <TextBlock x:Name="tblogbook" Text="Notifications"/>
    <TextBlock x:Name="tblogbook" Text="Cell Settings"/>
    <TextBlock x:Name="tblogbook" Text="Reports"/>

  </StackPanel>
</Border>
</Popup>

为了确认,我的文本块连同弹出控件被显示为在视频剪辑,但我想两个推卸弹出窗口的右侧,如果默认宽度大于新定义(空间之间的父控件网格和屏幕的右端铰)字面意思是有“日志”或“马”或“管理”,例如“否”,而不是“通知”等“洛”。
更新-代码

var taskBarHeight = SystemParameters.PrimaryScreenHeight - SystemParameters.WorkArea.Height;
        var screenHeight = SystemParameters.PrimaryScreenHeight - taskBarHeight;
        var screenWidht = SystemParameters.PrimaryScreenWidth - 40; //40 pixels is width of parent
        var gridPoint = sideMenuGrid.PointFromScreen(new Point(0, 0));
        
        var gridSizeHeight = gridPoint.Y < 0
                                        ? screenHeight - (-gridPoint.Y)
                                        : screenHeight - gridPoint.Y;
        var gridSizeWidth = gridPoint.X < 0
                                    ? screenWidht - (-gridPoint.X)
                                    : screenWidht - gridPoint.X;
        mypopup.Height = gridSizeHeight;
    
    if (DefaultSideMenuWidth - gridSizeWidth < 0) // Not at the edge of the screen
        sideMenuGrid.FindVisualChild<NonTopmostPopup>("PART_Popup").Width = DEFAULT_SIDE_MENU_WIDTH;
    else // At the edge of the screen
    {                    
        sideMenuGrid.FindVisualChild<NonTopmostPopup>("PART_Popup").Width = gridSizeWidth;
    }

通过这段代码,如果应用程序位于任务栏下方,我将获得垂直高度。宽度也是如此,我实现了宽度,但它不是从右边收缩,因为我希望它收缩。

更新(右侧):
所以,如果我把我的应用程序移到右边,例如我的侧菜单父(这是一个网格)被显示一半的大小,同样的事情发生在我的弹出窗口有一个完整的大小,当涉及到高度,但仍然是应用程序的左侧被吞噬的某种原因。

rggaifut

rggaifut1#

您可以创建一个自定义控件,如WinUI 3中的SplitView,而不是自己计算所有内容。

泛型.xaml

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:WpfSplitViewExample">

    <Style TargetType="{x:Type local:SplitView}">
        <Setter Property="OpenPaneLength" Value="200" />
        <Setter Property="CompactPaneLength" Value="30" />
        <Setter Property="PaneBackground" Value="LightGray" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type local:SplitView}">
                    <Border
                        Background="{TemplateBinding Background}"
                        BorderBrush="{TemplateBinding BorderBrush}"
                        BorderThickness="{TemplateBinding BorderThickness}">
                        <Grid>
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition
                                    x:Name="PaneColumn"
                                    Width="Auto" />
                                <ColumnDefinition Width="Auto" />
                                <ColumnDefinition Width="*" />
                            </Grid.ColumnDefinitions>
                            <Grid Grid.Column="0">
                                <Border
                                    x:Name="PaneBorder"
                                    Background="{TemplateBinding PaneBackground}" />
                            </Grid>
                            <GridSplitter Grid.Column="1" />
                            <Grid Grid.Column="2">
                                <Border x:Name="ContentBorder" />
                            </Grid>
                        </Grid>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

</ResourceDictionary>

SplitView.cs

using System.Windows;
using System.Windows.Controls;
using System.Windows.Markup;
using System.Windows.Media;

namespace WpfSplitViewExample;

[ContentProperty(nameof(Content))]
public class SplitView : Control
{
    public static readonly DependencyProperty IsPaneOpenProperty =
     DependencyProperty.Register(
         nameof(IsPaneOpen),
         typeof(bool),
         typeof(SplitView),
         new PropertyMetadata(false, (d, e) =>
         {
             if (d is SplitView splitView &&
                e.NewValue is bool isPaneOpen)
             {
                 if (isPaneOpen is true)
                 { 
                     splitView.OpenPane();
                 }
                 else
                 {
                     splitView.ClosePane();
                 }
             }
         }));

    public static readonly DependencyProperty OpenPaneLengthProperty =
        DependencyProperty.Register(
            nameof(OpenPaneLength),
            typeof(double),
            typeof(SplitView),
            new PropertyMetadata(0.0, (d, e) => (d as SplitView)?.UpdatePaneLength()));

    public static readonly DependencyProperty CompactPaneLengthProperty =
        DependencyProperty.Register(
            nameof(CompactPaneLength),
            typeof(double),
            typeof(SplitView),
            new PropertyMetadata(0.0, (d, e) => (d as SplitView)?.UpdatePaneLength()));

    public static readonly DependencyProperty PaneProperty =
        DependencyProperty.Register(
            nameof(Pane),
            typeof(UIElement),
            typeof(SplitView),
            new PropertyMetadata(default, (d, e) => (d as SplitView)?.UpdatePaneContent()));

    public static readonly DependencyProperty ContentProperty =
        DependencyProperty.Register(
            nameof(Content),
            typeof(UIElement),
            typeof(SplitView),
            new PropertyMetadata(default, (d, e) => (d as SplitView)?.UpdateContent()));

    public static readonly DependencyProperty PaneBackgroundProperty =
        DependencyProperty.Register(
            nameof(PaneBackground),
            typeof(Brush),
            typeof(SplitView),
            new PropertyMetadata(default));

    static SplitView()
    {
        DefaultStyleKeyProperty.OverrideMetadata(
            typeof(SplitView),
            new FrameworkPropertyMetadata(typeof(SplitView)));
    }

    public Brush PaneBackground
    {
        get => (Brush)GetValue(PaneBackgroundProperty);
        set => SetValue(PaneBackgroundProperty, value);
    }

    public UIElement Content
    {
        get => (UIElement)GetValue(ContentProperty);
        set => SetValue(ContentProperty, value);
    }

    public UIElement Pane
    {
        get => (UIElement)GetValue(PaneProperty);
        set => SetValue(PaneProperty, value);
    }

    public bool IsPaneOpen
    {
        get => (bool)GetValue(IsPaneOpenProperty);
        set => SetValue(IsPaneOpenProperty, value);
    }

    public double OpenPaneLength
    {
        get => (double)GetValue(OpenPaneLengthProperty);
        set => SetValue(OpenPaneLengthProperty, value);
    }

    public double CompactPaneLength
    {
        get => (double)GetValue(CompactPaneLengthProperty);
        set => SetValue(CompactPaneLengthProperty, value);
    }

    private ColumnDefinition? PaneColumn { get; set; }

    private Border? PaneBorder { get; set; }

    private Border? ContentBorder { get; set; }

    public event RoutedEventHandler? PaneOpened;

    public event RoutedEventHandler? PaneClosed;

    public override void OnApplyTemplate()
    {
        base.OnApplyTemplate();

        if (GetTemplateChild(nameof(PaneColumn)) is ColumnDefinition paneColumn)
        {
            PaneColumn = paneColumn;
        }

        if (GetTemplateChild(nameof(PaneBorder)) is Border paneBorder)
        {
            PaneBorder = paneBorder;
        }

        if (GetTemplateChild(nameof(ContentBorder)) is Border contentBorder)
        {
            ContentBorder = contentBorder;
        }

        UpdatePaneLength();
        UpdatePaneContent();
        UpdateContent();
    }

    private void OpenPane()
    {
        if (PaneColumn is not null)
        {
            PaneColumn.Width = new GridLength(OpenPaneLength);
            PaneOpened?.Invoke(this, new RoutedEventArgs());
        }
    }

    private void ClosePane()
    {
        if (PaneColumn is not null)
        {
            PaneColumn.Width = new GridLength(CompactPaneLength);
            PaneClosed?.Invoke(this, new RoutedEventArgs());
        }
    }

    private void UpdatePaneLength()
    {
        if (PaneColumn is not null)
        {
            PaneColumn.Width = IsPaneOpen is true
                ? new GridLength(OpenPaneLength)
                : new GridLength(CompactPaneLength);
        }
    }

    private void UpdatePaneContent()
    {
        if (PaneBorder is not null)
        {
            PaneBorder.Child = Pane;
        }
    }

    private void UpdateContent()
    {
        if (ContentBorder is not null)
        {
            ContentBorder.Child = Content;
        }
    }
}

然后像这样使用它:

<Window
    x:Class="WpfSplitViewExample.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:local="clr-namespace:WpfSplitViewExample"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    Title="MainWindow"
    Width="800"
    Height="450"
    Topmost="True"
    mc:Ignorable="d">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <ToggleButton
            x:Name="IsPaneOpenToggleButton"
            Grid.Row="0"
            Content="Is pane open" />
        <local:SplitView
            Grid.Row="1"
            IsPaneOpen="{Binding ElementName=IsPaneOpenToggleButton, Path=IsChecked}"
            PaneBackground="Yellow"
            PaneClosed="SplitView_PaneClosed"
            PaneOpened="SplitView_PaneOpened">
            <local:SplitView.Pane>
                <StackPanel>
                    <TextBlock Text="Logout" />
                    <TextBlock Text="Manage" />
                    <TextBlock Text="Logbook" />
                    <TextBlock Text="Notifications" />
                    <TextBlock Text="Cell Settings" />
                    <TextBlock Text="Reports" />
                </StackPanel>
            </local:SplitView.Pane>
            <TextBlock Text="Contents goes here." />
        </local:SplitView>
    </Grid>
</Window>

相关问题