如何使用baui的绑定和dataTemplate -或contentControl表示数据

发布于 2025-02-08 18:37:44 字数 1253 浏览 1 评论 0 原文

如何提供带有绑定和数据板的字符串,数字或视图模型?

我正在寻找WPF ContentControl的MAUI替换。

contentView 具有一个内容属性,但这来自类型 view contentPresenter 具有一个内容属性,但这也来自类型 view < tobleable> wtf,为什么当它只能显示一个视图时,为什么不将其命名为viewPresenter ??? 某种怪异很奇怪。

毛伊岛的

class PropertyViewModel {
   public string Name {get;set;}
   public object Value {get;set;}
}
<Page.Resources>
    <DataTemplate DataType="System.String">
        <Entry Text="{Binding}/>
    </DataTemplate>
    <DataTemplate DataType="System.Int32">
        <NumberPicker Value="{Binding}/>
    </DataTemplate>
    .. more templates, eg. DatePicker for System.DateOnly
</Page.Resources>

<DockLayout>
    <Label Text="{Binding Name}
    <TemplatedContenView Content={Binding Value}/> 
</DockPanel>

TemplatedContenview或ContentControl(在MAUI中不存在),可以将不同的模板用于不同的的价值类型。在WPF中,ContentControl使用ContentTemplate,ContentTemplatesElector,或者如果没有指定,则查看了资源以查找模板。

&lt; gt;我经常对毛伊岛的感觉,我必须不断地重塑wpf中标准的事物。是的,我知道毛伊岛不是WPF,但至少应该有类似的概念。 并且差异要大得多。

从Winforms到WPF的转换要容易得多,

How to present a string, number or a also view model with binding and DataTemplate?

I am looking for a MAUI replacement for the WPF ContentControl.

The ContentView has a Content property but this is from type View.
The ContentPresenter has a Content property but this is also from type View. <Ignorable>WTF, Why this is not named ViewPresenter when it can only present a View??? Someoteimes MAUI is weird.</Ignorable>

How to present any content with defining DataTemplates for each data type?

class PropertyViewModel {
   public string Name {get;set;}
   public object Value {get;set;}
}
<Page.Resources>
    <DataTemplate DataType="System.String">
        <Entry Text="{Binding}/>
    </DataTemplate>
    <DataTemplate DataType="System.Int32">
        <NumberPicker Value="{Binding}/>
    </DataTemplate>
    .. more templates, eg. DatePicker for System.DateOnly
</Page.Resources>

<DockLayout>
    <Label Text="{Binding Name}
    <TemplatedContenView Content={Binding Value}/> 
</DockPanel>

The TemplatedContenView or ContentControl (that does not exist in MAUI), can use different templates for different types of Value. In WPF the ContentControl uses ContentTemplate, ContentTemplateSelector or if none specified it looked into the resources to find the template.

<Ignorable>I often have the feeling with MAUI that I have to constantly reinvent things that are standard in WPF. Yes I know MAUI is not WPF, but there should still be at least similar concepts. The switch from WinForms to WPF was much easier and the differences were considerably greater.</Ignorable>

Edit1: a more detailed example

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

一场信仰旅途 2025-02-15 18:37:44

我是WPF开发人员,最近我开始了MAUI项目。而且看来您每次要编写一个简单的场景时都必须重新发明轮子,如您提到的那样:(。但是,当您使用毛伊岛时,您应该打破您的想法

。内部已连接了bindableLayout

templatedContentPresenter.xaml.cs:

public partial class TemplatedContentPresenter : ContentView
{
    public TemplatedContentPresenter()
    {
        InitializeComponent();
    }

    public static readonly BindableProperty DataTemplateSelectorProperty = BindableProperty.Create(nameof(DataTemplateSelector), typeof(DataTemplateSelector), typeof(TemplatedContentPresenter), null, propertyChanged: DataTemplateSelectorChanged);
    public static readonly BindableProperty DataTemplateProperty = BindableProperty.Create(nameof(DataTemplate), typeof(DataTemplate), typeof(TemplatedContentPresenter), null, propertyChanged: DataTemplateChanged);
    public static readonly BindableProperty DataProperty = BindableProperty.Create(nameof(Data), typeof(object), typeof(TemplatedContentPresenter), null, propertyChanged: DataChanged);

    public DataTemplateSelector DataTemplateSelector
    {
        get =>(DataTemplateSelector)GetValue(DataTemplateSelectorProperty);
        set => SetValue(DataTemplateSelectorProperty, value);
    }

    public DataTemplate DataTemplate
    {
        get => (DataTemplate)GetValue(DataTemplateProperty);
        set => SetValue(DataTemplateProperty, value);
    }

    public object Data
    {
        get => GetValue(DataProperty);
        set => SetValue(DataProperty, value);
    }

    private static void DataTemplateSelectorChanged(BindableObject bindable, object oldValue, object newValue)
    {
        if(bindable is TemplatedContentPresenter contentPresenter && newValue is DataTemplateSelector dataTemplateSelector)
        {
            BindableLayout.SetItemTemplateSelector(contentPresenter.HostGrid, dataTemplateSelector);
        }
    }
    private static void DataTemplateChanged(BindableObject bindable, object oldValue, object newValue)
    {
        if (bindable is TemplatedContentPresenter contentPresenter && newValue is DataTemplate dataTemplate)
        {
            BindableLayout.SetItemTemplate(contentPresenter.HostGrid, dataTemplate);
        }
    }

    private static void DataChanged(BindableObject bindable, object oldValue, object newValue)
    {
        if (bindable is TemplatedContentPresenter contentPresenter)
        {
            BindableLayout.SetItemsSource(contentPresenter.HostGrid, new object[] { newValue });
        }
    }
}

templatedContentPresenter.xaml:

<?xml version="1.0" encoding="utf-8" ?>
<ContentView xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="MyApp.TemplatedContentPresenter">
    <Grid x:Name="HostGrid" x:FieldModifier="private" />
</ContentView>

usage

<Frame WidthRequest="500" HeightRequest="500">
     <controls:TemplatedContentPresenter 
               Data="{Binding}" 
               DataTemplateSelector="{StaticResource CardTemplateSelector}"/>
</Frame>


当我写答案时,我提出了另一个带有一个简单转换器的解决方案:
singleObjectToArray.xaml

    internal class SingleObjectToArray : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return new object[] { value };
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }

用法:

<Frame>
    <Frame.Resources>
        <converters:SingleObjectToArray x:Key="SingleObjectToArrayConverter"/>
    </Frame.Resources>
    <Grid BindableLayout.ItemsSource="{Binding Converter={StaticResource SingleObjectToArrayConverter}}"
          BindableLayout.ItemTemplateSelector="{StaticResource CardTemplateSelector}" /> 
</Frame>

I'm a WPF developer and recently I've started MAUI project. And It looks like you have to reinvent the wheel every time when you are going to write such a simple scenario as you mentioned :(. When you do it using WPF you even don't need to thought about that, it's too easy to implement, but when you use MAUI you should break your mind to do such minor things.

I also encountered the same issue and I didn't find a simple in-box solution. But I came up with the idea to create a control with some layout inside that has attached properties from BindableLayout

TemplatedContentPresenter.xaml.cs:

public partial class TemplatedContentPresenter : ContentView
{
    public TemplatedContentPresenter()
    {
        InitializeComponent();
    }

    public static readonly BindableProperty DataTemplateSelectorProperty = BindableProperty.Create(nameof(DataTemplateSelector), typeof(DataTemplateSelector), typeof(TemplatedContentPresenter), null, propertyChanged: DataTemplateSelectorChanged);
    public static readonly BindableProperty DataTemplateProperty = BindableProperty.Create(nameof(DataTemplate), typeof(DataTemplate), typeof(TemplatedContentPresenter), null, propertyChanged: DataTemplateChanged);
    public static readonly BindableProperty DataProperty = BindableProperty.Create(nameof(Data), typeof(object), typeof(TemplatedContentPresenter), null, propertyChanged: DataChanged);

    public DataTemplateSelector DataTemplateSelector
    {
        get =>(DataTemplateSelector)GetValue(DataTemplateSelectorProperty);
        set => SetValue(DataTemplateSelectorProperty, value);
    }

    public DataTemplate DataTemplate
    {
        get => (DataTemplate)GetValue(DataTemplateProperty);
        set => SetValue(DataTemplateProperty, value);
    }

    public object Data
    {
        get => GetValue(DataProperty);
        set => SetValue(DataProperty, value);
    }

    private static void DataTemplateSelectorChanged(BindableObject bindable, object oldValue, object newValue)
    {
        if(bindable is TemplatedContentPresenter contentPresenter && newValue is DataTemplateSelector dataTemplateSelector)
        {
            BindableLayout.SetItemTemplateSelector(contentPresenter.HostGrid, dataTemplateSelector);
        }
    }
    private static void DataTemplateChanged(BindableObject bindable, object oldValue, object newValue)
    {
        if (bindable is TemplatedContentPresenter contentPresenter && newValue is DataTemplate dataTemplate)
        {
            BindableLayout.SetItemTemplate(contentPresenter.HostGrid, dataTemplate);
        }
    }

    private static void DataChanged(BindableObject bindable, object oldValue, object newValue)
    {
        if (bindable is TemplatedContentPresenter contentPresenter)
        {
            BindableLayout.SetItemsSource(contentPresenter.HostGrid, new object[] { newValue });
        }
    }
}

TemplatedContentPresenter.xaml:

<?xml version="1.0" encoding="utf-8" ?>
<ContentView xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="MyApp.TemplatedContentPresenter">
    <Grid x:Name="HostGrid" x:FieldModifier="private" />
</ContentView>

Usage:

<Frame WidthRequest="500" HeightRequest="500">
     <controls:TemplatedContentPresenter 
               Data="{Binding}" 
               DataTemplateSelector="{StaticResource CardTemplateSelector}"/>
</Frame>

UPD:
While I was writing the answer I came up with another solution with a simple converter:
SingleObjectToArray.xaml

    internal class SingleObjectToArray : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return new object[] { value };
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }

Usage:

<Frame>
    <Frame.Resources>
        <converters:SingleObjectToArray x:Key="SingleObjectToArrayConverter"/>
    </Frame.Resources>
    <Grid BindableLayout.ItemsSource="{Binding Converter={StaticResource SingleObjectToArrayConverter}}"
          BindableLayout.ItemTemplateSelector="{StaticResource CardTemplateSelector}" /> 
</Frame>
别挽留 2025-02-15 18:37:44

itemTemplatesElector (几个MS)。在 CollectionView 中完成时,这尤其可见。

达到条件模板绑定的一种方法是使用 ControlTemplate

这样您就可以:

  1. 为每个用例创建 ControlTemplate resourcectionary 中。
  2. 在您的视图中,添加 ControlTemplate 属性,该属性根据您的业务逻辑从您的资源中获取正确的 ControlTemplate
  3. 在您的XAML中,消耗模板asis &lt; contentView controlTemplate =“ {binding viewModel.template}”/&gt;

Circumventing ItemTemplateSelector as suggested by Alex is clever, but introduces some delays perceptible to end user (a few ms). This is particularly visible when done in CollectionView.

One way to acheive conditional template binding is to use ControlTemplate.

This way you can:

  1. Create a ControlTemplate for each of your use case in a ResourceDictionary.
  2. In your view model add a ControlTemplate property that fetch the correct ControlTemplate from your resource according to your business logic.
  3. In your xaml consume your template asis <ContentView ControlTemplate="{Binding ViewModel.Template}"/>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文