@nice3point @jeremy_tammik
I cannot share the actual code, unfortunately. Our codebase is really massive and closed ;-).
While I cannot find the time to provide a full working example, I can post some code for you to fill the gaps. The important snippet (to be called after previewControl.Loaded AND previewControll.IsVisibleChanged) is the following:
// get preview window host
var previewWndHost = previewControl.Content;
if (previewWndHost is null)
return;
// get preview view handle
var previewHwnd = (IntPtr)previewWndHost.GetType().GetProperty("Handle").GetValue(previewWndHost, null);
if (previewHwnd == IntPtr.Zero)
return;
// remove WS_EX_CLIENTEDGE on all child windows
foreach (var hwnd in HwndHelpers.GetAllChildHandles(previewHwnd).Append(previewHwnd))
{
var style = User32.GetWindowLong(hwnd, Constants.GWL_EXSTYLE).ToInt32() & ~(int)Constants.WS_EX_CLIENTEDGE;
User32.SetWindowLong(hwnd, Constants.GWL_EXSTYLE, style);
}
// trigger redraw by adding or removing a slight padding at the bottom
// the original padding is stored in the tag, so try to avoid using the
// tag property for anything else if you want this to work.
var p = previewControl.Padding;
if (previewControl.Tag is null)
previewControl.Tag = p;
if (previewControl.Tag is System.Windows.Thickness t)
{
p.Bottom = p.Bottom == t.Bottom ? p.Bottom + 1 : t.Bottom;
previewControl.Padding = p;
}
The IsVisibleChanged handler is required for use in tab controls, since Revit seems to re-create the view in case of visibility changes. I misused the tag to save the previous state and avoid shrinking/growing of the control due to the padding-changes at "reentry". If you find a better solution to trigger the redraw, please let me know. This part is pretty hacky, but I had to move on at some point and got stuck with whatever did the job.
I also use some WinAPI functions which can be easily imported (google, pinvoke). The HwndHelpers function is just syntactic sugar around EnumChildWindows.
public static IList<IntPtr> GetAllChildHandles(IntPtr hwnd)
{
var childHandles = new List<IntPtr>();
var gcChildHandles = GCHandle.Alloc(childHandles);
try
{
bool EnumWindow(IntPtr hWnd, IntPtr lParam)
{
(GCHandle.FromIntPtr(lParam).Target as List<IntPtr>)?.Add(hWnd);
return true;
}
var childProc = new User32.EnumWindowsProc(EnumWindow);
User32.EnumChildWindows(hwnd, childProc, GCHandle.ToIntPtr(gcChildHandles));
}
finally
{
gcChildHandles.Free();
}
return childHandles;
}