【问题标题】:Modify property from ViewModel before binding to ListView在绑定到 ListView 之前从 ViewModel 修改属性
【发布时间】:2019-10-01 05:52:20
【问题描述】:

我正在使用 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); }
}

我想在绑定之前每次为每个列表项修改 Button 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";
    }
}

异常截图

【问题讨论】:

  • 也许创建一个名为 BindableModel 的新模型并使用此模型填充 ListView,在该模型中根据您的条件分配值?
  • ButtonTextHold 的目的是什么?在更改ButtonTextHold 时,将其删除或将PropertyChanged 提高为ButtonText

标签: c# xamarin mvvm xamarin.forms prism


【解决方案1】:

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

【讨论】:

    【解决方案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";
        }
    }
    

    【讨论】:

    • 感谢您的回答。但我有一种复杂的逻辑来操纵价值。如果你想看,我会用 ViewModel 更新我的问题。
    • 我假设您的“学生”课程有某种布尔值或方法来确定学生是否缺席。只要您的值被正确绑定,视图就会相应地更新。
    • 在上面的 Edit2 中,我不确定您所说的“在第一个 else 部分中抛出异常值”是什么意思。我认为这可能是打字问题,因为valueobject,而您正在将其与strings 进行比较。我会相应地更新我的答案。
    • 我仍然遇到异常。请参阅我的问题中附加的屏幕截图。
    • 您应该可以完全删除该行。至于为什么它为空,那一定是 XAML 代码的绑定问题。仔细检查您的 XAML,如果您找不到任何错误,请发布屏幕截图。
    【解决方案3】:

    我猜你的 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>
    

    转换器实现根据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 = //...。然后您可以在该设置后的任何其他地方访问它。即在您的转换器中。

    【讨论】:

    • 感谢您的回答。请也检查我更新的问题和描述。
    • @Arvindraja 正如我上面所说,没有必要处理视图模型中的代码。将您的按钮文本直接绑定到您的AttendanceTypeStatusId。然后在转换器中对其进行操作。在那里返回你想要的任何东西。而且我认为你应该这样做,因为每个项目都有自己的AttendanceTypeStatusId,你不能将逻辑放在视图模型中。
    • 我有AttendanceStatus List,你能告诉我什么是在转换器类中获取列表数据的好方法吗?我的意思是在哪里调用服务来获取AttendanceStatus 数据?
    • @Arvindraja AttendanceStatus 是做什么用的?你把这份清单放在哪里了?
    • 这个列表只有两个字段 AttendanceTypeStatusIDAttendanceTypeStatusCD 来自这个列表,基于 ID 我得到了诸如 Absent、Present、Late 等的文本。我总是有三个带有 Id 的记录。跨度>
    猜你喜欢
    • 1970-01-01
    • 2021-05-21
    • 2013-06-25
    • 2011-02-01
    • 2011-08-26
    • 2021-03-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多