【问题标题】:MVVM add elements dynamically to scrollviewMVVM 动态添加元素到滚动视图
【发布时间】:2020-05-29 06:06:49
【问题描述】:

如果之前有人问过这个问题,请提前道歉。我发现的最接近的东西是 (How to use vertical Scroll view to show binding data),它看起来很有希望,但我不确定它是否会起作用,因为我的理解是模板,正如名称和定义所暗示的那样,必须遵循特定的模式,因此可以不要动态。

我的问题:我正在尝试重写我们的一些代码以更紧密地遵循 MVVM 模式,这当然意味着使视图尽可能地愚蠢。在我看来 (xaml.cs) 我有执行以下操作的代码:

 foreach(var tuple in itemsToAdd)
            {
                var formEntry = formEntries.First(x => x.FormEntryId == tuple.Item1);
                var controlType = formatting.GetControlType(formEntry.FormAnswerName,
                                                         formEntry.CustomEntryIdentifier);

                if (formEntry.Type == 0) {
                    switch (controlType) {
                        case CustomControl.Duration:
                            CustomFields.Children.Add(new DurationView(formEntry.FormEntryId, viewModel));
                            break;
                        case CustomControl.TextField:
                        case CustomControl.InputField:

                            CustomFields.Children.Add(new InputFieldView(formEntry.FormEntryId, viewModel));
 .....//continues like this for different controls.

列表itemsToAdd 是在我的视图模型中定义的,它的工作是找出用户生成的模板中的哪些元素需要显示。这当然很好,因为根据我对 MVVM 的理解,视图模型是需要控制行为(在这种情况下,是要显示的内容),而 UI 只是处理显示字段。

我想知道是否可以让视图模型处理,本质上,设置滚动视图的项目源,就像我们为列表视图创建项目源时所做的那样(比如可用模板),因为每个控件都是我们制作的自定义视图,所以我看不到实现此目的的可行方法,因为它不能(根据我的理解)遵循模板,因为每个控件都是不同的,并且我不想让我的视图模型返回一个实际的视图对象,因为这会违反 MVVM 原则。

真正的本质是:我是否误解了 Xamarin 中的 MVVM,是否可以让后面的 xaml 代码添加我在代码 sn-p 中显示的元素。

抱歉,如果不清楚我的要求是什么!

【问题讨论】:

    标签: c# mvvm xamarin.forms


    【解决方案1】:

    我不确定我是否理解真正的问题,您是否试图根据 Type 属性为每个 itemsToAdd 元素显示不同的 UI?

    如果是问题所在,您可以将整个集合绑定到ListView 控件(或您正在使用的任何控件)并使用DataTemplateSelector 来选择您想要的UI。 Reference

    查看 你可以参考之前的链接。就像:

    <ListView ItemsSource="{Binding FormEntries}" DataTemplateSelector="{StaticResource dataTemplateSelectorName}"/>
    

    确保您的页面数据上下文设置为视图模型

    视图模型 假设您的对象类型名为 FormEntry

    private ObservableCollection<FormEntry> _formEntries;
    public ObservableCollection<FormEntry> FormEntries
    {
        get => _formEntries;
        set
        {
            _formEntries = value;
            // Call the 'RaisePropertyChanged' of the framework you are using
        }
    }
    
    ...
    FormEntries = new ObservableCollection<FormEntry>(itemsToAdd);
    ...
    

    数据模板选择器 参考链接构建一个扩展DataTemplateSelector的类并覆盖OnSelectTemplate方法来确定业务逻辑来选择你想要的UI模板

    【讨论】:

    • 排序,但就像添加它的不是 xaml 代码,而是视图模型将决定孩子是什么。类似于如果我们有一个名称的列表视图,我们会让视图模型定义一个 List 并将其设置为项目源
    • 感谢您提供更新的答案,当我回到代码的那部分并向您更新结果时,我会尝试这个
    • 我会继续将您的答案设置为已接受的答案,因为感谢您,我才弄明白。我添加了我的完整示例,以展示如何使用具有不同方法的模板来实现它
    【解决方案2】:

    所以我能够弄清楚如何做到这一点,非常感谢 Krusty 为我指出了正确的来源。

    我必须创建我的 DataTemplateSelector,

    public class MyTemplate: DataTemplateSelector
        {
            public DataTemplate InputFieldTemplate { get; set; }
            public DataTemplate EmptyTemplate { get; set; }
            public DataTemplate DurationTemplate { get; set; }
            public DataTemplate SignatureDetailTemplate {get; set;}
            public DataTemplate SignaturePhoneTemplate { get; set; }
            public DataTemplate DateTemplate { get; set; }
    
    
            protected override DataTemplate OnSelectTemplate(object item, BindableObject container)
            {
                try
                {
                    ControlsViewModel viewModel = item as ControlsViewModel;
    
                    if (viewModel == null)
                    {
                        return EmptyTemplate;
                    }
    
    
                    if (viewModel.ControlType == Enums.CustomControl.InputField || viewModel.ControlType == Enums.CustomControl.TextField)
                        return InputFieldTemplate;
                    if (viewModel.ControlType == Enums.CustomControl.Duration)
                    {
                        return DurationTemplate;
                    }
                    if (viewModel.ControlType == Enums.CustomControl.Signature)
                    {
                        if(string.IsNullOrEmpty(viewModel.Disclaimer))
                        {
                            return SignatureDetailTemplate;
                        }
    
                        return SignaturePhoneTemplate;
                    }
    
    
    
                    return EmptyTemplate;
                }
                catch
                {
                    throw;
                }
            }
        }
    

    然后我为其创建相应的字典(在本例中为 ResourceDictionary.xaml)

    <DataTemplate x:Key="EmptyTemplate">
        <ViewCell>
            <BoxView></BoxView>
        </ViewCell>
    </DataTemplate>
    
    
    <DataTemplate x:Key="InputFieldTemplate">
        <ViewCell>
    
    
            <StackLayout Orientation="Vertical" 
                             Padding="0, 20, 0, 0"
                             HorizontalOptions="FillAndExpand"
                             VerticalOptions="StartAndExpand">
    
            <Label Text="{Binding Label}"
                          FontAttributes="Bold"
                          TextColor="Black"
                          FontSize="14"
                          VerticalOptions="Start"
                          HorizontalOptions="FillAndExpand"/>
    
    
            <StackLayout
                HorizontalOptions="FillAndExpand"
                VerticalOptions="Start"
                Spacing="0"
                Orientation="Vertical">
    
                <Editor
    
                    Text="{Binding Answer}"
                    TextColor="Black"
                    AutoSize="TextChanges" 
                    IsTextPredictionEnabled="False"
                    IsSpellCheckEnabled="False"
                    BackgroundColor="White"
                    FontSize="14"
                    VerticalOptions="Start"
                    HorizontalOptions="FillAndExpand"/>
    
                <BoxView HeightRequest="1"
                     BackgroundColor="{Binding FieldColor}" 
                     Margin="0"
                     HorizontalOptions="FillAndExpand"
                     VerticalOptions="Start"/>
    
            </StackLayout>
        </StackLayout>
        </ViewCell>
    </DataTemplate>    
    

    最后,在我要使用的视图中,添加如下:

    <ListView ItemsSource="{Binding NoteObjects}" ItemTemplate="{StaticResource DataTemplateSelector}"/>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多