MVVM uwp UserControl与VM作为DataTemplate

4

我将尝试使用MVVM模式在UWP中创建一个应用程序。

Listbox的每个项目都有一个DataTemplate,此处可能有一个用户控件(usercontrol),它拥有自己的VM。

下面是MainPage.xaml的一部分:

 <ListBox Name="ListBox1" ItemsSource="{Binding Components}">
            <ListBox.ItemTemplate >
                <DataTemplate x:DataType="vm:ComponentUserControlViewModel"  >
                    <local:ComponentUserControl />
                </DataTemplate>
            </ListBox.ItemTemplate>
 </ListBox>

MainPageVM包含以下内容:

public ObservableCollection<Component> Components

现在这是我的用户控件

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <Grid.RowDefinitions>
        <RowDefinition Height="*"></RowDefinition>
        <RowDefinition Height="*"></RowDefinition>
    </Grid.RowDefinitions>
    <TextBox Text="{Binding Id}" Grid.Row="0"></TextBox>
    <TextBox Text="{Binding Name}" Grid.Row="1"></TextBox>

</Grid>

VM:

    public class ComponentUserControlViewModel : ViewModelBase
{
    private string _componentId;
    private string _componentName;

    public ComponentUserControlViewModel()
    {
    }

    public string Id
    {
        get { return _componentId; }
        set
        {
            SetProperty(ref _componentId, value);
        }
    }
    public string Name
    {
        get { return _componentName; }
        set
        {
            SetProperty(ref _componentName, value);
        }
    }

我希望的是,例如,如果我在我的用户界面中更改Id属性,那么视图模型Id属性也会随之更改。

你的 ComponentUserControl 需要一个(依赖)属性,这样你就可以使用 <local:ComponentUserControl Component="{Binding}" /> - Kris Vandermotten
你能具体一点吗?我添加了这个属性,但是该如何使用它我不知道。我不知道它应该如何工作。 - Krystian Kuśmierek
1个回答

5

克里斯所说的是真的,你需要使用依赖属性来实现你想要的功能。

简言之,你可以拥有两种类型的属性:像 ViewModel 中的 Id 和 Name 这样的传统属性,以及依赖属性。 (当然还有附加属性,但从概念上讲,它们与依赖属性相同)。这两种属性类型之间的主要区别在于,虽然这两种类型都可以成为数据绑定的目标,但只有依赖属性可以成为数据绑定的源。这正是你所需要的。

因此,为了解决你的问题,我们需要一个依赖属性,在你的控件的代码后台中进行定义。让我们把这个属性称为“Component”,就像克里斯在他的回答中所做的那样:

public static readonly DependencyProperty ComponentProperty = DependencyProperty.Register(
    "Component",
    typeof(ComponentUserControlViewModel), 
    typeof(ComponentUserControl), 
    new PropertyMetadata(null));
    
public ComponentUserControlViewModel Component
{
    get { return (ComponentUserControlViewModel) GetValue(ComponentProperty); }
    set { SetValue(ComponentProperty, value); }
}
    

现在,如果你将UserControl的绑定更改为这些(注意Mode=OneWay,x:Bind默认是OneTime!更多信息请参见此处):

<TextBox Text="{x:Bind Component.Id, Mode=OneWay}" Grid.Row="0" />
<TextBox Text="{x:Bind Component.Name, Mode=OneWay}" Grid.Row="1" />

请将您的DataTemplate内容替换为Kris提供的内容:

<local:ComponentUserControl Component="{Binding}" />

神奇的事情将会发生,所有这些都会起作用! :) 如果您对此有更多问题,请查看此依赖属性的官方概述


我的项目源类型是Component而不是ComponentViewModel...我在思考上也有一些逻辑错误,感谢您的答案,最终我做到了。我还有一个问题,这个"Component="{Binding}"没有任何后面的内容,如何绑定数据上下文? - Krystian Kuśmierek
绑定以DataContext作为起点开始,如果您不明确地告诉它以另一种方式执行,则会按此方式执行。因此,当您编写例如{Binding Id}时,它将绑定到控件的DataContext的Id属性。在这种情况下,ListView根据您的DataTemplate设置每个创建的项的DataContext,因此每个ComponentUserControl的DataContext在此情况下都是一个组件(在我的答案中是ComponentViewModel)。要将依赖属性绑定到它,只需绑定到DataContext,这等同于编写{Binding}。希望这可以帮助! - Péter Bozsó

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接