Xamarin.Forms PCL MVVM Light>定制控制>最佳实践?

时间:2015-06-16 09:02:29

标签: xamarin mvvm-light xamarin.forms portable-class-library

HY

我想在一个带有MVVM-Light的Xamarin PCL项目中分享我的自定义xamarin.forms控件的方法。你觉得怎么样?

自定义控制 - > PersonPanel.xaml:

<?xml version="1.0" encoding="utf-8" ?>
<ContentView xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="xxx.PersonPanel">
  <StackLayout Orientation="Vertical">
    <Label x:Name="titleLabel" Text="{Binding TitleLabel}"/>
    <Entry x:Name="filterText" Placeholder="{Binding FilterPlaceholderText}" Text="{Binding Filter.Lookup}" TextChanged="OnFilterTextChanged"/>
    <Label x:Name="resultText" Text="{Binding ResultText}" IsVisible="{Binding ResultTextVisible}"/>
  </StackLayout>
</ContentView>

Code-Behind - &gt; PersonPanel.xaml.cs:

public partial class PersonPanel : ContentView
{
    public PersonPanel()
    {
        InitializeComponent();

        //Init ViewModel
        BindingContext = ServiceLocator.Current.GetInstance<PersonPanelViewModel>();
    }

    private PersonPanelViewModel PersonPanelViewModel
    {
        get
        {
            return (PersonPanelViewModel)BindingContext;
        }
    }

    public string TitleLabel
    {
        get
        {
            return PersonPanelViewModel.TitleLabel;
        }
        set
        {
            PersonPanelViewModel.TitleLabel = value;
        }
    }

    public string FilterPlaceholderText
    {
        get
        {
            return PersonPanelViewModel.FilterPlaceholderText;
        }
        set
        {
            PersonPanelViewModel.FilterPlaceholderText = value;
        }
    }

    private void OnFilterTextChanged(object sender, EventArgs e)
    {
        PersonPanelViewModel.SearchCommand.Execute(null);
    }
}

ViewModel - &gt; PersonPanelViewModel:

public class PersonPanelViewModel : ViewModelBase
{
    private IPersonService _personService;

    private decimal _personId = 0;
    private string _titleLabel = string.Empty;
    private string _filterPlaceholderText = string.Empty;
    private string _resultText = string.Empty;
    private bool _resultTextVisible = true;

    public PersonPanelViewModel(IPersonService personService)
    {
        _personService = personService;

        // Init Filter
        Filter = new PersonFilter();

        // Init Commands
        SearchCommand = new RelayCommand(Search);
    }

    public ICommand SearchCommand { get; set; }

    public PersonFilter Filter
    {
        get;
        private set;
    }

    public string ResultText
    {
        get
        {
            return _resultText;
        }
        set
        {
            Set(() => ResultText, ref _resultText, value);
        }
    }

    public bool ResultTextVisible
    {
        get
        {
            return _resultTextVisible;
        }
        set
        {
            Set(() => ResultTextVisible, ref _resultTextVisible, value);
        }
    }

    public string FilterPlaceholderText
    {
        get
        {
            return _filterPlaceholderText;
        }
        set
        {
            Set(() => FilterPlaceholderText, ref _filterPlaceholderText, value);
        }
    }

    public string TitleLabel
    {
        get
        {
            return _titleLabel;
        }
        set
        {
            Set(() => TitleLabel, ref _titleLabel, value);
        }
    }

    public decimal PersonId
    {
        get
        {
            return _PersonId;
        }
        set
        {
            Set(() => PersonId, ref _PersonId, value);
        }
    }

    private async void Search()
    {
        //Reset
        ResultText = string.Empty;
        ResultTextVisible = false;
        PersonId = 0;

        if (Filter.PersonLookup != null && Filter.PersonLookup.Length >= 3)
        {
            //Call to Person Service
            List<PersonResult> Person = await _personService.FindpersonByFilter(Filter);               

            if (Person.Count == 1)
            {
                PersonId = Person[0].PersonId;

                ResultText = Person[0].PersonName;
                ResultTextVisible = true;
            }
        }
    }
}

在另一个视图中使用Control:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:components="clr-namespace:xxx.ViewElements.Components"
             x:Class="xxx.MainPage">
  <StackLayout Orientation="Vertical">
    <components:PersonPanel x:Name="personPanel" TitleLabel="Person" FilterPlaceholderText="Type your search criteria here..."/>
  </StackLayout>
</ContentPage>

我正在使用Autofac作为IOC容器。

你怎么看?我正在使用MVVM(这对我来说很新)?

有没有更好的方法来处理从视图中的事件(TextChanged)调用命令?

Code-Behind中的属性是什么(路由到ViewModel)?

修改 我将尝试描述,我想要实现的目标:

  • 创建我们自己的控件(可在不同视图中重用,跨平台) - &gt; PersonPanel.xaml
  • 在我们的PCL项目中用XAML编写,其中包含纯Xamarin.Forms控件
  • 控件应具有自己的命令(搜索)和属性
  • 其中一个命令是使用服务
  • 控件应该通过IOC注入服务(作为接口)
  • 服务本身也在PCL项目中实现,并对Web服务进行REST调用
  • 将呼叫结果设置为控件的属性 - &gt; ResultText属性
  • 结果对用户可见

- &GT;通过上面的实现,所有这些都有效,但我不确定这是否正确......

感谢您的帮助!

亲切的问候, 彼得

1 个答案:

答案 0 :(得分:0)

将事件映射到命令的方法与我执行的完全一样。

其余的有点令人困惑。一般模式是在控件中创建可绑定属性,这些属性在主机视图中实例化时公开给视图模型。下面是一个非常基本的样本结构:

public class TestLabelControl : Label
{
    public static readonly BindableProperty TestTitleProperty = BindableProperty.Create< TestLabelControl, string> (p => p.TestTitle, null);

    public string TestTitle {
        get {
            return (object)GetValue (TestTitleProperty);
        }
        set {
            SetValue (TestTitleProperty, value);
        }
    }
}

public class TestContentPage : ContentPage
{
    public TestContentPage()
    {
        var testLabel = new TestLabel();
        testLabel.SetBinding<TestContentPageViewModel>(TestLabel.TestTitleProperty, vm => vm.TestLabelTitle, BindingMode.Default);
        Content = testLabel;
    }
}


public class TestContentPageViewModel
{
    public string TestLabelTitle{get;set;}

    public TestContentPageViewModel()
    {
        TestLabelTitle = "Something random";
    }
}

然后,您将创建本机渲染器以在每个平台上处理绘图。

通过遵循这种方法,您可以保持代码分离和简洁。它似乎是一种稍微冗长的方式来完成任务,但它具有高度可扩展性和可配置性。