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

时间:2019-05-14 08:52:42

标签: c# xamarin mvvm xamarin.forms prism

我正在使用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类中获取BtnText的更新值?

修改值意味着如果Text具有ID value,则显示'Present';如果为null,则显示'Absent'等。

学生班

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中编写了此逻辑,在else的前value部分中引发了异常

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";
    }
}

ExcpetionScreenshot

enter image description here

3 个答案:

答案 0 :(得分:2)

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>

然后创建一个实现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";
    }
}

答案 1 :(得分:1)

假设我正确理解了您的问题,那么执行此操作的标准方法是创建另一个有条件返回仅存在或不存在的get only属性,然后在更改实际属性时为该自定义属性引发属性更改事件。

答案 2 :(得分:1)

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

如果是这样,则不应更改Button的绑定上下文。仅当要在视图模型而非学生模型中触发此命令时,才可以更改命令的源。这是我的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>

转换器实现根据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();
    }
}

已更新:

如果要在运行时存储一些数据,可以创建一个静态类:

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

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