WinUI3开发记录(3)分类页面增删改查
预览效果
分类列表
编辑弹窗
1. CategoryPage
1.1 创建分类页面 GridView+ScrollViewer
页面布局采用Grid+StackPanel。Grid用于区分顶部添加按钮与下方分类列表,在列表内容超出屏幕时滚动不会影响顶部操作按钮。
<Grid x:Name="ContentArea">
<Grid.RowDefinitions>
<RowDefinition Height="50"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<RelativePanel Grid.Row="0">
<Button x:Uid="Category_Create" Click="CategoryCreate_Click"></Button>
</RelativePanel>
<ScrollViewer Grid.Row="1"
Name="ForegroundElement"
HorizontalAlignment="Stretch"
VerticalScrollMode="Enabled"
IsTabStop="True">
<StackPanel Style="{ThemeResource StackCardPanelStyle}" Background="{ThemeResource CardBackgroundFillColorDefaultBrush}">
<GridView x:Name="CategoryList"
Margin="{StaticResource SmallTopMargin}"
ItemTemplate="{StaticResource CategoryGridViewTemplate}"
ItemsSource="{x:Bind ViewModel.CategoryList,Mode=OneWay}"
BorderThickness="0"
BorderBrush="{ThemeResource SystemControlForegroundBaseMediumLowBrush}"
MinWidth="400"
HorizontalAlignment="Left"/>
</StackPanel>
</ScrollViewer>
</Grid>
1.2 GridView自定义展示效果
通过自定义ItemTemplate来实现GridView的展示效果,通过Grid布局实现上方显示图片,下方显示分类名称,并用InfoBadge来实现分类颜色的展示,注意设置宽高属性和Magrin。由于分类图片我统一从emoji下载的高清图240*240,这里图片就采用的80*80的尺寸。
<DataTemplate x:Key="CategoryGridViewTemplate" x:DataType="model:CategoryDto">
<Grid Margin="{StaticResource SmallLeftRightMargin}" ContextRequested="CategoryList_ContextRequested">
<Grid.RowDefinitions>
<RowDefinition Height="90"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="16"/>
<ColumnDefinition Width="100"/>
</Grid.ColumnDefinitions>
<Image Stretch="Fill" Height="80" Width="80" Source="{x:Bind Icon}" Grid.ColumnSpan="2" Margin="5"/>
<InfoBadge x:Name="infoBadge2" Style="{StaticResource AttentionIconInfoBadgeStyle}" Grid.Row="1" Background="{x:Bind Color}" />
<TextBlock Grid.Row="1" Grid.Column="1"
Text="{x:Bind Name}"
x:Phase="1"
HorizontalAlignment="Center"
HorizontalTextAlignment="Center"
Margin="{StaticResource SmallTopBottomMargin}"/>
</Grid>
</DataTemplate>
1.3 分类右键点击菜单 CommandBarFlyout
按钮的文字绑定多语言资源,通过x:Uid
绑定,如AppBarButton中显示文本为Label,对应在Resources.resw中配置key为Button_Edit.Label。其他类似,如xxx.Content、xxx.Text。
右键菜单通过ContextRequested绑定到想要触发的元素上。
<CommandBarFlyout Placement="Right" x:Name="CategoryCommandBarFlayout">
<CommandBarFlyout.SecondaryCommands>
<AppBarButton x:Uid="Button_Edit" Icon="Edit" Click="AppBarButton_Edit_Click" />
<AppBarButton x:Uid="Button_Delete" Icon="Delete" Click="AppBarButton_Delete_Click" />
</CommandBarFlyout.SecondaryCommands>
</CommandBarFlyout>
后台方法实现
// 延迟关闭右键菜单
private void DelayCloseFlyout()
{
Task.Delay(10).ContinueWith(_ => CategoryCommandBarFlayout.Hide(), TaskScheduler.FromCurrentSynchronizationContext());
}
// 显示右键菜单
private void ShowMenu(bool isTransient, UIElement element)
{
FlyoutShowOptions myOption = new FlyoutShowOptions();
myOption.ShowMode = isTransient ? FlyoutShowMode.Transient : FlyoutShowMode.Standard;
CategoryCommandBarFlayout.ShowAt(element, myOption);
}
2. CategoryViewModel
新建SelectedCatgeory,用于绑定分类列表选中的对象,方便后续删改更新页面。分类列表使用ObservableCollection,可以实时更新页面。
注:数据请求更新使用EFCore.Sqlite
public class CategoryViewModel : ObservableRecipient
{
private readonly IMapper _mapper;
public CategoryDto SelectedCategory
{
get; set;
}
public ObservableCollection<CategoryDto> CategoryList
{
get; private set;
}
public CategoryViewModel()
{
_mapper = App.GetService<IMapper>();
SelectedCategory = new();
CategoryList = new();
ListCategories();
}
public void ListCategories()
{
CategoryList.Clear();
using var context = new ApplicationDbContext();
var list = _mapper.Map<List<CategoryDto>>(context.CategoryModels.ToList());
foreach (var item in list)
{
CategoryList.Add(item);
}
}
// 修改后重载页面数据,实现无刷新更新
public void ListReload(CategoryModel newCategory)
{
var newDto = _mapper.Map<CategoryDto>(newCategory);
if (newCategory.ID > 0)
{
CategoryList.Remove(SelectedCategory);
}
CategoryList.Add(newDto);
}
public void AddCategory(CategoryModel category)
{
using var context = new ApplicationDbContext();
context.Add(category);
context.SaveChanges();
}
public void UpdateCategory(CategoryModel category)
{
using var context = new ApplicationDbContext();
context.Update(category);
context.SaveChanges();
}
public void DeleteCategory(int id)
{
using var context = new ApplicationDbContext();
var deleteModel = context.Find<CategoryModel>(id);
if (deleteModel != null)
{
context.CategoryModels.Remove(deleteModel);
context.SaveChanges();
}
}
public CategoryModel? FindCategory(int id)
{
using var context = new ApplicationDbContext();
var model = context.Find<CategoryModel>(id);
return model;
}
}
3. 弹窗编辑功能实现
参考WinUI 3 Gallery实现,自建一个CategoryModifyDialog页面,绑定到ContentDialog的Content中,通过发送当前选中的Category来传递数据。
private async void OpenModifyModal(CategoryModel? category)
{
var dialog = new ContentDialog
{
// XamlRoot must be set in the case of a ContentDialog running in a Desktop app
XamlRoot = this.XamlRoot,
Style = Application.Current.Resources["DefaultContentDialogStyle"] as Style,
Title = (category == null || category.ID == 0) ? "新增" : "编辑",
PrimaryButtonText = "Save",
CloseButtonText = "Cancel",
DefaultButton = ContentDialogButton.Primary,
Content = new CategoryModifyDialog(category)
};
dialog.PrimaryButtonClick += Dialog_PrimaryButtonClick;
var result = await dialog.ShowAsync();
}
private void Dialog_PrimaryButtonClick(ContentDialog sender, ContentDialogButtonClickEventArgs args)
{
var model = ((CategoryModifyDialog)sender.Content).CurrentCategory;
if (model.ID > 0)
{
ViewModel.UpdateCategory(model);
}
else
{
ViewModel.AddCategory(model);
}
ViewModel.ListReload(model);
}
4. 弹窗页面实现
<Page.Resources>
<x:Double x:Key="SwatchSize">32</x:Double>
</Page.Resources>
<StackPanel VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
<!-- Content body -->
<RelativePanel>
<SplitButton x:Name="colorButton">
<Border x:Name="CurrentColor" Width="26" Height="24" Background="{x:Bind CurrentCategory.Color,Mode=TwoWay}" CornerRadius="5"/>
<SplitButton.Flyout>
<Flyout Placement="Bottom">
<GridView ItemClick="GridView_ItemClick" IsItemClickEnabled="True">
<GridView.ItemsPanel>
<ItemsPanelTemplate>
<ItemsWrapGrid MaximumRowsOrColumns="3" Orientation="Horizontal"/>
</ItemsPanelTemplate>
</GridView.ItemsPanel>
<GridView.Resources>
<Style TargetType="Rectangle">
<Setter Property="Width" Value="{StaticResource SwatchSize}"/>
<Setter Property="Height" Value="{StaticResource SwatchSize}"/>
<Setter Property="RadiusX" Value="4"/>
<Setter Property="RadiusY" Value="4"/>
</Style>
</GridView.Resources>
<GridView.Items>
<Rectangle Fill="BlueViolet"/>
<Rectangle Fill="Violet"/>
<Rectangle Fill="Red"/>
<Rectangle Fill="OrangeRed"/>
<Rectangle Fill="Orange"/>
<Rectangle Fill="Yellow"/>
<Rectangle Fill="DarkCyan"/>
<Rectangle Fill="ForestGreen"/>
<Rectangle Fill="Gray"/>
</GridView.Items>
</GridView>
</Flyout>
</SplitButton.Flyout>
</SplitButton>
<TextBox Header="" Text="{x:Bind CurrentCategory.Name,Mode=TwoWay}" PlaceholderText="Enter Category name" Width="300" Margin="{StaticResource SmallLeftRightMargin}" RelativePanel.RightOf="colorButton" />
</RelativePanel>
<TextBlock Text="CategoryIcon" Margin="{StaticResource SmallTopBottomMargin}"></TextBlock>
<GridView ItemClick="CategoryIcon_ItemClick" SelectedValue="{x:Bind CurrentCategory.IconFile}" x:Name="CategoryIcon" IsItemClickEnabled="True">
<GridView.ItemsPanel>
<ItemsPanelTemplate>
<ItemsWrapGrid MaximumRowsOrColumns="5" Orientation="Horizontal"/>
</ItemsPanelTemplate>
</GridView.ItemsPanel>
<GridView.ItemTemplate>
<DataTemplate x:DataType="models:CategoryIconItem">
<Image Source="{x:Bind IconFile}" Width="64" Margin="5"></Image>
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
</StackPanel>
如果新增时,需要给Color设置默认值,防止报错。
public CategoryModifyDialog(CategoryModel model)
{
this.InitializeComponent();
LoadCategoryIconView();
if (model == null || model.ID == 0)
{
CurrentCategory = new CategoryModel
{
Name = "",
Color = "#95a5a6",
IconFile = ""
};
}
else
{
CurrentCategory = model;
}
}
本文链接:
/archives/1713427874914
版权声明:
本站所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自
不爱思考!
喜欢就支持一下吧
打赏
微信
支付宝