![](/img/trans.png)
[英]Binding Page with ViewModel (MVVM) on Universal Windows App
[英]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
確實是頁面的依賴屬性,因此它將起作用。
但是,通過指定頁面的DataContext
, x: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.