代码之家  ›  专栏  ›  技术社区  ›  TheGeneral

强制转换绑定路径,以便在设计时识别ViewModel属性

  •  10
  • TheGeneral  · 技术社区  · 6 年前

    好吧,这比问题更烦人。没有错误

    <ContentPage
       ...
       x:Name="This"
       //hack to have typed xaml at design-time
       BindingContext="{Binding Source={x:Static viewModels:ViewModelLocator.ChooseTargetLocationVm}}"
    

    子视图

    <views:ProductStandardView
        ...
        BindingContext="{Binding Product}">
        <Grid.Triggers>
            <DataTrigger
                Binding="{Binding Path=BindingContext.IsVacate, Source={x:Reference This}}"
                TargetType="Grid"
                Value="true">
                <Setter Property="BackgroundColor" Value="{StaticResource WarningColor}" />
            </DataTrigger>
        </Grid.Triggers>
    

    什么时候? 结合 BindingContext 来自 来源 参考 属于 This ,我得到一个xaml“警告”

    无法解析“Object”类型的数据上下文中的属性“IsVacate”

    Binding="{Binding Path=BindingContext.IsVacate, Source={x:Reference This}}"
    

    显然 绑定上下文 是一个 对象 和非类型化。 但是,上述代码可以编译并工作

    我想做的是投射它,首先是因为我有OCD,但是主要是因为它很容易在IDE页面频道栏上发现真正的问题。

    以下内容似乎合乎逻辑,但不起作用

    Binding="{Binding Path=BindingContext.(viewModels:ChooseTargetLocationVm.IsVacate), 
                      Source={x:Reference This}}"
    

    在我得到的输出中

    [0:]绑定:“”( viewModels:ChooseTargetLocationVm '属性不是 在上找到 ’ Inhouse.Mobile.Standard.ViewModels.ChooseTargetLocationVm '目标 属性:' Inhouse.Mobile.Standard.Views.ProductStandardView.Bound

    我理解这个错误,但我还能怎么施法呢?


    只是为了愚蠢,很明显下面的内容不会编译

    Binding="{Binding Path=((viewModels:ChooseTargetLocationVm)BindingContext).IsVacate, Source={x:Reference This}}"
    

    有没有办法 绑定上下文 到A 视图模型 所以任何 子属性 是否在设计时键入引用?

    更新

    这与 DataTemplate 或者在这种情况下,当控件有自己的 绑定上下文 这就是为什么我需要使用 Source={x:Reference This} 以页面为目标。

    注释 : <ContentPage.BindingContext> 在我使用Prism和Unity时,它对我不起作用,而且在初始测试中它似乎不能很好地与默认的构造函数配合使用,尽管我可能会更多地使用它。

    1 回复  |  直到 6 年前
        1
  •  4
  •   Sharada    6 年前

    你可以延长 ContentPage 创建一个通用类型(支持视图模型的类型参数),该类型反过来可用于 Binding 标记扩展。

    虽然它可能不会给你像智能感知一样的支持-但绝对应该删除你的警告。

    例如:

    /// <summary>
    /// Create a base page with generic support
    /// </summary>
    public class ContentPage<T> : ContentPage
    {
        /// <summary>
        /// This property basically type-casts the BindingContext to expected view-model type
        /// </summary>
        /// <value>The view model.</value>
        public T ViewModel { get { return (BindingContext != null) ? (T)BindingContext : default(T); } }
    
        /// <summary>
        /// Ensure ViewModel property change is raised when BindingContext changes
        /// </summary>
        protected override void OnBindingContextChanged()
        {
            base.OnBindingContextChanged();
    
            OnPropertyChanged(nameof(ViewModel));
        }
    }
    

    样品使用

    <?xml version="1.0" encoding="utf-8"?>
    <l:ContentPage 
        ...
        xmlns:l="clr-namespace:SampleApp" 
        x:TypeArguments="l:ThisPageViewModel"
        x:Name="This"
        x:Class="SampleApp.SampleAppPage">
    
        ...                            
             <Label Text="{Binding ViewModel.PropA, Source={x:Reference This}}" />
        ...
    </l:ContentPage>
    

    代码隐藏

    public partial class SampleAppPage : ContentPage<ThisPageViewModel>
    {
        public SampleAppPage()
        {
            InitializeComponent();
    
            BindingContext = new ThisPageViewModel();
        }
    }
    

    视图模型

    /// <summary>
    /// Just a sample viewmodel with properties
    /// </summary>
    public class ThisPageViewModel
    {
        public string PropA { get; } = "PropA";
        public string PropB { get; } = "PropB";
        public string PropC { get; } = "PropC";
    
        public string[] Items { get; } = new[] { "1", "2", "3" };
    }