Completed
Last Updated: 01 Aug 2024 11:01 by ADMIN
Release 2024.2.514 (2024 Q2)
Martin Ivanov
Created on: 15 Feb 2024 12:40
Category: TileList
Type: Bug Report
1
TileList: GroupTemplate content presenter's measuring behavior is changed which leads to layout changes in the elements in the template
The measuring logic of the groups in RadTileList was changed because of a new feature which brings issues with some layouts defined in the GroupTemplate. For example, if you have a TextBlock in the GroupTemplate, and set its HorizontalAlignment to Center, the TextBlock will be positioned around the center of the RadTileList control, instead of the group's center. Also, in this case the TextBlock disappears. 
5 comments
ADMIN
Martin Ivanov
Posted on: 01 Aug 2024 11:01

Hello Mark,

Thank you for the notice and for the extra information. 

Yes, you won't hit the same exception in the latest version, because the error occurs in a very specific implementation of the custom code provided as a workaround. As you saw, the fix of the original issue is just how the "columnsCount" value in the TileListPanel's code is accessed.

Regards,
Martin Ivanov
Progress Telerik

Love the Telerik and Kendo UI products and believe more people should try them? Invite a fellow developer to become a Progress customer and each of you can get a $50 Amazon gift voucher.

Mark
Posted on: 31 Jul 2024 16:07

Note that I was able to compare the source of your latest version to the previous, and it appears that the implemented fix is done very differently compared to the supplied patch code and thus is not likely to encounter this issue.

While it is possible that part of the fix was outside of the "TileListPanel.cs" file, I was not able to determine this.
If the issue that we encountered as a result of the manual patch cannot happen in the fixed version due to the difference in how it was addressed, please let me know so I can inform the "powers that be" over here to potentially get the new version in our release pipeline.

Thank you for your time.

Mark
Posted on: 31 Jul 2024 15:01

The sample project that you sent me on the originating ticket should be good enough as I modelled our changes based on that.  They are virtually identical.

I have not tried updating to version 2024.2.514.  It typically takes a significant amount of time for us to release updates for third-party controls, as we try not to do it very often to keep things stable and minimize changes for our clients.  It also takes a while to get it in and through our testing department.  I only posted this because it seems significant so I wanted to make you aware of it in case it could affect your implemented solution.

This is the Event Log of the error.  I just noticed that apparently it is occuring due to a size change.

Application: Seradex.AppBox.exe
Framework Version: v4.0.30319
Description: The process was terminated due to an unhandled exception.
Exception Info: System.InvalidOperationException
   at System.Linq.Enumerable.Min(System.Collections.Generic.IEnumerable`1<Double>)
   at Seradex.AppBox.TileListUtilities.GetEnclosingBounds(System.Collections.Generic.IEnumerable`1<System.Windows.FrameworkElement>, System.Windows.FrameworkElement)
   at Seradex.AppBox.TileListUtilities.UpdatePresenter(System.Windows.FrameworkElement)
   at Seradex.AppBox.TileListUtilities+<>c__DisplayClass3_0.<OnSyncWidthWithParentGroupChanged>b__0(System.Object, System.Windows.SizeChangedEventArgs)
   at System.Windows.SizeChangedEventArgs.InvokeEventHandler(System.Delegate, System.Object)
   at System.Windows.RoutedEventArgs.InvokeHandler(System.Delegate, System.Object)
   at System.Windows.RoutedEventHandlerInfo.InvokeHandler(System.Object, System.Windows.RoutedEventArgs)
   at System.Windows.EventRoute.InvokeHandlersImpl(System.Object, System.Windows.RoutedEventArgs, Boolean)
   at System.Windows.UIElement.RaiseEventImpl(System.Windows.DependencyObject, System.Windows.RoutedEventArgs)
   at System.Windows.UIElement.RaiseEvent(System.Windows.RoutedEventArgs)
   at System.Windows.FrameworkElement.OnRenderSizeChanged(System.Windows.SizeChangedInfo)
   at System.Windows.ContextLayoutManager.fireSizeChangedEvents()
   at System.Windows.ContextLayoutManager.UpdateLayout()
   at System.Windows.UIElement.UpdateLayout()
   at System.Windows.Interop.HwndSource.Process_WM_SIZE(System.Windows.UIElement, IntPtr, MS.Internal.Interop.WindowMessage, IntPtr, IntPtr)
   at System.Windows.Interop.HwndSource.LayoutFilterMessage(IntPtr, Int32, IntPtr, IntPtr, Boolean ByRef)
   at MS.Win32.HwndWrapper.WndProc(IntPtr, Int32, IntPtr, IntPtr, Boolean ByRef)
   at MS.Win32.HwndSubclass.DispatcherCallbackOperation(System.Object)
   at System.Windows.Threading.ExceptionWrapper.InternalRealCall(System.Delegate, System.Object, Int32)
   at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(System.Object, System.Delegate, System.Object, Int32, System.Delegate)
   at System.Windows.Threading.Dispatcher.LegacyInvokeImpl(System.Windows.Threading.DispatcherPriority, System.TimeSpan, System.Delegate, System.Object, Int32)
   at MS.Win32.HwndSubclass.SubclassWndProc(IntPtr, Int32, IntPtr, IntPtr)
   at MS.Win32.UnsafeNativeMethods.CallWindowProc(IntPtr, IntPtr, Int32, IntPtr, IntPtr)
   at MS.Win32.HwndSubclass.DefWndProcWrapper(IntPtr, Int32, IntPtr, IntPtr)
   at MS.Win32.UnsafeNativeMethods.CallWindowProc(IntPtr, IntPtr, Int32, IntPtr, IntPtr)
   at MS.Win32.HwndSubclass.SubclassWndProc(IntPtr, Int32, IntPtr, IntPtr

ADMIN
Martin Ivanov
Posted on: 31 Jul 2024 11:56

Hello Mark,

Can you send over the message and the full stacktrace of the InvalidOperationException? Also, it would be very helpful if you can send over a sample project reproducing the issue.

Additionally, this bug was fixed with the 2024.2.514 (2024 Q2) release, so you shouldn't need the custom code anymore.

Regards,
Martin Ivanov
Progress Telerik

Love the Telerik and Kendo UI products and believe more people should try them? Invite a fellow developer to become a Progress customer and each of you can get a $50 Amazon gift voucher.

Mark
Posted on: 31 Jul 2024 02:21

Note that this was originally logged via When a TextBlock is put in the GroupTemplate with HorizontalAlignment="Center" it is centered outside of the visible area.

Sample code was provided with that that generally addresses the issue, however we have recently encountered an issue with it.  The following is part of the provided sample code.  It seems that there are cases where "parentGroup.ChildrenOfType<Tile>();" in "private static void UpdatePresenter(FrameworkElement presenter)" either retrieves no tiles, or certain properties, such as the visibility of the tiles, prevents the "GetEnclosingBounds" method from accessing the size of the visual element.  Either way the result is an unhandled InvalidOperationException at System.Linq.Enumerable.Min(System.Collections.Generic.IEnumerable`1<Double>).  I am informing you of this in case it affects the solution you have implemented.

private static void OnSyncWidthWithParentGroupChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    FrameworkElement element = (FrameworkElement)d;
    FrameworkElement presenter = element.ParentOfType<ContentPresenter>();
    var tileList = element.ParentOfType<RadTileList>();

    if ((bool)e.NewValue)
    {
        UpdatePresenter(presenter);
        tileList.SizeChanged += (s, args) =>
        {
            UpdatePresenter(presenter);
        };
    }
}

private static void UpdatePresenter(FrameworkElement presenter)
{
    FrameworkElement parentGroup = presenter.ParentOfType<TileGroupContainer>();
    IEnumerable<FrameworkElement> tiles = parentGroup.ChildrenOfType<Tile>();
    Rect enclosingBounds = GetEnclosingBounds(tiles, parentGroup);

    presenter.HorizontalAlignment = HorizontalAlignment.Left;
    presenter.Width = enclosingBounds.Width;
}

private static Rect GetEnclosingBounds(IEnumerable<FrameworkElement> visuals, FrameworkElement parent)
{
    var boundsList = new List<Rect>();

    foreach (FrameworkElement visual in visuals)
    {
        GeneralTransform gt = visual.TransformToAncestor(parent);
        Rect elementBounds = gt.TransformBounds(new Rect(0, 0, visual.ActualWidth, visual.ActualHeight));
        boundsList.Add(elementBounds);
    }

    double top = boundsList.Min(x => x.Top);
    double bottom = boundsList.Max(x => x.Bottom);
    double left = boundsList.Min(x => x.Left);
    double right = boundsList.Max(x => x.Right);

    return new Rect(top, left, right - left, bottom - top);
}