在绑定到 ListView 之前从 ViewModel 修改 属性

Modify property from ViewModel before binding to ListView

我正在使用 Prism MVVM 将 ItemSource 绑定到 ListView。这是列表 Cell

<ListView x:Name="list1" ItemsSource="{Binding StudentList}">
<ListView.ItemTemplate >
    <DataTemplate>
        <ViewCell>
            <StackLayout>
                <Label VerticalTextAlignment="Center"  
                       Text="{Binding StudentName}" />
                <Button x:Name="mybtn"         
                    BindingContext="{Binding Source={x:Reference list1}, Path=BindingContext}" 
                    Command="{Binding BtnTextCommand}" 
                    CommandParameter="{Binding Source={x:Reference mybtn}}"  
                    Text="{Binding BtnText}" />
            </StackLayout>                  
        </ViewCell>
    </DataTemplate>
</ListView.ItemTemplate>
</ListView>

这是 ViewModel

中的来源
private List<Student> _studentList;
public List<Student> StudentList
{
    get { return _studentList; }
    set { SetProperty(ref _studentList, value); }
}

我想在绑定之前为每个列表项每次修改按钮 Text。我怎样才能从 ViewModel Class 获取 BtnText 的更新值?

修改值表示如果Text有ID value则显示'Present'如果为空则显示'Absent'等

学生Class

public class Student
{
    public Mychildren MyKid { get; set; }
    public string LocalStudentId { get; set; }
    public int? StudentId { get; set; }
    public string StudentName { get; set; }
    public int? AttendanceTypeStatusId { get; set; }
    public int? StudentDailyAttendanceId { get; set; }
    public int? AbsentReasonId { get; set; }
    public string AttendanceTypeStatusCD { get; set; }}
}

编辑:

我已经在 Converter 中编写了这个逻辑,在 value

的第一 else 部分抛出异常
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
    string attStatusId = string.Empty;
    //AttendanceTypeStatusId
    if (value != null)
    {
        attStatusId = "Present";
    }
    else
    {
        attStatusId = SISConst.AttendanceResults.FirstOrDefault(i => i.AttendanceTypeStatusID == System.Convert.ToInt32(value)).AttendanceTypeStatusCD;
    }
    if (attStatusId == "Absent")
    {
        return "A";
    }
    else if (attStatusId == "Present")
    {
        return "P";
    }
    else
    {
        return "L";
    }
}

异常截图

假设我正确理解了您的问题,那么标准方法是创建另一个仅获取 属性 的 returns 有条件存在或不存在的事件,然后引发 属性 更改事件对于那个习俗 属性 当实际 属性 改变时。

A Converter 将是一个很好的解决方案。易于创建和修改。

尝试类似 -

<ListView x:Name="list1" ItemsSource="{Binding StudentList}">
<ListView.ItemTemplate >
    <DataTemplate>
        <ViewCell>
            <StackLayout>
                <Label VerticalTextAlignment="Center"  
                       Text="{Binding StudentName}" />
                <Button x:Name="mybtn"         
                    BindingContext="{Binding Source={x:Reference list1}, Path=BindingContext}" 
                    Command="{Binding BtnTextCommand}" 
                    CommandParameter="{Binding Source={x:Reference mybtn}}"  
                    Text="{Binding PresentBool, Converter={StaticResource PresentToString}}" />
            </StackLayout>                  
        </ViewCell>
    </DataTemplate>
</ListView.ItemTemplate>
</ListView>

然后创建一个新的 class 实现 IValueConverter -

public class PresentToString : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return (bool)value ? "Present" : "Absent";
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }

要像上面那样将其用作 StaticResource,您需要将其包含在相关资源字典中。您可以将其放在此 ListView 来自的 Page/ContentView -

<ContentView>
    <ContentView.Resources>
        <PresentToString x:Key="PresentToString" />
    </ContentView.Resources>

    <ListView x:Name="list1" ... >
...

这就是全部!如果您的转换器位于不同的命名空间中,则必须将 xaml 添加到 Page/ContentView.

编辑

public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
    var typedValue = (int)value;
    // Since ints are not nullable, we don't need to do a null check

    switch (typedValue)
    {
        case 1:
            return "P";
        case 2:
            return "L";
        // case 0 handled in default. Removed to avoid redundancy.
        default:
            return "A";
    }
}

我猜你的 Student 模型必须包含 ID 属性。您是说当 ID 的值不为 null 时要将按钮的文本设置为 Present,而另一方面将其设置为 Absent 吗?

如果是,则不应更改按钮的绑定上下文。当您想在视图模型而不是学生模型中触发此命令时,您只能更改命令的源。这是我的 XAML 供您参考:

<ContentPage.Resources>
    <local:IDToStringConverter x:Key="IDToStringConverter"/>
</ContentPage.Resources>
<ContentPage.Content>
    <StackLayout>
        <ListView x:Name="list1" ItemsSource="{Binding StudentList}" HasUnevenRows="True">
            <ListView.ItemTemplate >
                <DataTemplate>
                    <ViewCell>
                        <StackLayout>
                            <Label VerticalTextAlignment="Center" 
                                Text="{Binding StudentName}" />
                            <Button x:Name="mybtn"         
                                Command="{Binding BindingContext.BtnTextCommand, Source={x:Reference list1}}" 
                                CommandParameter="{Binding Source={x:Reference mybtn}}"  
                                Text="{Binding ID, Converter={x:StaticResource IDToStringConverter}}"/>
                        </StackLayout>
                    </ViewCell>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
    </StackLayout>
</ContentPage.Content>

转换器实现 returns 不同字符串取决于 ID 值的效果:

public class IDToStringConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value != null)
        {
            return "Present";
        }
        return "Absent";
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

更新:

如果你想在运行时存储一些数据,你可以创建一个静态的 class:

public static class UtiClass
{
    public static List<AttendanceStatusModel> AttendanceStatus { set; get; }
}

在推送到第 2 页之前设置它的值:UtiClass.AttendanceStatus = //...。然后您可以在该设置后的任何其他地方访问它。即在您的转换器中。