繁体   English   中英

条目上的多个行为(Xamarin 表单)

[英]Multiple behaviors on an entry (Xamarin Forms)

我在一个条目上实现多个行为时遇到了很多麻烦

如果用户类型介于整数、十进制数、日期和文本之间,我想实现用户输入验证

希望您能提供帮助或发送示例

你很幸运,因为就在最近我实现了非常相似的事情:

 private FormQuestion formModel {get;set;}
 public Form()
    {
        InitializeComponent();
        //Hook up events, set layout of main Stack
        CreateViews(formModel);
        mainStack.Orientation = StackOrientation.Vertical;
        mainStack.VerticalOptions = LayoutOptions.FillAndExpand;
        mainStack.HorizontalOptions = LayoutOptions.FillAndExpand;
    }
    #endregion
    /// <summary>
    /// Method that returns Stack layout that contains control required for filling up the form if QuestionType is Text.
    /// This method creates StackLayout, Label and Entry then returns it.
    /// </summary>
    /// <param name="formQuestions"></param>
    /// <returns></returns>
    private StackLayout CreateQuestionStackText(FormQuestion formQuestions)
    {
        StackLayout stack = new StackLayout
        {
            Orientation = StackOrientation.Horizontal,
            VerticalOptions = LayoutOptions.Center,
            HorizontalOptions = LayoutOptions.FillAndExpand
        };
        Label label = new Label
        {
            HorizontalOptions = LayoutOptions.Start,
            VerticalOptions = LayoutOptions.CenterAndExpand
        };
        label.SetBinding(Label.TextProperty, "Text");
        Entry entry = new Entry
        {
            HorizontalOptions = LayoutOptions.EndAndExpand,
            VerticalOptions = LayoutOptions.CenterAndExpand,
            WidthRequest = 200
        };
        entry.SetBinding(Entry.TextProperty, "Value");
        stack.Children.Add(label);
        stack.Children.Add(entry);
        return stack;

    }
    /// <summary>
    /// Method that returns Stack layout that contains control required for filling up the form if QuestionType is Number. 
    /// This method creates StackLayout, Label and Entry that enforces Numerical Keyboard then returns it.  
    /// </summary>
    /// <param name="formQuestions"></param>
    /// <returns></returns>
    private StackLayout CreateQuestionStackNumber(FormQuestion formQuestions)
    {
        StackLayout stack = new StackLayout
        {
            Orientation = StackOrientation.Horizontal,
            VerticalOptions = LayoutOptions.Center,
            HorizontalOptions = LayoutOptions.FillAndExpand
        };
        Label label = new Label
        {
            HorizontalOptions = LayoutOptions.Start,
            VerticalOptions = LayoutOptions.CenterAndExpand
        };
        label.SetBinding(Label.TextProperty, "Text");
        Entry entry = new Entry
        {
            HorizontalOptions = LayoutOptions.EndAndExpand,
            VerticalOptions = LayoutOptions.CenterAndExpand,
            Keyboard = Keyboard.Numeric,
            WidthRequest = 200
        };
        entry.SetBinding(Entry.TextProperty, "Value");
        stack.Children.Add(label);
        stack.Children.Add(entry);
        return stack;
    }
    /// <summary>
    /// Method that returns Stack layout that contains control required for filling up the form if QuestionType is DropDown
    /// This method creates StackLayout, Label and BindablePicker, which is custom Picker I've created to be able to get work with MVVM, then returns it.
    /// </summary>
    /// <param name="formQuestions"></param>
    /// <returns></returns>
    private StackLayout CreateQuestionStackDropDown(FormQuestion formQuestions)
    {
        StackLayout stack = new StackLayout
        {
            Orientation = StackOrientation.Horizontal,
            VerticalOptions = LayoutOptions.Center,
            HorizontalOptions = LayoutOptions.FillAndExpand
        };
        Label label = new Label 
        {
            HorizontalOptions = LayoutOptions.Start,
            VerticalOptions = LayoutOptions.CenterAndExpand
        };
        label.SetBinding(Label.TextProperty, "Text");
        BindablePicker picker = new BindablePicker();
        picker.HorizontalOptions = LayoutOptions.EndAndExpand;
        picker.BindingContext = this;
        var bind = this.BindingContext;
        var strings = formQuestions.DataSource.Values;
        var listOfStrings = strings.Split(';');
        List<string> result = new List<string>();
        foreach (var item in listOfStrings)
        {
            result.Add(item);
        }
        picker.ItemsSource = result;
        picker.SelectedIndexChanged += Picker_SelectedIndexChanged;
        //picker.SetBinding(BindablePicker.DisplayMemberPathProperty, new Binding( "Values", BindingMode.TwoWay, new ValuesToListOfStringsConverter(), null));
        picker.SetBinding(BindablePicker.SelectedItemProperty, "Value");
        picker.WidthRequest = 200;
        stack.Children.Add(label);
        stack.Children.Add(picker);
        return stack;
    }
    /// <summary>
    /// Method that returns Stack layout that contains control required for filling up the form if QuestionType is Data
    /// This method creates StackLayout, Label and DataPicker and returns it.
    /// </summary>
    /// <param name="formQuestions"></param>
    /// <returns></returns>
    private StackLayout CreateQuestionStackDate(FormQuestion formQuestions)
    {
        StackLayout stack = new StackLayout
        {
            Orientation = StackOrientation.Horizontal,
            VerticalOptions = LayoutOptions.Center,
            HorizontalOptions = LayoutOptions.FillAndExpand
        };
        Label label = new Label
        {
            HorizontalOptions = LayoutOptions.Start,
            VerticalOptions = LayoutOptions.CenterAndExpand
        };
        label.SetBinding(Label.TextProperty, "Text");
        DatePicker datePicker = new DatePicker();
        datePicker.HorizontalOptions = LayoutOptions.EndAndExpand;
        datePicker.SetBinding(DatePicker.DateProperty, "Value");
        stack.Children.Add(label);
        stack.Children.Add(datePicker);
        return stack;
    }
    /// <summary>
    /// Little hack, that unfortunately I had to implement. Because DropDown contains list of DataSource Properties that is essentially array of objects, I had to work around with pulling data of selected item and only
    /// get Values property value. This couldnt be bound correctly, because Values are expecting to be string, but SelectedItem property of picker is an actuall full Object of DataSource. 
    /// I Could probably work around it by Implementing Converter, but Converter will have more code, and I couldnt be bothered. 
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void Picker_SelectedIndexChanged(object sender, EventArgs e)
    {
        //Cast sender object to BindablePicker (since sender is BindablePicker)
        var picker = (BindablePicker)sender;
        ///Get SelectedItem Value and cast it to DataSource (since SelectedItem is DataSource)
        var value = (string)picker.SelectedItem;
        // Assign Values value back to My Collection
        ((FormQuestion)BindingContext).Value = value;
    }
    /// <summary>
    /// Determine which stack should be created, depending on QuestionType
    /// </summary>
    /// <param name="formModel"></param>
    private void CreateViews(FormQuestion formModel)
    {
        StackLayout newStack = new StackLayout();
                switch (formModel.QuestionType.Name)
                {
                    case "text":
                    newStack.Children.Add(CreateQuestionStackText(formModel));
                        break;
                    case "number":
                    newStack.Children.Add(CreateQuestionStackNumber(formModel));
                        break;
                    case "dropDown":
                    newStack.Children.Add(CreateQuestionStackDropDown(formModel));
                        break;
                    case "date":
                    newStack.Children.Add(CreateQuestionStackDate(formModel));
                        break;
                    default:
                    newStack.Children.Add(CreateQuestionStackText(formModel));
                    break;
                }
        this.mainStack.Children.Add(newStack);
    }
    #endregion

    public class FormQuestion
{
    public int FormQuestionId { get; set; }
    public string Text { get; set; }
    public string Value { get; set; }
    public int QuestionTypeId { get; set; }
    public virtual QuestionType QuestionType { get; set; }
    public int FormId { get; set; }
    public Form Form { get; set; }
    public DataSource DataSource { get; set; }
}
   public class QuestionType
{
    public int QuestionTypeId { get; set; }

    public string Name { get; set; }
}

这将是您的 Xaml。

            <StackLayout VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand">
    <Frame BorderColor="Gray" CornerRadius="2" VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand" >
    <StackLayout Orientation="Vertical" VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand" x:Name="mainStack">
    </StackLayout>
    </Frame>
    </StackLayout>

您需要稍微修改以适应您的目的,但我已经为您提供了我的实现,因此您对应该做什么有基本的掌握和概念。 还请记住,这样做是为了使用 MVVM。 我还剥离了一些无关紧要的方法。 BindablePicker 是 Picker 的扩展版本,因为标准 Xamarin Forms 选择器没有可绑定属性。 我的代码的主要目的是根据来自后端的表单类型动态创建不同类型的条目、选择器、日期选择器等,并将它们绑定到 ListView 内的 ViewModel。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM