Fix null file bug and add context menu to my ratings column

This commit is contained in:
Michael Bucari-Tovo 2022-12-31 21:09:30 -07:00
parent 613cfdd903
commit a7bf30954d
14 changed files with 118 additions and 144 deletions

View File

@ -1,5 +0,0 @@
<DataGridCheckBoxColumn xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="LibationAvalonia.Controls.DataGridCheckBoxColumnExt">
</DataGridCheckBoxColumn >

View File

@ -1,10 +1,11 @@
using Avalonia.Controls;
using Avalonia.Controls;
using LibationAvalonia.ViewModels;
using System;
using System.Linq;
namespace LibationAvalonia.Controls
{
public partial class DataGridCheckBoxColumnExt : DataGridCheckBoxColumn
public class DataGridCheckBoxColumnExt : DataGridCheckBoxColumn
{
protected override IControl GenerateEditingElementDirect(DataGridCell cell, object dataItem)
{

View File

@ -1,6 +1,5 @@
using Avalonia.Collections;
using Avalonia.Collections;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
using LibationAvalonia.ViewModels;
using System;
using System.Reflection;
@ -19,36 +18,46 @@ namespace LibationAvalonia.Controls
=> GetCellValueMethod.Invoke(column, new object[] { item, column.ClipboardContentBinding })?.ToString() ?? "";
public string CellClipboardContents => GetCellValue(Column, GridEntry);
public DataGridTemplateColumnExt Column { get; init; }
public DataGridColumn Column { get; init; }
public GridEntry GridEntry { get; init; }
public ContextMenu ContextMenu { get; init; }
public AvaloniaList<MenuItem> ContextMenuItems
=> ContextMenu.Items as AvaloniaList<MenuItem>;
}
public partial class DataGridTemplateColumnExt : DataGridTemplateColumn
internal static class DataGridContextMenus
{
public event EventHandler<DataGridCellContextMenuStripNeededEventArgs> CellContextMenuStripNeeded;
public static event EventHandler<DataGridCellContextMenuStripNeededEventArgs> CellContextMenuStripNeeded;
private static readonly ContextMenu ContextMenu = new();
private static readonly AvaloniaList<MenuItem> MenuItems = new();
private static readonly AvaloniaList<MenuItem> MenuItems = new();
private static readonly PropertyInfo OwningColumnProperty;
public DataGridTemplateColumnExt()
static DataGridContextMenus()
{
AvaloniaXamlLoader.Load(this);
ContextMenu.Items = MenuItems;
OwningColumnProperty = typeof(DataGridCell).GetProperty("OwningColumn", BindingFlags.Instance | BindingFlags.NonPublic);
}
private void Cell_ContextRequested(object sender, ContextRequestedEventArgs e)
public static void AttachContextMenuToCell(this DataGridCell cell)
{
if (cell.ContextMenu is null)
{
cell.ContextRequested += Cell_ContextRequested;
cell.ContextMenu = ContextMenu;
}
}
private static void Cell_ContextRequested(object sender, ContextRequestedEventArgs e)
{
if (sender is DataGridCell cell && cell.DataContext is GridEntry entry)
{
var args = new DataGridCellContextMenuStripNeededEventArgs
{
Column = this,
Column = OwningColumnProperty.GetValue(cell) as DataGridColumn,
GridEntry = entry,
ContextMenu = ContextMenu
};
args.ContextMenuItems.Clear();
CellContextMenuStripNeeded?.Invoke(sender, args);
@ -58,16 +67,5 @@ namespace LibationAvalonia.Controls
else
e.Handled = true;
}
protected override IControl GenerateElement(DataGridCell cell, object dataItem)
{
if (cell.ContextMenu is null)
{
cell.ContextRequested += Cell_ContextRequested;
cell.ContextMenu = ContextMenu;
}
return base.GenerateElement(cell, dataItem);
}
}
}

View File

@ -1,17 +1,15 @@
using Avalonia;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Interactivity;
using Avalonia.Markup.Xaml;
using DataLayer;
namespace LibationAvalonia.Controls
{
public partial class MyRatingGridColumn : DataGridBoundColumn
public class DataGridMyRatingColumn : DataGridBoundColumn
{
private static Rating DefaultRating => new Rating(0, 0, 0);
public MyRatingGridColumn()
public DataGridMyRatingColumn()
{
AvaloniaXamlLoader.Load(this);
BindingTarget = MyRatingCellEditor.RatingProperty;
}
@ -20,40 +18,26 @@ namespace LibationAvalonia.Controls
var myRatingElement = new MyRatingCellEditor
{
Name = "CellMyRatingDisplay",
HorizontalAlignment = Avalonia.Layout.HorizontalAlignment.Left,
VerticalAlignment = Avalonia.Layout.VerticalAlignment.Center,
IsEditingMode = false,
Margin = new Thickness(3),
IsEnabled = false
IsEditingMode = false
};
//Create a panel that fills the cell to host the rating tool tip
var panel = new Panel
{
Background = Avalonia.Media.Brushes.Transparent,
HorizontalAlignment = Avalonia.Layout.HorizontalAlignment.Stretch,
VerticalAlignment = Avalonia.Layout.VerticalAlignment.Stretch,
};
panel.Children.Add(myRatingElement);
ToolTip.SetTip(panel, "Click to change ratings");
ToolTip.SetTip(myRatingElement, "Click to change ratings");
cell?.AttachContextMenuToCell();
if (Binding != null)
{
myRatingElement.Bind(BindingTarget, Binding);
}
return panel;
return myRatingElement;
}
protected override IControl GenerateEditingElementDirect(DataGridCell cell, object dataItem)
{
var myRatingElement = new MyRatingCellEditor
{
Name = "CellMyRatingCellEditor",
HorizontalAlignment = Avalonia.Layout.HorizontalAlignment.Left,
VerticalAlignment = Avalonia.Layout.VerticalAlignment.Center,
IsEditingMode = true,
Margin = new Thickness(3)
Name = "CellMyRatingEditor",
IsEditingMode = true
};
return myRatingElement;

View File

@ -1,7 +0,0 @@
<DataGridTemplateColumn xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
x:Class="LibationAvalonia.Controls.DataGridTemplateColumnExt">
</DataGridTemplateColumn>

View File

@ -0,0 +1,15 @@
using Avalonia.Controls;
using System;
using System.Linq;
namespace LibationAvalonia.Controls
{
public partial class DataGridTemplateColumnExt : DataGridTemplateColumn
{
protected override IControl GenerateElement(DataGridCell cell, object dataItem)
{
cell?.AttachContextMenuToCell();
return base.GenerateElement(cell, dataItem);
}
}
}

View File

@ -2,51 +2,53 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
mc:Ignorable="d" d:DesignWidth="115" d:DesignHeight="80"
x:Class="LibationAvalonia.Controls.MyRatingCellEditor">
<Grid ColumnDefinitions="Auto,*" RowDefinitions="Auto,Auto,Auto">
<Grid.Styles>
<Style Selector="TextBlock">
<Setter Property="FontSize" Value="11" />
</Style>
<Style Selector="StackPanel > TextBlock">
<Setter Property="Padding" Value="0,0,-2,0" />
</Style>
</Grid.Styles>
<Panel Background="Transparent" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<Grid Name="ratingsGrid" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="3,0,0,0" ColumnDefinitions="Auto,*" RowDefinitions="Auto,Auto,Auto">
<Grid.Styles>
<Style Selector="TextBlock">
<Setter Property="FontSize" Value="11" />
</Style>
<Style Selector="StackPanel > TextBlock">
<Setter Property="Padding" Value="0,0,-2,0" />
</Style>
</Grid.Styles>
<TextBlock Grid.Column="0" Grid.Row="0" Name="tblockOverall" Text="Overall:" />
<TextBlock Grid.Column="0" Grid.Row="1" Name="tblockPerform" Text="Perform:" />
<TextBlock Grid.Column="0" Grid.Row="2" Name="tblockStory" Text="Story:" />
<TextBlock Grid.Column="0" Grid.Row="0" Name="tblockOverall" Text="Overall:" />
<TextBlock Grid.Column="0" Grid.Row="1" Name="tblockPerform" Text="Perform:" />
<TextBlock Grid.Column="0" Grid.Row="2" Name="tblockStory" Text="Story:" />
<Panel Background="Transparent" PointerExited="Panel_PointerExited" Grid.Column="1" Grid.Row="0">
<StackPanel Name="panelOverall" Orientation="Horizontal">
<TextBlock PointerEntered="Star_PointerEntered" Tapped="Star_Tapped" />
<TextBlock PointerEntered="Star_PointerEntered" Tapped="Star_Tapped" />
<TextBlock PointerEntered="Star_PointerEntered" Tapped="Star_Tapped" />
<TextBlock PointerEntered="Star_PointerEntered" Tapped="Star_Tapped" />
<TextBlock PointerEntered="Star_PointerEntered" Tapped="Star_Tapped" />
</StackPanel>
</Panel>
<Panel Background="Transparent" PointerExited="Panel_PointerExited" Grid.Column="1" Grid.Row="0">
<StackPanel Name="panelOverall" Orientation="Horizontal">
<TextBlock PointerEntered="Star_PointerEntered" Tapped="Star_Tapped" />
<TextBlock PointerEntered="Star_PointerEntered" Tapped="Star_Tapped" />
<TextBlock PointerEntered="Star_PointerEntered" Tapped="Star_Tapped" />
<TextBlock PointerEntered="Star_PointerEntered" Tapped="Star_Tapped" />
<TextBlock PointerEntered="Star_PointerEntered" Tapped="Star_Tapped" />
</StackPanel>
</Panel>
<Panel Background="Transparent" PointerExited="Panel_PointerExited" Grid.Column="1" Grid.Row="1">
<StackPanel Name="panelPerform" Orientation="Horizontal">
<TextBlock PointerEntered="Star_PointerEntered" Tapped="Star_Tapped" />
<TextBlock PointerEntered="Star_PointerEntered" Tapped="Star_Tapped" />
<TextBlock PointerEntered="Star_PointerEntered" Tapped="Star_Tapped" />
<TextBlock PointerEntered="Star_PointerEntered" Tapped="Star_Tapped" />
<TextBlock PointerEntered="Star_PointerEntered" Tapped="Star_Tapped" />
</StackPanel>
</Panel>
<Panel Background="Transparent" PointerExited="Panel_PointerExited" Grid.Column="1" Grid.Row="1">
<StackPanel Name="panelPerform" Orientation="Horizontal">
<TextBlock PointerEntered="Star_PointerEntered" Tapped="Star_Tapped" />
<TextBlock PointerEntered="Star_PointerEntered" Tapped="Star_Tapped" />
<TextBlock PointerEntered="Star_PointerEntered" Tapped="Star_Tapped" />
<TextBlock PointerEntered="Star_PointerEntered" Tapped="Star_Tapped" />
<TextBlock PointerEntered="Star_PointerEntered" Tapped="Star_Tapped" />
</StackPanel>
</Panel>
<Panel Background="Transparent" PointerExited="Panel_PointerExited" Grid.Column="1" Grid.Row="2">
<StackPanel Name="panelStory" Orientation="Horizontal">
<TextBlock PointerEntered="Star_PointerEntered" Tapped="Star_Tapped" />
<TextBlock PointerEntered="Star_PointerEntered" Tapped="Star_Tapped" />
<TextBlock PointerEntered="Star_PointerEntered" Tapped="Star_Tapped" />
<TextBlock PointerEntered="Star_PointerEntered" Tapped="Star_Tapped" />
<TextBlock PointerEntered="Star_PointerEntered" Tapped="Star_Tapped" />
</StackPanel>
</Panel>
</Grid>
<Panel Background="Transparent" PointerExited="Panel_PointerExited" Grid.Column="1" Grid.Row="2">
<StackPanel Name="panelStory" Orientation="Horizontal">
<TextBlock PointerEntered="Star_PointerEntered" Tapped="Star_Tapped" />
<TextBlock PointerEntered="Star_PointerEntered" Tapped="Star_Tapped" />
<TextBlock PointerEntered="Star_PointerEntered" Tapped="Star_Tapped" />
<TextBlock PointerEntered="Star_PointerEntered" Tapped="Star_Tapped" />
<TextBlock PointerEntered="Star_PointerEntered" Tapped="Star_Tapped" />
</StackPanel>
</Panel>
</Grid>
</Panel>
</UserControl>

View File

@ -14,11 +14,8 @@ namespace LibationAvalonia.Controls
AvaloniaProperty.Register<MyRatingCellEditor, Rating>(nameof(Rating));
public bool IsEditingMode { get; set; }
public Rating Rating
{
get { return GetValue(RatingProperty); }
set { SetValue(RatingProperty, value); }
}
public Rating Rating { get => GetValue(RatingProperty); set => SetValue(RatingProperty, value); }
public MyRatingCellEditor()
{
InitializeComponent();
@ -44,16 +41,17 @@ namespace LibationAvalonia.Controls
foreach (TextBlock star in panelStory.Children)
star.Tag = star.Text = Rating.StoryRating > rating++ ? SOLID_STAR : blankValue;
SetVisible(IsEditingMode);
SetVisible();
}
base.OnPropertyChanged(change);
}
private void SetVisible(bool allVisible)
private void SetVisible()
{
tblockOverall.IsVisible = panelOverall.IsVisible = allVisible || Rating?.OverallRating > 0;
tblockPerform.IsVisible = panelPerform.IsVisible = allVisible || Rating?.PerformanceRating > 0;
tblockStory.IsVisible = panelStory.IsVisible = allVisible || Rating?.StoryRating > 0;
ratingsGrid.IsEnabled = IsEditingMode;
tblockOverall.IsVisible = panelOverall.IsVisible = IsEditingMode || Rating?.OverallRating > 0;
tblockPerform.IsVisible = panelPerform.IsVisible = IsEditingMode || Rating?.PerformanceRating > 0;
tblockStory.IsVisible = panelStory.IsVisible = IsEditingMode || Rating?.StoryRating > 0;
}
public void Panel_PointerExited(object sender, Avalonia.Input.PointerEventArgs e)

View File

@ -1,8 +0,0 @@
<DataGridBoundColumn xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="LibationAvalonia.Controls.MyRatingGridColumn">
</DataGridBoundColumn>

View File

@ -131,7 +131,7 @@ namespace LibationAvalonia.Dialogs
var selectedFiles = await StorageProvider.OpenFilePickerAsync(openFileDialogOptions);
var selectedFile = selectedFiles.SingleOrDefault();
if (!selectedFile.TryGetUri(out var uri)) return;
if (selectedFile?.TryGetUri(out var uri) is not true) return;
try
{
@ -291,7 +291,7 @@ namespace LibationAvalonia.Dialogs
var selectedFile = await StorageProvider.SaveFilePickerAsync(options);
if (!selectedFile.TryGetUri(out var uri)) return;
if (selectedFile?.TryGetUri(out var uri) is not true) return;
try
{

View File

@ -51,7 +51,7 @@ namespace LibationAvalonia.Dialogs
{
Title = $"Save Sover Image",
SuggestedStartLocation = new Avalonia.Platform.Storage.FileIO.BclStorageFolder(Environment.GetFolderPath(Environment.SpecialFolder.MyPictures)),
SuggestedFileName = $"{PictureFileName}.jpg",
SuggestedFileName = PictureFileName,
DefaultExtension = "jpg",
ShowOverwritePrompt = true,
FileTypeChoices = new FilePickerFileType[]
@ -62,7 +62,7 @@ namespace LibationAvalonia.Dialogs
var selectedFile = await StorageProvider.SaveFilePickerAsync(options);
if (!selectedFile.TryGetUri(out var uri)) return;
if (selectedFile?.TryGetUri(out var uri) is not true) return;
try
{

View File

@ -34,7 +34,7 @@ namespace LibationAvalonia.Views
var selectedFile = await StorageProvider.SaveFilePickerAsync(options);
if (!selectedFile.TryGetUri(out var uri)) return;
if (selectedFile?.TryGetUri(out var uri) is not true) return;
var ext = System.IO.Path.GetExtension(uri.LocalPath);
switch (ext)

View File

@ -160,8 +160,7 @@
</DataGridTemplateColumn.CellTemplate>
</controls:DataGridTemplateColumnExt>
<controls:MyRatingGridColumn IsReadOnly="false" Width="115" Header="My Rating" CanUserSort="True" SortMemberPath="MyRating" ClipboardContentBinding="{Binding MyRatingString}" Binding="{Binding MyRating, Mode=TwoWay}" />
<controls:DataGridMyRatingColumn IsReadOnly="false" Width="115" Header="My Rating" CanUserSort="True" SortMemberPath="MyRating" ClipboardContentBinding="{Binding MyRatingString}" Binding="{Binding MyRating, Mode=TwoWay}" />
<controls:DataGridTemplateColumnExt Width="135" Header="Misc" CanUserSort="True" SortMemberPath="Misc" ClipboardContentBinding="{Binding Misc}">
<DataGridTemplateColumn.CellTemplate>

View File

@ -71,6 +71,7 @@ namespace LibationAvalonia.Views
AvaloniaXamlLoader.Load(this);
productsGrid = this.FindControl<DataGrid>(nameof(productsGrid));
DataGridContextMenus.CellContextMenuStripNeeded += ProductsGrid_CellContextMenuStripNeeded;
}
#region Cell Context Menu
@ -121,7 +122,7 @@ namespace LibationAvalonia.Views
var selectedFiles = await this.GetParentWindow().StorageProvider.OpenFilePickerAsync(openFileDialogOptions);
var selectedFile = selectedFiles.SingleOrDefault();
if (selectedFile.TryGetUri(out var uri))
if (selectedFile?.TryGetUri(out var uri) is true)
FilePathCache.Insert(entry.AudibleProductId, uri.LocalPath);
}
catch (Exception ex)
@ -179,10 +180,6 @@ namespace LibationAvalonia.Views
foreach (var column in productsGrid.Columns)
{
//Wire up column context menu
if (column is DataGridTemplateColumnExt tc)
tc.CellContextMenuStripNeeded += ProductsGrid_CellContextMenuStripNeeded;
var itemName = column.SortMemberPath;
if (itemName == nameof(GridEntry.Remove))