关于WPF使用ToolSettingsHost控件附加到MicroStation ToolSetings之后显示器高分辨率缩放显示问题及解决方案

先添加一个用户控件

打开 UserControl1.xaml 文件  把控件类型 UserControl 改为 : ToolSettingsHost

添加一个按钮 作为内容显示 

<wpf:ToolSettingsHost x:Class="TestAddin.UserControl1"
                  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                  xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
                  xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
                  xmlns:wpf="clr-namespace:Bentley.MstnPlatformNET.WPF;assembly=Bentley.MicroStation.WPF"
                  mc:Ignorable="d" 
                  Width="300" Height="150">
    <Grid>
            <Button Content="点击" VerticalAlignment="Center" Padding="10,5,10,5"></Button>
    </Grid>
</wpf:ToolSettingsHost>

打开  UserControl1.xaml.cs  把UserControl1 的继承类 UserControl 也改为: ToolSettingsHost

using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Bentley.MstnPlatformNET.WPF;

namespace TestAddin
{
    /// <summary>
    /// UserControl1.xaml 的交互逻辑
    /// </summary>
    public partial class UserControl1 : ToolSettingsHost
    {
        public UserControl1()
        {
            InitializeComponent();
        }
    }
}

创建控件实列   

UserControl1 userControl1=new UserControl1();
userControl1.Attach(addin);

使用ToolSettingsHost 附加到 MicroStation  之后效果为  

因为我的显示器分辨率缩放值为125%,1.25倍窗口(MSWindow)进行缩放,  所以实际窗口的大小为原有控件的宽高除以1.25倍;

导致控件内容(ElementHost)大小(宽,高)大于窗口(MSWindow)大小(宽,高),所以显示内容不全; 那么只要修正ElementHost 大小跟窗口大小为一致就行了;

解决方案:

修改 UserControl1.xaml.cs 内容 为:

/// <summary>
    /// UserControl1.xaml 的交互逻辑
    /// </summary>
    public partial class UserControl1 : ToolSettingsHost
    {
        public UserControl1()
        {
            InitializeComponent();
        }

        [DllImport("stdmdlbltin.dll", SetLastError = true)]
        public static extern int mdlNativeWindow_getToolSettingsWindow(out IntPtr windowPp);


        [DllImport("nativewindow.dll", SetLastError = true)]
        public static extern int mdlNativeWindow_setSize(IntPtr windowP, int width, int height);




        public override void Attach(IMatchLifetime addIn)
        {
            //   AdjustWidthAndHeight();

            base.Attach(addIn);

            //   ElementHost.Width = (int)RenderSize.Width;
            //  ElementHost.Height = (int)RenderSize.Height;
            ToolSettingsUtil.SetToolSettingsWindowSize(ElementHost.Width, ElementHost.Height);
        }



        /// <summary>
        /// 根据缩放比重新调整控件大小
        /// </summary>
        public new void AdjustWidthAndHeight()
        {
            double dipScale = GetDipScale();
            Width *= dipScale;
            Height *= dipScale;
        }


        /// <summary>
        /// 获取显示器缩放比
        /// </summary>
        /// <returns></returns>
        public double GetDipScale()
        {
            Graphics g = Graphics.FromHwnd(IntPtr.Zero);
            double dipScale = 1;
            switch (g.DpiX)
            {
                case 96: dipScale = 1; break;
                case 120: dipScale = 1.25; break;
                case 144: dipScale = 1.5; break;
                case 168: dipScale = 1.75; break;
                case 192: dipScale = 2; break;
            }

            return dipScale;

        }
    }

方法1:ElementHost 跟随窗口(MSWindow)保持统一  但是不考虑原控件缩放的问题 实际会跟设定大小不一样

public override void Attach(IMatchLifetime addIn)
{
    base.Attach(addIn);
    ElementHost.Width = (int)RenderSize.Width;
    ElementHost.Height = (int)RenderSize.Height;
}

方法2:ElementHost 跟随窗口(MSWindow)保持统一,考虑原控件大小 先乘以一个缩放比 Attach 之后会自动减去之前乘以的缩放比 结果会保持原控件大小 但是检测系统显示器缩放比的方法是否 绝对可靠 有待考证

public override void Attach(IMatchLifetime addIn)
{

    AdjustWidthAndHeight();
    base.Attach(addIn);
    ElementHost.Width = (int)RenderSize.Width;
    ElementHost.Height = (int)RenderSize.Height;
 
}

方法3:Attach之后 直接再次修改窗口(MSWindow) 的大小 保持原有大小 这里进行了 CLR函数封装

public override void Attach(IMatchLifetime addIn)
{
    base.Attach(addIn);
    ToolSettingsUtil.SetToolSettingsWindowSize(ElementHost.Width, ElementHost.Height);
 
}

// ClR 封装函数 
void  ToolSettingsUtil::SetToolSettingsWindowSize(int width,int height)
{
    MSWindow* MSWPtr;
    mdlNativeWindow_getToolSettingsWindow(&MSWPtr);
    mdlNativeWindow_setSize(MSWPtr,width,height);
}

方法4:同方法3,不需要封装 使用P/Invoke方式调用 但是声明 mdlNativeWindow_setSize() 编译报错,有会的希望指点一下

(由郭老师 指出问题所在 函数封装在 nativewindow.dll 中) 推荐使用此方法

 public override void Attach(IMatchLifetime addIn)
{
    base.Attach(addIn);
    mdlNativeWindow_getToolSettingsWindow(out IntPtr windowPp);
    mdlNativeWindow_setSize(windowPp, ElementHost.Width, ElementHost.Height);
}

最终效果图:

Parents Reply Children