Restored previous attempt at IndexOf(), but it's broken either way
This commit is contained in:
		
							parent
							
								
									059c093ec3
								
							
						
					
					
						commit
						ee6a57b784
					
				
					 4 changed files with 354 additions and 345 deletions
				
			
		| 
						 | 
					@ -289,7 +289,19 @@ namespace Nuclex.Avalonia.Collections {
 | 
				
			||||||
    /// <param name="item">Item whose index will be determined</param>
 | 
					    /// <param name="item">Item whose index will be determined</param>
 | 
				
			||||||
    /// <returns>The index of the item in the list or -1 if not found</returns>
 | 
					    /// <returns>The index of the item in the list or -1 if not found</returns>
 | 
				
			||||||
    public int IndexOf(TItem item) {
 | 
					    public int IndexOf(TItem item) {
 | 
				
			||||||
      return this.typedList.IndexOf(item);
 | 
					      requireCount();
 | 
				
			||||||
 | 
					      requireAllPages();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      // TODO: this won't work, it will compare the placeholder items :-/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      IComparer<TItem> itemComparer = Comparer<TItem>.Default;
 | 
				
			||||||
 | 
					      for(int index = 0; index < this.assumedCount.Value; ++index) {
 | 
				
			||||||
 | 
					        if(itemComparer.Compare(this.typedList[index], item) == 0) {
 | 
				
			||||||
 | 
					          return index;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      return -1;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <summary>Inserts an item into the list at the specified index</summary>
 | 
					    /// <summary>Inserts an item into the list at the specified index</summary>
 | 
				
			||||||
| 
						 | 
					@ -344,10 +356,8 @@ namespace Nuclex.Avalonia.Collections {
 | 
				
			||||||
    /// <param name="item">Item the list will be checked for</param>
 | 
					    /// <param name="item">Item the list will be checked for</param>
 | 
				
			||||||
    /// <returns>True if the list contains the specified items</returns>
 | 
					    /// <returns>True if the list contains the specified items</returns>
 | 
				
			||||||
    public bool Contains(TItem item) {
 | 
					    public bool Contains(TItem item) {
 | 
				
			||||||
      requireCount();
 | 
					      // TODO: this won't work, it will compare the placeholder items :-/
 | 
				
			||||||
      requireAllPages();
 | 
					      return (IndexOf(item) != -1);
 | 
				
			||||||
 | 
					 | 
				
			||||||
      return this.typedList.Contains(item);
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <summary>Copies the contents of the list into an array</summary>
 | 
					    /// <summary>Copies the contents of the list into an array</summary>
 | 
				
			||||||
| 
						 | 
					@ -359,14 +369,13 @@ namespace Nuclex.Avalonia.Collections {
 | 
				
			||||||
      requireCount();
 | 
					      requireCount();
 | 
				
			||||||
      requireAllPages();
 | 
					      requireAllPages();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      // TODO: this won't work, it will copy the placeholder items :-/
 | 
				
			||||||
      this.typedList.CopyTo(array, arrayIndex);
 | 
					      this.typedList.CopyTo(array, arrayIndex);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <summary>Total number of items in the list</summary>
 | 
					    /// <summary>Total number of items in the list</summary>
 | 
				
			||||||
    public int Count {
 | 
					    public int Count {
 | 
				
			||||||
      get {
 | 
					      get { return requireCount(); }
 | 
				
			||||||
        return requireCount();
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <summary>Whether the list is a read-only list</summary>
 | 
					    /// <summary>Whether the list is a read-only list</summary>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,35 +1,35 @@
 | 
				
			||||||
#region Apache License 2.0
 | 
					#region Apache License 2.0
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
Nuclex Foundation libraries for .NET
 | 
					Nuclex Foundation libraries for .NET
 | 
				
			||||||
Copyright (C) 2002-2025 Markus Ewald / Nuclex Development Labs
 | 
					Copyright (C) 2002-2025 Markus Ewald / Nuclex Development Labs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Licensed under the Apache License, Version 2.0 (the "License");
 | 
					Licensed under the Apache License, Version 2.0 (the "License");
 | 
				
			||||||
you may not use this file except in compliance with the License.
 | 
					you may not use this file except in compliance with the License.
 | 
				
			||||||
You may obtain a copy of the License at
 | 
					You may obtain a copy of the License at
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    http://www.apache.org/licenses/LICENSE-2.0
 | 
					    http://www.apache.org/licenses/LICENSE-2.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Unless required by applicable law or agreed to in writing, software
 | 
					Unless required by applicable law or agreed to in writing, software
 | 
				
			||||||
distributed under the License is distributed on an "AS IS" BASIS,
 | 
					distributed under the License is distributed on an "AS IS" BASIS,
 | 
				
			||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
					WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
				
			||||||
See the License for the specific language governing permissions and
 | 
					See the License for the specific language governing permissions and
 | 
				
			||||||
limitations under the License.
 | 
					limitations under the License.
 | 
				
			||||||
*/
 | 
					*/
 | 
				
			||||||
#endregion // Apache License 2.0
 | 
					#endregion // Apache License 2.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using System;
 | 
					using System;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using Avalonia.Controls;
 | 
					using Avalonia.Controls;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace Nuclex.Avalonia {
 | 
					namespace Nuclex.Avalonia {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /// <summary>Allows the currently active top level window to be looked up</summary>
 | 
					  /// <summary>Allows the currently active top level window to be looked up</summary>
 | 
				
			||||||
  public interface IActiveWindowTracker {
 | 
					  public interface IActiveWindowTracker {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <summary>The currently active top-level or modal window</summary>
 | 
					    /// <summary>The currently active top-level or modal window</summary>
 | 
				
			||||||
    Window? ActiveWindow { get; }
 | 
					    Window? ActiveWindow { get; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
} // namespace Nuclex.Avalonia
 | 
					} // namespace Nuclex.Avalonia
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,114 +1,114 @@
 | 
				
			||||||
#region Apache License 2.0
 | 
					#region Apache License 2.0
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
Nuclex Foundation libraries for .NET
 | 
					Nuclex Foundation libraries for .NET
 | 
				
			||||||
Copyright (C) 2002-2025 Markus Ewald / Nuclex Development Labs
 | 
					Copyright (C) 2002-2025 Markus Ewald / Nuclex Development Labs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Licensed under the Apache License, Version 2.0 (the "License");
 | 
					Licensed under the Apache License, Version 2.0 (the "License");
 | 
				
			||||||
you may not use this file except in compliance with the License.
 | 
					you may not use this file except in compliance with the License.
 | 
				
			||||||
You may obtain a copy of the License at
 | 
					You may obtain a copy of the License at
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    http://www.apache.org/licenses/LICENSE-2.0
 | 
					    http://www.apache.org/licenses/LICENSE-2.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Unless required by applicable law or agreed to in writing, software
 | 
					Unless required by applicable law or agreed to in writing, software
 | 
				
			||||||
distributed under the License is distributed on an "AS IS" BASIS,
 | 
					distributed under the License is distributed on an "AS IS" BASIS,
 | 
				
			||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
					WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
				
			||||||
See the License for the specific language governing permissions and
 | 
					See the License for the specific language governing permissions and
 | 
				
			||||||
limitations under the License.
 | 
					limitations under the License.
 | 
				
			||||||
*/
 | 
					*/
 | 
				
			||||||
#endregion // Apache License 2.0
 | 
					#endregion // Apache License 2.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using System;
 | 
					using System;
 | 
				
			||||||
using System.Threading.Tasks;
 | 
					using System.Threading.Tasks;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using Avalonia.Controls;
 | 
					using Avalonia.Controls;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace Nuclex.Avalonia {
 | 
					namespace Nuclex.Avalonia {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /// <summary>Manages open windows and connecting them to view models</summary>
 | 
					  /// <summary>Manages open windows and connecting them to view models</summary>
 | 
				
			||||||
  public interface IWindowManager : IActiveWindowTracker {
 | 
					  public interface IWindowManager : IActiveWindowTracker {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <summary>Opens a view as a new root window of the application</summary>
 | 
					    /// <summary>Opens a view as a new root window of the application</summary>
 | 
				
			||||||
    /// <typeparam name="TViewModel">
 | 
					    /// <typeparam name="TViewModel">
 | 
				
			||||||
    ///   Type of view model a root window will be opened for
 | 
					    ///   Type of view model a root window will be opened for
 | 
				
			||||||
    /// </typeparam>
 | 
					    /// </typeparam>
 | 
				
			||||||
    /// <param name="viewModel">
 | 
					    /// <param name="viewModel">
 | 
				
			||||||
    ///   View model a window will be opened for. If null, the view model will be
 | 
					    ///   View model a window will be opened for. If null, the view model will be
 | 
				
			||||||
    ///   created as well (unless the dialog already specifies one as a resource)
 | 
					    ///   created as well (unless the dialog already specifies one as a resource)
 | 
				
			||||||
    /// </param>
 | 
					    /// </param>
 | 
				
			||||||
    /// <param name="disposeOnClose">
 | 
					    /// <param name="disposeOnClose">
 | 
				
			||||||
    ///   Whether the view model should be disposed when the view is closed
 | 
					    ///   Whether the view model should be disposed when the view is closed
 | 
				
			||||||
    /// </param>
 | 
					    /// </param>
 | 
				
			||||||
    /// <returns>The window that has been opened by the window manager</returns>
 | 
					    /// <returns>The window that has been opened by the window manager</returns>
 | 
				
			||||||
    Window OpenRoot<TViewModel>(
 | 
					    Window OpenRoot<TViewModel>(
 | 
				
			||||||
      TViewModel? viewModel = null, bool disposeOnClose = true
 | 
					      TViewModel? viewModel = null, bool disposeOnClose = true
 | 
				
			||||||
    ) where TViewModel : class;
 | 
					    ) where TViewModel : class;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <summary>Displays a view as a modal window</summary>
 | 
					    /// <summary>Displays a view as a modal window</summary>
 | 
				
			||||||
    /// <typeparam name="TViewModel">
 | 
					    /// <typeparam name="TViewModel">
 | 
				
			||||||
    ///   Type of the view model for which a view will be displayed
 | 
					    ///   Type of the view model for which a view will be displayed
 | 
				
			||||||
    /// </typeparam>
 | 
					    /// </typeparam>
 | 
				
			||||||
    /// <param name="viewModel">
 | 
					    /// <param name="viewModel">
 | 
				
			||||||
    ///   View model a modal window will be displayed for. If null, the view model will
 | 
					    ///   View model a modal window will be displayed for. If null, the view model will
 | 
				
			||||||
    ///   be created as well (unless the dialog already specifies one as a resource)
 | 
					    ///   be created as well (unless the dialog already specifies one as a resource)
 | 
				
			||||||
    /// </param>
 | 
					    /// </param>
 | 
				
			||||||
    /// <param name="disposeOnClose">
 | 
					    /// <param name="disposeOnClose">
 | 
				
			||||||
    ///   Whether the view model should be disposed when the view is closed
 | 
					    ///   Whether the view model should be disposed when the view is closed
 | 
				
			||||||
    /// </param>
 | 
					    /// </param>
 | 
				
			||||||
    /// <returns>The return value of the modal window</returns>
 | 
					    /// <returns>The return value of the modal window</returns>
 | 
				
			||||||
    Task ShowModalAsync<TViewModel>(
 | 
					    Task ShowModalAsync<TViewModel>(
 | 
				
			||||||
      TViewModel? viewModel = null, bool disposeOnClose = false
 | 
					      TViewModel? viewModel = null, bool disposeOnClose = false
 | 
				
			||||||
    ) where TViewModel : class;
 | 
					    ) where TViewModel : class;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <summary>Displays a view as a modal window</summary>
 | 
					    /// <summary>Displays a view as a modal window</summary>
 | 
				
			||||||
    /// <typeparam name="TResult">
 | 
					    /// <typeparam name="TResult">
 | 
				
			||||||
    ///   Type of result the modal dialog will return to the caller
 | 
					    ///   Type of result the modal dialog will return to the caller
 | 
				
			||||||
    /// </typeparam>
 | 
					    /// </typeparam>
 | 
				
			||||||
    /// <typeparam name="TViewModel">
 | 
					    /// <typeparam name="TViewModel">
 | 
				
			||||||
    ///   Type of the view model for which a view will be displayed
 | 
					    ///   Type of the view model for which a view will be displayed
 | 
				
			||||||
    /// </typeparam>
 | 
					    /// </typeparam>
 | 
				
			||||||
    /// <param name="viewModel">
 | 
					    /// <param name="viewModel">
 | 
				
			||||||
    ///   View model a modal window will be displayed for. If null, the view model will
 | 
					    ///   View model a modal window will be displayed for. If null, the view model will
 | 
				
			||||||
    ///   be created as well (unless the dialog already specifies one as a resource)
 | 
					    ///   be created as well (unless the dialog already specifies one as a resource)
 | 
				
			||||||
    /// </param>
 | 
					    /// </param>
 | 
				
			||||||
    /// <param name="disposeOnClose">
 | 
					    /// <param name="disposeOnClose">
 | 
				
			||||||
    ///   Whether the view model should be disposed when the view is closed
 | 
					    ///   Whether the view model should be disposed when the view is closed
 | 
				
			||||||
    /// </param>
 | 
					    /// </param>
 | 
				
			||||||
    /// <returns>The return value of the modal window</returns>
 | 
					    /// <returns>The return value of the modal window</returns>
 | 
				
			||||||
    Task<TResult> ShowModalAsync<TResult, TViewModel>(
 | 
					    Task<TResult> ShowModalAsync<TResult, TViewModel>(
 | 
				
			||||||
      TViewModel? viewModel = null, bool disposeOnClose = true
 | 
					      TViewModel? viewModel = null, bool disposeOnClose = true
 | 
				
			||||||
    ) where TViewModel : class;
 | 
					    ) where TViewModel : class;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <summary>Creates the view for the specified view model</summary>
 | 
					    /// <summary>Creates the view for the specified view model</summary>
 | 
				
			||||||
    /// <typeparam name="TViewModel">
 | 
					    /// <typeparam name="TViewModel">
 | 
				
			||||||
    ///   Type of view model for which a view will be created
 | 
					    ///   Type of view model for which a view will be created
 | 
				
			||||||
    /// </typeparam>
 | 
					    /// </typeparam>
 | 
				
			||||||
    /// <param name="viewModel">
 | 
					    /// <param name="viewModel">
 | 
				
			||||||
    ///   View model a view will be created for. If null, the view model will be
 | 
					    ///   View model a view will be created for. If null, the view model will be
 | 
				
			||||||
    ///   created as well (unless the dialog already specifies one as a resource)
 | 
					    ///   created as well (unless the dialog already specifies one as a resource)
 | 
				
			||||||
    /// </param>
 | 
					    /// </param>
 | 
				
			||||||
    /// <returns>The view for the specified view model</returns>
 | 
					    /// <returns>The view for the specified view model</returns>
 | 
				
			||||||
    Control CreateView<TViewModel>(TViewModel? viewModel = null)
 | 
					    Control CreateView<TViewModel>(TViewModel? viewModel = null)
 | 
				
			||||||
      where TViewModel : class;
 | 
					      where TViewModel : class;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <summary>Creates a view model without a matching view</summary>
 | 
					    /// <summary>Creates a view model without a matching view</summary>
 | 
				
			||||||
    /// <typeparam name="TViewModel">Type of view model that will be created</typeparam>
 | 
					    /// <typeparam name="TViewModel">Type of view model that will be created</typeparam>
 | 
				
			||||||
    /// <returns>The new view model</returns>
 | 
					    /// <returns>The new view model</returns>
 | 
				
			||||||
    /// <remarks>
 | 
					    /// <remarks>
 | 
				
			||||||
    ///   <para>
 | 
					    ///   <para>
 | 
				
			||||||
    ///     This is useful if a view model needs to create child view models (i.e. paged container
 | 
					    ///     This is useful if a view model needs to create child view models (i.e. paged container
 | 
				
			||||||
    ///     and wants to ensure the same dependency injector (if any) if used as the window
 | 
					    ///     and wants to ensure the same dependency injector (if any) if used as the window
 | 
				
			||||||
    ///     manager uses for other view models it creates.
 | 
					    ///     manager uses for other view models it creates.
 | 
				
			||||||
    ///   </para>
 | 
					    ///   </para>
 | 
				
			||||||
    ///   <para>
 | 
					    ///   <para>
 | 
				
			||||||
    ///     This way, view models can set up their child view models without having to immediately
 | 
					    ///     This way, view models can set up their child view models without having to immediately
 | 
				
			||||||
    ///     bind a view to them. Later on, views can use the window manager to create a matching
 | 
					    ///     bind a view to them. Later on, views can use the window manager to create a matching
 | 
				
			||||||
    ///     child view and store it in a container.
 | 
					    ///     child view and store it in a container.
 | 
				
			||||||
    ///   </para>
 | 
					    ///   </para>
 | 
				
			||||||
    /// </remarks>
 | 
					    /// </remarks>
 | 
				
			||||||
    TViewModel CreateViewModel<TViewModel>()
 | 
					    TViewModel CreateViewModel<TViewModel>()
 | 
				
			||||||
      where TViewModel : class;
 | 
					      where TViewModel : class;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
} // namespace Nuclex.Avalonia
 | 
					} // namespace Nuclex.Avalonia
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,188 +1,188 @@
 | 
				
			||||||
#region Apache License 2.0
 | 
					#region Apache License 2.0
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
Nuclex Foundation libraries for .NET
 | 
					Nuclex Foundation libraries for .NET
 | 
				
			||||||
Copyright (C) 2002-2025 Markus Ewald / Nuclex Development Labs
 | 
					Copyright (C) 2002-2025 Markus Ewald / Nuclex Development Labs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Licensed under the Apache License, Version 2.0 (the "License");
 | 
					Licensed under the Apache License, Version 2.0 (the "License");
 | 
				
			||||||
you may not use this file except in compliance with the License.
 | 
					you may not use this file except in compliance with the License.
 | 
				
			||||||
You may obtain a copy of the License at
 | 
					You may obtain a copy of the License at
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    http://www.apache.org/licenses/LICENSE-2.0
 | 
					    http://www.apache.org/licenses/LICENSE-2.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Unless required by applicable law or agreed to in writing, software
 | 
					Unless required by applicable law or agreed to in writing, software
 | 
				
			||||||
distributed under the License is distributed on an "AS IS" BASIS,
 | 
					distributed under the License is distributed on an "AS IS" BASIS,
 | 
				
			||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
					WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
				
			||||||
See the License for the specific language governing permissions and
 | 
					See the License for the specific language governing permissions and
 | 
				
			||||||
limitations under the License.
 | 
					limitations under the License.
 | 
				
			||||||
*/
 | 
					*/
 | 
				
			||||||
#endregion // Apache License 2.0
 | 
					#endregion // Apache License 2.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using System;
 | 
					using System;
 | 
				
			||||||
using System.Threading.Tasks;
 | 
					using System.Threading.Tasks;
 | 
				
			||||||
using System.Diagnostics;
 | 
					using System.Diagnostics;
 | 
				
			||||||
using System.Runtime.InteropServices;
 | 
					using System.Runtime.InteropServices;
 | 
				
			||||||
using System.Runtime.Versioning;
 | 
					using System.Runtime.Versioning;
 | 
				
			||||||
#if NET6_0_OR_GREATER
 | 
					#if NET6_0_OR_GREATER
 | 
				
			||||||
using System.Runtime.Versioning;
 | 
					using System.Runtime.Versioning;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using Avalonia.Controls;
 | 
					using Avalonia.Controls;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using MessageBoxIcon = MsBox.Avalonia.Enums.Icon;
 | 
					using MessageBoxIcon = MsBox.Avalonia.Enums.Icon;
 | 
				
			||||||
using MessageBoxButtons = MsBox.Avalonia.Enums.ButtonEnum;
 | 
					using MessageBoxButtons = MsBox.Avalonia.Enums.ButtonEnum;
 | 
				
			||||||
using MessageDialogResult = MsBox.Avalonia.Enums.ButtonResult;
 | 
					using MessageDialogResult = MsBox.Avalonia.Enums.ButtonResult;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace Nuclex.Avalonia.Messages {
 | 
					namespace Nuclex.Avalonia.Messages {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /// <summary>Uses Avalonia to display message boxes</summary>
 | 
					  /// <summary>Uses Avalonia to display message boxes</summary>
 | 
				
			||||||
  public class AvaloniaMessagePresenter : IMessageService {
 | 
					  public class AvaloniaMessagePresenter : IMessageService {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #region class MessageScope
 | 
					    #region class MessageScope
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <summary>Triggers the message displayed and acknowledged events</summary>
 | 
					    /// <summary>Triggers the message displayed and acknowledged events</summary>
 | 
				
			||||||
    private class MessageScope : IDisposable {
 | 
					    private class MessageScope : IDisposable {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      /// <summary>
 | 
					      /// <summary>
 | 
				
			||||||
      ///   Initializes a new message scope, triggering the message displayed event
 | 
					      ///   Initializes a new message scope, triggering the message displayed event
 | 
				
			||||||
      /// </summary>
 | 
					      /// </summary>
 | 
				
			||||||
      /// <param name="self">Message service the scope belongs to</param>
 | 
					      /// <param name="self">Message service the scope belongs to</param>
 | 
				
			||||||
      /// <param name="image">Image of the message being displayed</param>
 | 
					      /// <param name="image">Image of the message being displayed</param>
 | 
				
			||||||
      /// <param name="text">Text contained in the message being displayed</param>
 | 
					      /// <param name="text">Text contained in the message being displayed</param>
 | 
				
			||||||
      public MessageScope(
 | 
					      public MessageScope(
 | 
				
			||||||
        AvaloniaMessagePresenter self, MessageBoxIcon image, MessageText text
 | 
					        AvaloniaMessagePresenter self, MessageBoxIcon image, MessageText text
 | 
				
			||||||
      ) {
 | 
					      ) {
 | 
				
			||||||
        EventHandler<MessageEventArgs>? messageDisplayed = self.MessageDisplaying;
 | 
					        EventHandler<MessageEventArgs>? messageDisplayed = self.MessageDisplaying;
 | 
				
			||||||
        if(messageDisplayed != null) {
 | 
					        if(messageDisplayed != null) {
 | 
				
			||||||
          messageDisplayed(this, new MessageEventArgs(image, text));
 | 
					          messageDisplayed(this, new MessageEventArgs(image, text));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        this.self = self;
 | 
					        this.self = self;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      /// <summary>Triggers the message acknowledged event</summary>
 | 
					      /// <summary>Triggers the message acknowledged event</summary>
 | 
				
			||||||
      public void Dispose() {
 | 
					      public void Dispose() {
 | 
				
			||||||
        EventHandler? messageAcknowledged = self.MessageAcknowledged;
 | 
					        EventHandler? messageAcknowledged = self.MessageAcknowledged;
 | 
				
			||||||
        if(messageAcknowledged != null) {
 | 
					        if(messageAcknowledged != null) {
 | 
				
			||||||
          messageAcknowledged(this, EventArgs.Empty);
 | 
					          messageAcknowledged(this, EventArgs.Empty);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      /// <summary>Message service the scope belongs to</summary>
 | 
					      /// <summary>Message service the scope belongs to</summary>
 | 
				
			||||||
      private AvaloniaMessagePresenter self;
 | 
					      private AvaloniaMessagePresenter self;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #endregion // class MessageScope
 | 
					    #endregion // class MessageScope
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <summary>Triggered when a message is displayed to the user</summary>
 | 
					    /// <summary>Triggered when a message is displayed to the user</summary>
 | 
				
			||||||
    public event EventHandler<MessageEventArgs>? MessageDisplaying;
 | 
					    public event EventHandler<MessageEventArgs>? MessageDisplaying;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <summary>Triggered when the user has acknowledged the current message</summary>
 | 
					    /// <summary>Triggered when the user has acknowledged the current message</summary>
 | 
				
			||||||
    public event EventHandler? MessageAcknowledged;
 | 
					    public event EventHandler? MessageAcknowledged;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <summary>Initializes a new Avalonia message service</summary>
 | 
					    /// <summary>Initializes a new Avalonia message service</summary>
 | 
				
			||||||
    /// <param name="tracker">Used to determine the current top-level window</param>
 | 
					    /// <param name="tracker">Used to determine the current top-level window</param>
 | 
				
			||||||
    public AvaloniaMessagePresenter(IActiveWindowTracker tracker) {
 | 
					    public AvaloniaMessagePresenter(IActiveWindowTracker tracker) {
 | 
				
			||||||
      this.tracker = tracker;
 | 
					      this.tracker = tracker;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <summary>Asks the user a question that can be answered via several buttons</summary>
 | 
					    /// <summary>Asks the user a question that can be answered via several buttons</summary>
 | 
				
			||||||
    /// <param name="image">Image that will be shown on the message box</param>
 | 
					    /// <param name="image">Image that will be shown on the message box</param>
 | 
				
			||||||
    /// <param name="text">Text that will be shown to the user</param>
 | 
					    /// <param name="text">Text that will be shown to the user</param>
 | 
				
			||||||
    /// <param name="buttons">Buttons available for the user to click on</param>
 | 
					    /// <param name="buttons">Buttons available for the user to click on</param>
 | 
				
			||||||
    /// <returns>The button the user has clicked on</returns>
 | 
					    /// <returns>The button the user has clicked on</returns>
 | 
				
			||||||
    public Task<MessageDialogResult> ShowQuestionAsync(
 | 
					    public Task<MessageDialogResult> ShowQuestionAsync(
 | 
				
			||||||
      MessageBoxIcon image, MessageText text, MessageBoxButtons buttons
 | 
					      MessageBoxIcon image, MessageText text, MessageBoxButtons buttons
 | 
				
			||||||
    ) {
 | 
					    ) {
 | 
				
			||||||
      using(var scope = new MessageScope(this, image, text)) {
 | 
					      using(var scope = new MessageScope(this, image, text)) {
 | 
				
			||||||
        MsBox.Avalonia.Base.IMsBox<MessageDialogResult> messageBox = (
 | 
					        MsBox.Avalonia.Base.IMsBox<MessageDialogResult> messageBox = (
 | 
				
			||||||
          MsBox.Avalonia.MessageBoxManager.GetMessageBoxStandard(
 | 
					          MsBox.Avalonia.MessageBoxManager.GetMessageBoxStandard(
 | 
				
			||||||
            new MsBox.Avalonia.Dto.MessageBoxStandardParams() {
 | 
					            new MsBox.Avalonia.Dto.MessageBoxStandardParams() {
 | 
				
			||||||
              ContentTitle = text.Caption,
 | 
					              ContentTitle = text.Caption,
 | 
				
			||||||
              ContentHeader = text.Message,
 | 
					              ContentHeader = text.Message,
 | 
				
			||||||
              ContentMessage = text.Details ?? string.Empty,
 | 
					              ContentMessage = text.Details ?? string.Empty,
 | 
				
			||||||
              ButtonDefinitions = buttons,
 | 
					              ButtonDefinitions = buttons,
 | 
				
			||||||
              Icon = image,
 | 
					              Icon = image,
 | 
				
			||||||
              WindowStartupLocation = WindowStartupLocation.CenterOwner
 | 
					              WindowStartupLocation = WindowStartupLocation.CenterOwner
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
          )
 | 
					          )
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
        return messageBox.ShowAsync(); // TODO: Make modal to current or main window
 | 
					        return messageBox.ShowAsync(); // TODO: Make modal to current or main window
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <summary>Displays a notification to the user</summary>
 | 
					    /// <summary>Displays a notification to the user</summary>
 | 
				
			||||||
    /// <param name="image">Image that will be shown on the message bx</param>
 | 
					    /// <param name="image">Image that will be shown on the message bx</param>
 | 
				
			||||||
    /// <param name="text">Text that will be shown to the user</param>
 | 
					    /// <param name="text">Text that will be shown to the user</param>
 | 
				
			||||||
    public Task ShowNotificationAsync(MessageBoxIcon image, MessageText text) {
 | 
					    public Task ShowNotificationAsync(MessageBoxIcon image, MessageText text) {
 | 
				
			||||||
      using(var scope = new MessageScope(this, image, text)) {
 | 
					      using(var scope = new MessageScope(this, image, text)) {
 | 
				
			||||||
        MsBox.Avalonia.Base.IMsBox<MessageDialogResult> messageBox = (
 | 
					        MsBox.Avalonia.Base.IMsBox<MessageDialogResult> messageBox = (
 | 
				
			||||||
          MsBox.Avalonia.MessageBoxManager.GetMessageBoxStandard(
 | 
					          MsBox.Avalonia.MessageBoxManager.GetMessageBoxStandard(
 | 
				
			||||||
            new MsBox.Avalonia.Dto.MessageBoxStandardParams() {
 | 
					            new MsBox.Avalonia.Dto.MessageBoxStandardParams() {
 | 
				
			||||||
              ContentTitle = text.Caption,
 | 
					              ContentTitle = text.Caption,
 | 
				
			||||||
              ContentHeader = text.Message,
 | 
					              ContentHeader = text.Message,
 | 
				
			||||||
              ContentMessage = text.Details ?? string.Empty,
 | 
					              ContentMessage = text.Details ?? string.Empty,
 | 
				
			||||||
              ButtonDefinitions = MessageBoxButtons.Ok,
 | 
					              ButtonDefinitions = MessageBoxButtons.Ok,
 | 
				
			||||||
              Icon = image,
 | 
					              Icon = image,
 | 
				
			||||||
              WindowStartupLocation = WindowStartupLocation.CenterOwner
 | 
					              WindowStartupLocation = WindowStartupLocation.CenterOwner
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
          )
 | 
					          )
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Window? activeWindow = this.tracker.ActiveWindow;
 | 
					        Window? activeWindow = this.tracker.ActiveWindow;
 | 
				
			||||||
        if(activeWindow == null) {
 | 
					        if(activeWindow == null) {
 | 
				
			||||||
          return messageBox.ShowAsync();
 | 
					          return messageBox.ShowAsync();
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
          //return messageBox.ShowAsPopupAsync(activeWindow);
 | 
					          //return messageBox.ShowAsPopupAsync(activeWindow);
 | 
				
			||||||
          return messageBox.ShowWindowDialogAsync(activeWindow);
 | 
					          return messageBox.ShowWindowDialogAsync(activeWindow);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <summary>Reports an error using the system's message box functions</summary>
 | 
					    /// <summary>Reports an error using the system's message box functions</summary>
 | 
				
			||||||
    /// <param name="title">Title of the message box</param>
 | 
					    /// <param name="title">Title of the message box</param>
 | 
				
			||||||
    /// <param name="message">Message text that will be displayed</param>
 | 
					    /// <param name="message">Message text that will be displayed</param>
 | 
				
			||||||
    public static void FallbackReportError(string title, string message) {
 | 
					    public static void FallbackReportError(string title, string message) {
 | 
				
			||||||
      // TODO: Escape quotes for the command-line tools
 | 
					      // TODO: Escape quotes for the command-line tools
 | 
				
			||||||
      // TODO: Wait for the child process to exit so display is certain
 | 
					      // TODO: Wait for the child process to exit so display is certain
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if(RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) {
 | 
					      if(RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) {
 | 
				
			||||||
        MessageBoxW(IntPtr.Zero, message, title, MB_OK | MB_ICONEXCLAMATION);
 | 
					        MessageBoxW(IntPtr.Zero, message, title, MB_OK | MB_ICONEXCLAMATION);
 | 
				
			||||||
      } else if(RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) {
 | 
					      } else if(RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) {
 | 
				
			||||||
        Process.Start("zenity", $"--error --title=\"{title}\" --text=\"{message}\"");
 | 
					        Process.Start("zenity", $"--error --title=\"{title}\" --text=\"{message}\"");
 | 
				
			||||||
      } else if(RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) {
 | 
					      } else if(RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) {
 | 
				
			||||||
        Process.Start("osascript", $"-e 'display dialog \"{message}\" with title \"{title}\" with icon stop'");
 | 
					        Process.Start("osascript", $"-e 'display dialog \"{message}\" with title \"{title}\" with icon stop'");
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <summary>Windows only: display a message box with an OK button</summary>
 | 
					    /// <summary>Windows only: display a message box with an OK button</summary>
 | 
				
			||||||
#if NET6_0_OR_GREATER
 | 
					#if NET6_0_OR_GREATER
 | 
				
			||||||
  [SupportedOSPlatform("windows")]
 | 
					  [SupportedOSPlatform("windows")]
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
    private const uint MB_OK = 0x00000000;
 | 
					    private const uint MB_OK = 0x00000000;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <summary>Windows only: display a message box with an Exclamation icon</summary>
 | 
					    /// <summary>Windows only: display a message box with an Exclamation icon</summary>
 | 
				
			||||||
#if NET6_0_OR_GREATER
 | 
					#if NET6_0_OR_GREATER
 | 
				
			||||||
  [SupportedOSPlatform("windows")]
 | 
					  [SupportedOSPlatform("windows")]
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
    private const uint MB_ICONEXCLAMATION = 0x00000030;
 | 
					    private const uint MB_ICONEXCLAMATION = 0x00000030;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <summary>Windows only: displays a native Windows message box</summary>
 | 
					    /// <summary>Windows only: displays a native Windows message box</summary>
 | 
				
			||||||
    /// <param name="parentWindowHandle">Handle of the window that owns the message box</param>
 | 
					    /// <param name="parentWindowHandle">Handle of the window that owns the message box</param>
 | 
				
			||||||
    /// <param name="text">Text that should be in the message box</param>
 | 
					    /// <param name="text">Text that should be in the message box</param>
 | 
				
			||||||
    /// <param name="caption">Caption or window title of the message box</param>
 | 
					    /// <param name="caption">Caption or window title of the message box</param>
 | 
				
			||||||
    /// <param name="type">Which icons and buttons that message box should have</param>
 | 
					    /// <param name="type">Which icons and buttons that message box should have</param>
 | 
				
			||||||
    /// <returns>How the user closed the message box and which button they clicked</returns>
 | 
					    /// <returns>How the user closed the message box and which button they clicked</returns>
 | 
				
			||||||
    [DllImport("user32.dll", CharSet = CharSet.Unicode)]
 | 
					    [DllImport("user32.dll", CharSet = CharSet.Unicode)]
 | 
				
			||||||
#if NET6_0_OR_GREATER
 | 
					#if NET6_0_OR_GREATER
 | 
				
			||||||
  [SupportedOSPlatform("windows")]
 | 
					  [SupportedOSPlatform("windows")]
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
    private static extern int MessageBoxW(IntPtr parentWindowHandle, string text, string caption, uint type);
 | 
					    private static extern int MessageBoxW(IntPtr parentWindowHandle, string text, string caption, uint type);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // <summary>Provides the currently active top-level window</summary>
 | 
					    // <summary>Provides the currently active top-level window</summary>
 | 
				
			||||||
    private IActiveWindowTracker tracker;
 | 
					    private IActiveWindowTracker tracker;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
} // namespace Nuclex.Avalonia.Messages
 | 
					} // namespace Nuclex.Avalonia.Messages
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue