Skip to content

Commit

Permalink
Incorporate dialog content without having to code the buttons. Suppor…
Browse files Browse the repository at this point in the history
…t UserControl and IDialog
  • Loading branch information
cwinland committed Jul 27, 2023
1 parent 2a25fe7 commit dc29f21
Show file tree
Hide file tree
Showing 14 changed files with 507 additions and 81 deletions.
15 changes: 15 additions & 0 deletions src/ButtonTemplateControl.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<UserControl x:Class="wpf_material_dialogs.ButtonTemplateControl"
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:local="clr-namespace:wpf_material_dialogs"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<ContentControl Margin="3 10 3 5"
Height="33"
VerticalContentAlignment="Bottom"
HorizontalAlignment="{Binding ButtonAlignment, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}"
Content="{Binding SelectedButtons, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}" materialDesign:ThemeAssist.Theme="Inherit" />
</UserControl>
42 changes: 42 additions & 0 deletions src/ButtonTemplateControl.xaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
using System.Windows;
using System.Windows.Controls;
using wpf_material_dialogs.Interfaces;

namespace wpf_material_dialogs
{
/// <inheritdoc cref="UserControl" />
/// <summary>
/// Interaction logic for ButtonTemplateControl.xaml
/// </summary>
public partial class ButtonTemplateControl : UserControl
{
/// <summary>
/// The button alignment property
/// </summary>
public static readonly DependencyProperty ButtonAlignmentProperty = DependencyProperty.Register(
nameof(ButtonAlignment), typeof(HorizontalAlignment), typeof(ButtonTemplateControl), new PropertyMetadata(HorizontalAlignment.Right));

public static readonly DependencyProperty SelectedButtonsProperty = DependencyProperty.Register(
nameof(SelectedButtons), typeof(IButtons), typeof(ButtonTemplateControl), new PropertyMetadata(default(IButtons)));

public IButtons SelectedButtons
{
get => (IButtons) GetValue(SelectedButtonsProperty);
set => SetValue(SelectedButtonsProperty, value);
}
/// <summary>
/// Gets or sets the button alignment.
/// </summary>
/// <value>The button alignment.</value>
public HorizontalAlignment ButtonAlignment
{
get => (HorizontalAlignment) GetValue(ButtonAlignmentProperty);
set => SetValue(ButtonAlignmentProperty, value);
}

public ButtonTemplateControl()
{
InitializeComponent();
}
}
}
31 changes: 31 additions & 0 deletions src/Dialogs/ContentDialog.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<UserControl x:Class="wpf_material_dialogs.Dialogs.ContentDialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:wpfMaterialDialogs="clr-namespace:wpf_material_dialogs"
mc:Ignorable="d"
Height="Auto" Width="500"
d:DesignHeight="450" d:DesignWidth="500">
<Grid Margin="5">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<StackPanel Grid.Row="0">
<ContentControl Content="{Binding ContentControl, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}" />
</StackPanel>
<StackPanel Grid.Row="1" Orientation="Horizontal" VerticalAlignment="Bottom" Margin="5" HorizontalAlignment="Right">
<wpfMaterialDialogs:ButtonTemplateControl
Visibility="{Binding ShowButtons, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}, Converter={StaticResource BooleanToVisibilityConverter}}"
ButtonAlignment="{Binding ButtonAlignment, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}"
SelectedButtons="{Binding SelectedButtons, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}" materialDesign:ThemeAssist.Theme="Inherit"
DataContext="{Binding}"
/>
</StackPanel>
</Grid>
</UserControl>
216 changes: 216 additions & 0 deletions src/Dialogs/ContentDialog.xaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Windows;
using System.Windows.Controls;
using wpf_material_dialogs.Enums;
using wpf_material_dialogs.Interfaces;

namespace wpf_material_dialogs.Dialogs
{
/// <summary>
/// Interaction logic for ContentDialog.xaml
/// </summary>
/// <inheritdoc cref="System.Windows.Controls.UserControl" />
public partial class ContentDialog : UserControl, INotifyPropertyChanged
{
#region Events

/// <inheritdoc />
/// <summary>
/// Occurs when [property changed].
/// </summary>
public event PropertyChangedEventHandler PropertyChanged;

#endregion

#region Fields

/// <summary>
/// The content control property
/// </summary>
public static readonly DependencyProperty ContentControlProperty = DependencyProperty.Register(
nameof(ContentControl), typeof(object), typeof(ContentDialog), new FrameworkPropertyMetadata(
default, FrameworkPropertyMetadataOptions.AffectsParentArrange |
FrameworkPropertyMetadataOptions.AffectsParentMeasure |
FrameworkPropertyMetadataOptions.AffectsRender |
FrameworkPropertyMetadataOptions.AffectsMeasure, Refresh));

/// <summary>
/// The content control property
/// </summary>
public static readonly DependencyProperty DialogButtonsProperty = DependencyProperty.Register(
nameof(DialogButtons), typeof(DialogButton), typeof(ContentDialog), new FrameworkPropertyMetadata(
DialogButton.OkButtons, FrameworkPropertyMetadataOptions.AffectsParentArrange |
FrameworkPropertyMetadataOptions.AffectsParentMeasure |
FrameworkPropertyMetadataOptions.AffectsRender |
FrameworkPropertyMetadataOptions.AffectsMeasure, Refresh));

/// <summary>
/// The button alignment property
/// </summary>
public static readonly DependencyProperty ButtonAlignmentProperty = DependencyProperty.Register(
nameof(ButtonAlignment), typeof(HorizontalAlignment), typeof(ContentDialog), new PropertyMetadata(HorizontalAlignment.Right, Refresh));

/// <summary>
/// The buttons property
/// </summary>
public static readonly DependencyProperty ButtonsProperty = DependencyProperty.Register(
nameof(Buttons), typeof(IButtons), typeof(ContentDialog), new PropertyMetadata(default(IButtons), Refresh));

/// <summary>
/// The show buttons property
/// </summary>
public static readonly DependencyProperty ShowButtonsProperty = DependencyProperty.Register(
nameof(ShowButtons), typeof(bool), typeof(ContentDialog), new PropertyMetadata(true, Refresh));

private readonly object buttonLock = new();
private readonly List<Type> buttonTypes = new();

#endregion

#region Properties

/// <summary>
/// Gets or sets a value indicating whether [show buttons].
/// </summary>
/// <value><c>true</c> if [show buttons]; otherwise, <c>false</c>.</value>
public bool ShowButtons
{
get => (bool) GetValue(ShowButtonsProperty);
set => SetValue(ShowButtonsProperty, value);
}

/// <summary>
/// Gets or sets the buttons.
/// </summary>
/// <value>The buttons.</value>
public IButtons Buttons
{
get => (IButtons) GetValue(ButtonsProperty);
set => SetValue(ButtonsProperty, value);
}

/// <summary>
/// Gets or sets the button alignment.
/// </summary>
/// <value>The button alignment.</value>
public HorizontalAlignment ButtonAlignment
{
get => (HorizontalAlignment) GetValue(ButtonAlignmentProperty);
set => SetValue(ButtonAlignmentProperty, value);
}

/// <summary>
/// Gets the selected buttons based on the <see cref="DialogButtons" /> selection.
/// </summary>
/// <value><see cref="IButtons" />.</value>
public IButtons SelectedButtons => ShowButtons
? DialogButtons == DialogButton.Custom
? Buttons
: GetButtons(DialogButtons)
: null;

/// <summary>
/// Gets or sets the content control.
/// </summary>
/// <value>The content control.</value>
public object ContentControl
{
get => GetValue(ContentControlProperty);
set => SetValue(ContentControlProperty, value);
}

/// <summary>
/// Gets or sets the dialog buttons.
/// </summary>
/// <value>The dialog buttons.</value>
public DialogButton DialogButtons
{
get => (DialogButton) GetValue(DialogButtonsProperty);
set
{
SetValue(DialogButtonsProperty, value);
NotifyOfPropertyChanged(nameof(SelectedButtons));
}
}

#endregion

/// <inheritdoc />
/// <summary>
/// Initializes a new instance of the <see cref="T:wpf_material_dialogs.Dialogs.ContentDialog" /> class.
/// </summary>
public ContentDialog() => InitializeComponent();

/// <inheritdoc />
/// <summary>
/// Initializes a new instance of the <see cref="T:wpf_material_dialogs.Dialogs.ContentDialog" /> class.
/// </summary>
/// <param name="contentControl">The content control.</param>
public ContentDialog(UserControl contentControl) : this() => ContentControl = contentControl;

/// <inheritdoc />
/// <summary>
/// Initializes a new instance of the <see cref="T:wpf_material_dialogs.Dialogs.ContentDialog" /> class.
/// </summary>
/// <param name="contentControl">The content control.</param>
public ContentDialog(IDialog contentControl) : this() => ContentControl = contentControl;

/// <summary>
/// Gets the buttons.
/// </summary>
/// <param name="button">The button enum to convert to an IButton.</param>
/// <returns>IButtons.</returns>
/// <exception cref="System.ArgumentOutOfRangeException">button</exception>
/// <exception cref="T:System.ArgumentOutOfRangeException">button</exception>
/// <exception cref="T:System.ArgumentOutOfRangeException">button</exception>
/// <exception cref="T:System.ArgumentOutOfRangeException">button</exception>
public IButtons GetButtons(DialogButton button)
{
// ReSharper disable once PossibleNullReferenceException
lock (buttonLock)
{
var assembly = Assembly.GetExecutingAssembly();

if (!buttonTypes?.Any() ?? false)
{
buttonTypes.AddRange(assembly
.GetTypes()
.Where(mytype => mytype.GetInterfaces().Contains(typeof(IButtons))));
}

var selectedButtonType =
buttonTypes?.First(mytype => button.ToString().Equals(mytype?.Name, StringComparison.CurrentCultureIgnoreCase));

return selectedButtonType?.FullName != null
? assembly.CreateInstance(selectedButtonType.FullName) as IButtons
: throw new ArgumentOutOfRangeException(nameof(button));
}
}

/// <summary>
/// Notifies the of property changed.
/// </summary>
/// <param name="propertyName">Name of the property.</param>
/// <inheritdoc cref="INotifyPropertyChanged" />
public void NotifyOfPropertyChanged([CallerMemberName] string propertyName = "") =>
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));

/// <summary>
/// Refreshes this instance.
/// </summary>
internal void Refresh() => NotifyOfPropertyChanged(nameof(SelectedButtons));

private static void Refresh(DependencyObject o, DependencyPropertyChangedEventArgs _)
{
if (o is ContentDialog d)
{
d.Refresh();
}
}
}
}
Loading

0 comments on commit dc29f21

Please sign in to comment.