如何动态更改列表中基于按钮的值的图标?

Posted

技术标签:

【中文标题】如何动态更改列表中基于按钮的值的图标?【英文标题】:How to dynamically change the icon on a button based value in a list? 【发布时间】:2021-12-08 14:50:28 【问题描述】:

我有以下 xaml 代码:

                <ListView.ItemTemplate>
                    <DataTemplate>
                        <ViewCell>
                            <ViewCell.ContextActions>
                                <MenuItem Text="Check In"
                                      Clicked="CheckInFile"/>
                                <MenuItem Text="Check Out"
                                      Clicked="CheckOutFile"/>
                                <MenuItem Text="Download"
                                      Clicked="DownloadFile"/>
                                <MenuItem Text="Upload Local Copy"
                                      Clicked="UploadFile"/>
                            </ViewCell.ContextActions>

                            <Grid>
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition Width="Auto" />
                                    <ColumnDefinition Width="Auto" />
                                </Grid.ColumnDefinitions>
                                <Grid.RowDefinitions>
                                    <RowDefinition Height="30" />
                                    <RowDefinition Height="30" />
                                </Grid.RowDefinitions>

                                <Label Grid.Column="0" Text="Binding Path=DriveItem.Name"
                                   FontSize="Small" />
                                <Label Grid.Column="1""
                                    FontFamily="Segoe MDL2 Assets" 
                                       Text="Binding PublicationStatus"
                                     />
                            </Grid>
                        </ViewCell>

                    </DataTemplate>
                </ListView.ItemTemplate>

以及相关的cs代码:

   protected override async void OnAppearing()
    

        var directoryContents = await App.GraphClient.Sites[siteID].Lists[sharedDocsDriveId]
            .Items
            .Request()
            //.Expand(item => item.DriveItem)
            .Expand("driveItem($select=publication,name,id,description,file,webUrl)")
            .GetAsync();

        SharedDocumentList.ItemsSource = directoryContents.CurrentPage.ToList();
      

对于返回的每个项目,它都包含有关文件的信息 - 如果当前已签出。该字段是“级别”,如下所示/

directoryContents.CurrentPage[i].DriveItem.Publication
Microsoft.Graph.PublicationFacet
    AdditionalData: null
    Level: "checkout"
    ODataType: null
    VersionId: "4.0"

如果 Level 的值为“checkout”,我想使用以下方法显示锁定图标: https://docs.microsoft.com/en-us/windows/apps/design/style/segoe-ui-symbol-font 但如果它是“已发布”,我想使用解锁图标。

是否有一种简单的方法可以在 XAML 中执行某种 IF 语句来评估 DriveItem.Publication.Level 的值,然后显示相应的图标?我开始在我的代码隐藏中公开一个名为publicationStatus的新属性,但是......也许这有点矫枉过正。我觉得有一种我没有想到的更简单的方法?

编辑 1

所以我更新了 xaml 以使用 datatrigger 方法,但我收到错误,即在类型 BindingExtension 中找不到属性“RelativeSource”。

            <ListView x:Name="SharedDocumentList"
                  HasUnevenRows="true"
                 >
                <ListView.Resources>
                    <Style x:Key="PublicationStatus" TargetType="Label">
                        <Setter Property="FontFamily" Value="Segoe MDL2 Assets" />
                        <Style.Triggers>
                            <DataTrigger Binding="Binding Path=Tag, RelativeSource=RelativeSource Self"
                                 Value="checkout">
                                <Setter Property="Text" Value="\uE701"/>
                            </DataTrigger>
                            <DataTrigger Binding="Binding Path=Tag, RelativeSource=RelativeSource Self"
                                Value="published">
                                <Setter Property="Text" Value="\uE702"/>
                            </DataTrigger>
                        </Style.Triggers>
                    </Style>
                </ListView.Resources>

                <ListView.ItemTemplate>
                    <DataTemplate>
                        <ViewCell>
                            <ViewCell.ContextActions>
                                <MenuItem Text="Check In"
                                      Clicked="CheckInFile"/>
                                <MenuItem Text="Check Out"
                                      Clicked="CheckOutFile"/>
                                <MenuItem Text="Download"
                                      Clicked="DownloadFile"/>
                                <MenuItem Text="Upload Local Copy"
                                      Clicked="UploadFile"/>
                            </ViewCell.ContextActions>

                            <Grid>
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition Width="Auto" />
                                    <ColumnDefinition Width="Auto" />
                                </Grid.ColumnDefinitions>
                                <Grid.RowDefinitions>
                                    <RowDefinition Height="30" />
                                    <RowDefinition Height="30" />
                                </Grid.RowDefinitions>

                                <Label Grid.Column="0" Text="Binding Path=DriveItem.Name"
                                   FontSize="Small" />
                                <Label Grid.Column="1"
                                   Style="StaticResource PublicationStatus"
                                   Tag="Binding PublicationStatus" />
                            </Grid>
                        </ViewCell>
                    </DataTemplate>
                </ListView.ItemTemplate>
            </ListView>

编辑 2

这是我使用 ValueConverter 的尝试。

下面是该类的部分代码:

[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class SPDocumentLibraryContentsPage : ContentPage

    public string IconValue  get; set; 
    public SPDocumentLibraryContentsPage()
    
        InitializeComponent();
        IconValue = "checkout";
        //this.DataContext doesn't exist.
    

Xaml 页面上的 ListView 如下所示:

                            <Grid>
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition Width="Auto" />
                                    <ColumnDefinition Width="Auto" />
                                </Grid.ColumnDefinitions>
                                <Grid.RowDefinitions>
                                    <RowDefinition Height="30" />
                                    <RowDefinition Height="30" />
                                </Grid.RowDefinitions>

                                <Label Grid.Column="0" Text="Binding Path=DriveItem.Name"
                                   FontSize="Small" />
                                <Label x:Name="testBlock" Grid.Column="2"                                      
                                  Text="Binding IconValue,Converter=StaticResource IconValueConverter" FontFamily="Segoe MDL2 Assets" />
                            </Grid>
                        </ViewCell>
                    </DataTemplate>
                </ListView.ItemTemplate>
            </ListView>

而且我能够毫无问题地创建 IconConverter 类。 这里只是一个sn-p:

 namespace GraphTutorial.Models
 
     public class IconValueConverter : Xamarin.Forms.IValueConverter
     
     

编辑 3

为了得到工作的答案,我做了以下工作:

 <Label Grid.Column="0" Text="Binding Path=DriveItem.Name" FontSize="Small" />
 <Label Grid.Column="1" Text="Binding Path=DriveItem.Publication.Level,Converter=StaticResource IconValueConverter" FontFamily="Segoe MDL2 Assets" />

【问题讨论】:

【参考方案1】:

您的应用似乎是 Xamarin UWP 应用,而不是本机 UWP 应用。

您也可以在使用绑定时尝试使用ValueConverter。您需要做的是创建一个 ValueConverter 类,并制定自己的逻辑,将不同的字符串转换为 ValueConverter 中的不同图标。 之后,您只需要在绑定中使用 ValueConverter 作为参数即可。

这是我在原生 UWP 应用中测试的示例代码。它应该在 Xamarin UWP 应用程序中工作。您需要将Textblock 替换为Label

代码隐藏:

 public class IconValueConverter: IValueConverter

    public object Convert(object value, Type targetType, object parameter, string language)
    
        string OutputValue ;

        string textvalue = value as string;
        if (textvalue.Equals("checkout"))
        
            OutputValue = "\uE701";
        
        else if (textvalue.Equals("published"))
        
            OutputValue = "\uE702";
        
        else 
        
            OutputValue = "\uE703";
        


        return OutputValue;
    

    public object ConvertBack(object value, Type targetType, object parameter, string language)
    
        throw new NotImplementedException();
    

主页:

 public string IconValue  get; set;

    public MainPage()
    
        this.InitializeComponent();

        IconValue = "checkout";

        this.BindingContext = this;
    

Xaml 代码:

  <Page.Resources>
    <local:IconValueConverter x:Key="IconValueConverter"/>
</Page.Resources>

<Grid>
    <TextBlock x:Name="MyTextBlcok" Text="Binding IconValue,Converter=StaticResource IconValueConverter" FontFamily="Segoe MDL2 Assets" />
</Grid>

【讨论】:

李,我已经尝试实现....唯一不起作用的是“this.DataContext=this;”线。我没有可用的属性/字段。请参阅编辑 2... 我将很快添加。但是当我构建时没有错误......但是gui上也没有任何显示。 :) 是的,它是一个 Xamarin Forms UWP 应用 @dot 好的,这是一个 Xamarin UWP 应用。所以在 Xamarin 中应该是 this.BindingContext=this。我也会更新我的答案【参考方案2】:

有一个聪明的方法可以通过TriggerTag 属性来实现这一点,以避免使用IValueConverter 或从Style 内部访问父DataContext

在列表视图或根元素内

<ListView.Resources>
    <Style x:Key="PublicationStatus" TargetType="Label">        
        <Setter Property="FontFamily" Value="Segoe MDL2 Assets" />
        <Style.Triggers>
            <Trigger Property="Tag"
                     Value="checkout">
                <Setter Property="Text" Value="\uE701"/>
            </Trigger>
           <Trigger Property="Tag"
                    Value="published">
                <Setter Property="Text" Value="\uE702"/>
           </Trigger>
        </Style.Triggers>
    </Style>
</ListView.Resources>

然后在代码中:

<Label Grid.Column="1"
       Style="StaticResource PublicationStatus"
       Tag="Binding PublicationStatus" />

你也可以重用一个样式并将其放入一些ResourceDictionary

警告。未测试。

【讨论】:

所以......我回来的错误是在“BindingExtension”类型中找不到“RelativeSource” 查看我的编辑 1 @dot 对此我深表歉意。请查看更新的答案 不用担心。我尝试了您更新的解决方案,它也爆炸了。错误是我“缺少“Xamarin.Forms.Trigger”上的强制属性“TargetType”。所以我在两个 元素上都添加了该属性,但随后它抱怨标签对于标签来说是不合法的。

以上是关于如何动态更改列表中基于按钮的值的图标?的主要内容,如果未能解决你的问题,请参考以下文章

如何创建多个从同一个数组中获取值的动态下拉列表,而无需更改 Javascript 中的其他下拉列表

动态更改 jQuery Mobile 列表视图中的图标

Flutter 动态更改应用程序启动图标

如何将动态图片变成鼠标指针?

如何在 onPressed() 中动态更改凸起按钮的背景颜色

Vue Storybook 动态故事