簡體   English   中英

Windows 10 Universal編譯綁定(x:Bind)與ViewModel沖突

[英]Windows 10 Universal Compiled binding (x:Bind) conflict with ViewModel

我想將頁面中的元素綁定到帶有編譯綁定的代碼中的依賴屬性,同時使用常規綁定將另一個元素綁定到ViewModel。 但它給出了運行時錯誤。

這是我的xaml代碼。

<Page
x:Class="XbindingProblem.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:XbindingProblem"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
DataContext="{Binding Main, Source={StaticResource Locator}}"
mc:Ignorable="d">
<Page.Resources>
    <DataTemplate x:Key="UserDataTemplate" x:DataType="local:User">
        <StackPanel>
            <TextBlock Text="{x:Bind Name}" />
            <TextBlock Text="{x:Bind Age}" />
        </StackPanel>
    </DataTemplate>
</Page.Resources>
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <StackPanel>
        <TextBlock Text="{Binding Title}"/>
        <ContentPresenter ContentTemplate="{StaticResource UserDataTemplate}" Content="{x:Bind CurrentUser, Mode=OneWay}"/>
    </StackPanel>        
</Grid>

這里CurrentUser是依賴屬性,它最初為null,然后在運行時更改。 這會產生以下運行時錯誤。

Incorrect type passed into template. Based on the x:DataType global::XbindingProblem.User was expected.

問題是當CurrentUser為null時,它將ViewModel傳遞給UserDataTemplate而不是CurrentUser依賴屬性。

誰能對這個問題有一個很好的解釋?

如果刪除DataContext="{Binding Main, Source={StaticResource Locator}}" ,它將起作用。 為什么? 因為{x:Bind CurrentUser}正在尋找位於MainPage.xaml.cs內的名為CurrentUser的屬性。 由於CurrentUser確實是頁面的依賴屬性,因此它將起作用。

但是,通過指定頁面的DataContextx:Bind現在除了MainViewModel實例中的CurrentUser屬性外,當然它不會找到它,因此會拋出編譯時錯誤。

一個可能的解決方法是在調用InitializeComponent之前很早就設置this.CurrentUser

this.CurrentUser = new User();

InitializeComponent();

但這是恕我直言,不是正確的做事方式,因為它基本上是一個賽車游戲 - 它試圖在DataContext更新之前填充ContentPresenter ,最后你將得到TextBlock (其中Text綁定到Title )和ContentPresenter附加到不同的上下文!

那么問問自己為什么需要在Page對象中為CurrentUser創建一個依賴項屬性,而不是在MainViewModel中有一個普通的屬性(使用INotifyPropertyChanged實現)? 我更喜歡后者,因為它在語義上更正確。

問題很有趣,我所做的只是刪除datacontext,這背后的代碼與你的類似:

public sealed partial class BlankPage1 : Page
{
    public User CurrentUser
    {
        get { return (User)GetValue(CurrentUserProperty); }
        set { SetValue(CurrentUserProperty, value); }
    }

    // Using a DependencyProperty as the backing store for CurrentUser.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty CurrentUserProperty =
        DependencyProperty.Register("CurrentUser", typeof(User), typeof(BlankPage1), new PropertyMetadata(null));

    public BlankPage1()
    {
        this.InitializeComponent();

        CurrentUser = new User() { Name = "Hello", Age = "20" };
    }
}

public class User
{
    public String Name { get; set; }
    public String Age { get; set; }
}

可能是您在另一個命名空間中有User類,或者在依賴項屬性的typeof(...)中有另一個類。 因為我測試了它並且有效。 頁面的DataContext可以是您想要的任何不會影響的內容。

然后我添加了datacontext來測試:

<Page.DataContext>
    <local:Main/>
</Page.DataContext>

以及用於測試的代碼:

public class Main
{
    public String Title { get; } = "title";
    public User MainUser { get; set; }
}

並且它不會拋出任何異常,顯示主數據和CurrentUser數據。

UPDATE。 當User為null時發生錯誤,因此它就像x:Bind為null它傳播到Binding,為了解決這個問題(很難):

<Page x:Name="Root"
    x:Class="Deletetb.BlankPage1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:Deletetb"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d" >
    <Page.DataContext>
        <local:Main/>
    </Page.DataContext>

    <Page.Resources>
        <DataTemplate x:Key="UserDataTemplate" x:DataType="local:User">
            <StackPanel>
                <TextBlock Text="{x:Bind Name}" />
                <TextBlock Text="{x:Bind Age}" />
            </StackPanel>
        </DataTemplate>
    </Page.Resources>
    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <StackPanel DataContext="{x:Null}">
            <TextBlock Text="{Binding DataContext.Title, ElementName=Root}" />
            <ContentPresenter  ContentTemplate="{StaticResource UserDataTemplate}" Content="{x:Bind CurrentUser, Mode=OneWay}"/>
        </StackPanel>
    </Grid>
</Page>

綁定定義的位置(TextBlock)我在父容器(StackPanel)中將datacontext設置為null並按元素名稱綁定,並且它不會崩潰,我還添加了等待代碼來測試和設置當前用戶並且它可以正常工作。 這是一個挑戰。 希望它也適合你。

雖然它打破了MVVM的想法,但您可以像這樣向頁面添加屬性:

public MainViewModel viewModel => DataContext as MainViewModel;

然后在XAML代碼中引用頁面屬性

<ContentPresenter Content="{x:Bind viewModel.CurrentUser, Mode=OneWay}" />

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM