在运行时访问和修改 UWP C++/CX 应用程序中 Button 的子项
Access and modify child items of Button in UWP C++/CX app at runtime
我是 UWP Xaml C++/CX 开发的新手,所以如果我使用了错误的术语,我深表歉意。
我正在尝试制作 image/photo 缩略图 select离子托盘。用户 select 浏览哪个文件夹,内容显示在可滚动的缩略图托盘中,文件名显示在下方。
页面是在 xaml 中构建的,我使用的是 C++/CX。缩略图托盘是使用以下 xaml
构建的
<ScrollViewer Grid.Row="1" Margin="20,20,20,20" ScrollViewer.VerticalScrollBarVisibility="Hidden">
<Grid x:Name="thumb_grid">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
</Grid.RowDefinitions>
</Grid>
</ScrollViewer>
我使用
通过代码动态添加新行
AddRow() {
RowDefinition^ rd = ref new RowDefinition();
rd->Height.Auto;
thumb_grid->RowDefinitions->Append(rd);
}
然后我使用
用新的 Button 填充每个网格元素
AddImageButton(int row, int col) {
Button^ b = ref new Button();
auto style = R->Lookup("ButtonStyle1");
b->Style = safe_cast<Windows::UI::Xaml::Style^>(style);
thumb_grid->Children->Append(b);
thumb_grid->SetRow(b, row);
thumb_grid->SetColumn(b, col);
}
其中 "ButtonStyle1" 在我的 dictionary.xaml 中定义为
<Style x:Key="ButtonStyle1" TargetType="Button">
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Foreground" Value="{ThemeResource SystemControlForegroundBaseHighBrush}"/>
<Setter Property="BorderBrush" Value="{ThemeResource SystemControlForegroundTransparentBrush}"/>
<Setter Property="BorderThickness" Value="{ThemeResource ButtonBorderThemeThickness}"/>
<Setter Property="Padding" Value="8,4,8,4"/>
<Setter Property="Margin" Value="10"/>
<Setter Property="HorizontalAlignment" Value="Stretch"/>
<Setter Property="VerticalAlignment" Value="Stretch"/>
<Setter Property="FontFamily" Value="{ThemeResource ContentControlThemeFontFamily}"/>
<Setter Property="FontWeight" Value="Normal"/>
<Setter Property="FontSize" Value="{ThemeResource ControlContentThemeFontSize}"/>
<Setter Property="UseSystemFocusVisuals" Value="True"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Grid x:Name="RootGrid" Background="{TemplateBinding Background}">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<VisualStateManager.VisualStateGroups>
<!--REMOVED THIS SECTION TO REDUCE EXAMPLE CODE-->
</VisualStateManager.VisualStateGroups>
<ContentPresenter x:Name="ContentPresenter" AutomationProperties.AccessibilityView="Raw"
BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}"
ContentTemplate="{TemplateBinding ContentTemplate}" ContentTransitions="{TemplateBinding ContentTransitions}"
Content="{TemplateBinding Content}" HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
Padding="{TemplateBinding Padding}" VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"/>
<Image x:Name="thumb_image" Grid.Row="0" HorizontalAlignment="Stretch" Source="Assets/demo.jpg"/>
<TextBlock x:Name="thumb_filename" Grid.Row="1" Text="demo.jpg" FontSize="20" Foreground="White"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
TextAlignment="Center"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
所有这些都会创建所需的输出,如下图所示。显然,我目前只是为按钮内容使用硬编码图像和文本。
问题
问题是如何动态更改自定义图像按钮的内容?
目前我可以通过按名称访问内容来更改按钮内的图像。然而,这要求按钮的图像内容具有唯一的名称。
Xaml代码
<Button x:Name="btnToggleShowHide" Grid.Row="1" Height="50" Width="50"
HorizontalAlignment="Left" VerticalAlignment="Bottom"
Background="Transparent"
Click="btnToggleShowHide_Click">
<Image x:Name="imgToggleShowHideBtn"
Source="Assets/Graphics/show.png"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"/>
</Button>
以及换图的C++/CX代码(不含实际逻辑,仅展示使用的代码)
show = ref new BitmapImage(ref new Uri(imgToggleShowHideBtn->BaseUri->RawUri, "Assets/Graphics/show.png"));
hide = ref new BitmapImage(ref new Uri(imgToggleShowHideBtn->BaseUri->RawUri, "Assets/Graphics/hide.png"));
imgToggleShowHideBtn->Source = show;
imgToggleShowHideBtn->Source = hide;
但是我无法使用自定义按钮图像 "demo.jpg" 中的名称直接访问文本
thumb_filename->Text = "test.jpg";
因为文本块 thumb_filename 仅在运行时存在。在 AddImageButton() 中,我需要以某种方式设置内容,但不知道如何访问按钮中的子对象。在我看来,我想做类似
的事情
Button^ b = ref new Button();
auto style = R->Lookup("ButtonStyle1");
b->Style = safe_cast<Windows::UI::Xaml::Style^>(style);
//NOT ACTUAL CODE - THIS IS WHAT I'M TRYIN TO ACHIEVE
b->Image->Source = img; //obviously wont work because it has no knowledge whether ButtonStyle1 contains an image
b->TextBlock->Text = filename; //obviously wont work because it has no knowledge whether ButtonStyle1 contains a textblock
所以我最终使用了 Nico Zhu - MSFT 建议的方法,并使用 GridView 和数据绑定。
首先我创建了一个按钮class(注意:我还在完善中,所以可能会有一些多余的片段)
namespace Models {
[Windows::UI::Xaml::Data::Bindable]
public ref class FileBrowser sealed
{
private:
Platform::String^ _fname;
Platform::String^ _path;
ImageSource^ _thumbImage;
BitmapImage^ _imagedata;
public:
FileBrowser();
property Platform::String^ Filename
{
Platform::String^ get()
{
return _fname;
}
void set(Platform::String^ value)
{
_fname = value;
}
}
property Platform::String^ Filepath
{
Platform::String^ get()
{
return _path;
}
void set(Platform::String^ value)
{
_path = value;
}
}
property ImageSource^ ThumbImage
{
ImageSource^ get()
{
return _thumbImage;
}
void set(ImageSource^ value)
{
_thumbImage = value;
}
}
property BitmapImage^ ImageData
{
BitmapImage^ get()
{
return _imagedata;
}
void set(BitmapImage^ value)
{
_imagedata = value;
}
}
};
}
将#include "FileBrowser.h" 添加到 "MainPage.xaml.h"。在包含图像 browser/list 的 View.xaml 页面中,将 xmlns:local="using:Models" 添加到标签中。
我的GridView是按以下方式创建的
<GridView x:Name="thumb_grid" Grid.Row="1" Margin="20,20,20,20" IsItemClickEnabled="True" SelectionMode="Single" ItemClick="thumb_grid_ItemClick">
<GridView.ItemTemplate>
<DataTemplate>
<Grid MaxHeight="200" MinHeight="200" MinWidth="200" MaxWidth="200">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="auto"/>
</Grid.RowDefinitions>
<Image Grid.Row="0" Source="{Binding ImageData}"/>
<TextBlock Text="{Binding Filename}" Grid.Row="1" FontSize="20" Foreground="Gray" VerticalAlignment="Center" HorizontalAlignment="Center"/>
</Grid>
</DataTemplate>
</GridView.ItemTemplate>
<GridView.Items>
</GridView.Items>
</GridView>
在运行时使用(f 和 I 提供相关文件和图像数据)
将一个新按钮添加到 GridView
auto btn = ref new Models::FileBrowser();
btn->Filename = f->GetAt(i)->DisplayName + f->GetAt(i)->FileType;
btn->Filepath = f->GetAt(i)->Path;
btn->ImageData = I;
thumb_grid->Items->Append(btn);
这现在会生成显示文件夹内容的所需图像托盘。每个图像 clickable/touchable 并调用相同的函数,在这种情况下,GridView 中的每个项目在按下时调用 thumb_grid_ItemClick()。
按钮的数据可以使用以下方法获取
void View::thumb_grid_ItemClick(Platform::Object^ sender, Windows::UI::Xaml::Controls::ItemClickEventArgs^ e)
{
auto btn = (Models::FileBrowser^)e->ClickedItem;
}
我是 UWP Xaml C++/CX 开发的新手,所以如果我使用了错误的术语,我深表歉意。
我正在尝试制作 image/photo 缩略图 select离子托盘。用户 select 浏览哪个文件夹,内容显示在可滚动的缩略图托盘中,文件名显示在下方。
页面是在 xaml 中构建的,我使用的是 C++/CX。缩略图托盘是使用以下 xaml
构建的<ScrollViewer Grid.Row="1" Margin="20,20,20,20" ScrollViewer.VerticalScrollBarVisibility="Hidden">
<Grid x:Name="thumb_grid">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
</Grid.RowDefinitions>
</Grid>
</ScrollViewer>
我使用
通过代码动态添加新行AddRow() {
RowDefinition^ rd = ref new RowDefinition();
rd->Height.Auto;
thumb_grid->RowDefinitions->Append(rd);
}
然后我使用
用新的 Button 填充每个网格元素AddImageButton(int row, int col) {
Button^ b = ref new Button();
auto style = R->Lookup("ButtonStyle1");
b->Style = safe_cast<Windows::UI::Xaml::Style^>(style);
thumb_grid->Children->Append(b);
thumb_grid->SetRow(b, row);
thumb_grid->SetColumn(b, col);
}
其中 "ButtonStyle1" 在我的 dictionary.xaml 中定义为
<Style x:Key="ButtonStyle1" TargetType="Button">
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Foreground" Value="{ThemeResource SystemControlForegroundBaseHighBrush}"/>
<Setter Property="BorderBrush" Value="{ThemeResource SystemControlForegroundTransparentBrush}"/>
<Setter Property="BorderThickness" Value="{ThemeResource ButtonBorderThemeThickness}"/>
<Setter Property="Padding" Value="8,4,8,4"/>
<Setter Property="Margin" Value="10"/>
<Setter Property="HorizontalAlignment" Value="Stretch"/>
<Setter Property="VerticalAlignment" Value="Stretch"/>
<Setter Property="FontFamily" Value="{ThemeResource ContentControlThemeFontFamily}"/>
<Setter Property="FontWeight" Value="Normal"/>
<Setter Property="FontSize" Value="{ThemeResource ControlContentThemeFontSize}"/>
<Setter Property="UseSystemFocusVisuals" Value="True"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Grid x:Name="RootGrid" Background="{TemplateBinding Background}">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<VisualStateManager.VisualStateGroups>
<!--REMOVED THIS SECTION TO REDUCE EXAMPLE CODE-->
</VisualStateManager.VisualStateGroups>
<ContentPresenter x:Name="ContentPresenter" AutomationProperties.AccessibilityView="Raw"
BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}"
ContentTemplate="{TemplateBinding ContentTemplate}" ContentTransitions="{TemplateBinding ContentTransitions}"
Content="{TemplateBinding Content}" HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
Padding="{TemplateBinding Padding}" VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"/>
<Image x:Name="thumb_image" Grid.Row="0" HorizontalAlignment="Stretch" Source="Assets/demo.jpg"/>
<TextBlock x:Name="thumb_filename" Grid.Row="1" Text="demo.jpg" FontSize="20" Foreground="White"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
TextAlignment="Center"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
所有这些都会创建所需的输出,如下图所示。显然,我目前只是为按钮内容使用硬编码图像和文本。
问题
问题是如何动态更改自定义图像按钮的内容?
目前我可以通过按名称访问内容来更改按钮内的图像。然而,这要求按钮的图像内容具有唯一的名称。
Xaml代码
<Button x:Name="btnToggleShowHide" Grid.Row="1" Height="50" Width="50"
HorizontalAlignment="Left" VerticalAlignment="Bottom"
Background="Transparent"
Click="btnToggleShowHide_Click">
<Image x:Name="imgToggleShowHideBtn"
Source="Assets/Graphics/show.png"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"/>
</Button>
以及换图的C++/CX代码(不含实际逻辑,仅展示使用的代码)
show = ref new BitmapImage(ref new Uri(imgToggleShowHideBtn->BaseUri->RawUri, "Assets/Graphics/show.png"));
hide = ref new BitmapImage(ref new Uri(imgToggleShowHideBtn->BaseUri->RawUri, "Assets/Graphics/hide.png"));
imgToggleShowHideBtn->Source = show;
imgToggleShowHideBtn->Source = hide;
但是我无法使用自定义按钮图像 "demo.jpg" 中的名称直接访问文本
thumb_filename->Text = "test.jpg";
因为文本块 thumb_filename 仅在运行时存在。在 AddImageButton() 中,我需要以某种方式设置内容,但不知道如何访问按钮中的子对象。在我看来,我想做类似
的事情Button^ b = ref new Button();
auto style = R->Lookup("ButtonStyle1");
b->Style = safe_cast<Windows::UI::Xaml::Style^>(style);
//NOT ACTUAL CODE - THIS IS WHAT I'M TRYIN TO ACHIEVE
b->Image->Source = img; //obviously wont work because it has no knowledge whether ButtonStyle1 contains an image
b->TextBlock->Text = filename; //obviously wont work because it has no knowledge whether ButtonStyle1 contains a textblock
所以我最终使用了 Nico Zhu - MSFT 建议的方法,并使用 GridView 和数据绑定。
首先我创建了一个按钮class(注意:我还在完善中,所以可能会有一些多余的片段)
namespace Models {
[Windows::UI::Xaml::Data::Bindable]
public ref class FileBrowser sealed
{
private:
Platform::String^ _fname;
Platform::String^ _path;
ImageSource^ _thumbImage;
BitmapImage^ _imagedata;
public:
FileBrowser();
property Platform::String^ Filename
{
Platform::String^ get()
{
return _fname;
}
void set(Platform::String^ value)
{
_fname = value;
}
}
property Platform::String^ Filepath
{
Platform::String^ get()
{
return _path;
}
void set(Platform::String^ value)
{
_path = value;
}
}
property ImageSource^ ThumbImage
{
ImageSource^ get()
{
return _thumbImage;
}
void set(ImageSource^ value)
{
_thumbImage = value;
}
}
property BitmapImage^ ImageData
{
BitmapImage^ get()
{
return _imagedata;
}
void set(BitmapImage^ value)
{
_imagedata = value;
}
}
};
}
将#include "FileBrowser.h" 添加到 "MainPage.xaml.h"。在包含图像 browser/list 的 View.xaml 页面中,将 xmlns:local="using:Models" 添加到标签中。
我的GridView是按以下方式创建的
<GridView x:Name="thumb_grid" Grid.Row="1" Margin="20,20,20,20" IsItemClickEnabled="True" SelectionMode="Single" ItemClick="thumb_grid_ItemClick">
<GridView.ItemTemplate>
<DataTemplate>
<Grid MaxHeight="200" MinHeight="200" MinWidth="200" MaxWidth="200">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="auto"/>
</Grid.RowDefinitions>
<Image Grid.Row="0" Source="{Binding ImageData}"/>
<TextBlock Text="{Binding Filename}" Grid.Row="1" FontSize="20" Foreground="Gray" VerticalAlignment="Center" HorizontalAlignment="Center"/>
</Grid>
</DataTemplate>
</GridView.ItemTemplate>
<GridView.Items>
</GridView.Items>
</GridView>
在运行时使用(f 和 I 提供相关文件和图像数据)
将一个新按钮添加到 GridViewauto btn = ref new Models::FileBrowser();
btn->Filename = f->GetAt(i)->DisplayName + f->GetAt(i)->FileType;
btn->Filepath = f->GetAt(i)->Path;
btn->ImageData = I;
thumb_grid->Items->Append(btn);
这现在会生成显示文件夹内容的所需图像托盘。每个图像 clickable/touchable 并调用相同的函数,在这种情况下,GridView 中的每个项目在按下时调用 thumb_grid_ItemClick()。
按钮的数据可以使用以下方法获取
void View::thumb_grid_ItemClick(Platform::Object^ sender, Windows::UI::Xaml::Controls::ItemClickEventArgs^ e)
{
auto btn = (Models::FileBrowser^)e->ClickedItem;
}