【问题标题】:MVVM + UserControl + UserControl + DependencyPropertyMVVM + UserControl + UserControl + DependencyProperty
【发布时间】:2012-03-02 10:00:50
【问题描述】:

我有一个用户控件,它显示位于绑定到视图模型的另一个页面内的地址。 viewmodel 有一个原始的 User,它有一个 Address 对象的集合。用户控件将驻留在多个页面上,因此我希望能够通过依赖属性将其绑定到地址列表。虽然我目前的解决方案正在工作,但它的某些地方感觉不对,我想我会征求第二意见。为了简洁起见,我已经删掉了很多代码。

基本上,页面绑定到 usercontrols 代码中的依赖属性,然后通过设置它的 itemsource 来更新 usercontrol 的数据网格。在我看来,这打破了 MVVM 的基本租户。

AddressListView 控件:

<UserControl x:Class="Insight.Controls.AddressListView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"
    xmlns:tk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/toolkit"
    xmlns:command="clr-namespace:PrismFramework.Implementors.Commanding;assembly=PrismFramework"
    mc:Ignorable="d"
    d:DesignHeight="300" d:DesignWidth="840">

    <UserControl.Resources>
        <command:ObservableCommand x:Name="EditAddressCommand" Value="{Binding EditAddressCmd}"/>
        <command:ObservableCommand x:Name="DeleteAddressCommand" Value="{Binding DeleteAddressCmd}"/>
    </UserControl.Resources>

    <Grid x:Name="LayoutRoot" Background="White">
        <sdk:DataGrid Name="dgAddresses" 
                    Height="Auto" 
                    Width="Auto" 
                    AutoGenerateColumns="False" 
                    HeadersVisibility="None" >
            <sdk:DataGrid.Columns>
                <sdk:DataGridTemplateColumn x:Name="dgcAddresses" 
                            Width="*" >
                    <sdk:DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <Border x:Name="bdrAddress" 
                                    HorizontalAlignment="Stretch"
                                    VerticalAlignment="Stretch"
                                    Height="Auto"
                                    Width="Auto"
                                    BorderBrush="Silver"  
                                    BorderThickness="1" 
                                    Padding="0" 
                                    Margin="1,1,1,1">
                                <Grid x:Name="grdAddressItem"
                                        HorizontalAlignment="Stretch"
                                        VerticalAlignment="Stretch"
                                        Height="Auto" 
                                        Width="Auto">
                                    <Grid.RowDefinitions>
                                        <RowDefinition Height="17" MinHeight="17"/>
                                        <RowDefinition Height="17" MinHeight="17"/>
                                        <RowDefinition Height="17" MinHeight="17"/>
                                        <RowDefinition Height="17" MinHeight="17"/>
                                        <RowDefinition Height="17" MinHeight="17"/>
                                        <RowDefinition Height="17" MinHeight="17"/>
                                        <RowDefinition Height="17" MinHeight="17"/>
                                    </Grid.RowDefinitions>
                                    <Grid.ColumnDefinitions>
                                        <ColumnDefinition Width="70"/>
                                        <ColumnDefinition Width="55" />
                                        <ColumnDefinition Width="*" />
                                        <ColumnDefinition Width="Auto" />
                                    </Grid.ColumnDefinitions>
                                    <TextBlock Padding="0,0,5,0" Text="Type:" TextAlignment="Right" />
                                    <TextBlock Grid.Column="1" Padding="0" Text="{Binding Path=AType}" Grid.ColumnSpan="2" />
                                    <TextBlock Grid.Row ="1" Grid.Column="0" Padding="0,0,5,0" Text="Address 1:" TextAlignment="Right" />
<!-- List Of Similar Fields ->
                                    <Grid x:Name="grdAddressEditOptions" 
                                            HorizontalAlignment="Stretch"
                                            VerticalAlignment="Stretch"
                                            Height="Auto"
                                            Width="Auto"
                                            Grid.Column="3"
                                            Grid.RowSpan="7" >
                                        <Grid.RowDefinitions>
                                            <RowDefinition Height="Auto" />
                                            <RowDefinition Height="*" />
                                            <RowDefinition Height="Auto" />
                                        </Grid.RowDefinitions>
                                        <Button x:Name="btnEdit"
                                                HorizontalAlignment="Stretch"
                                                VerticalAlignment="Stretch"
                                                Height="Auto"
                                                Width="Auto"
                                                Grid.Row="0"
                                                Padding="4,5,4,8"
                                                Margin="0,8,10,0"
                                                Command="{Binding Value, Source={StaticResource EditAddressCommand}}"
                                                CommandParameter="{Binding}" >
                                            <Button.Content>
                                                <Image x:Name="btnEditIcon"
                                                        HorizontalAlignment="Center"
                                                        VerticalAlignment="Center"
                                                        Height="Auto"
                                                        Width="Auto"
                                                        Source="/Insight.ModuleUser;component/Images/edit.png" 
                                                        Visibility="Visible" />
                                            </Button.Content>
                                        </Button>
                                        <Button x:Name="btnDelete"
                                                HorizontalAlignment="Stretch"
                                                VerticalAlignment="Stretch"
                                                Height="Auto"
                                                Width="Auto"
                                                Grid.Row="2"
                                                Padding="4,5,4,8"
                                                    Margin="0,0,10,5"
                                                Command="{Binding Value, Source={StaticResource  DeleteAddressCommand}}"
                                                CommandParameter="{Binding}" >
                                            <Button.Content>
                                                <Image x:Name="btnDeleteIcon"
                                                            HorizontalAlignment="Center"
                                                            VerticalAlignment="Center"
                                                            Height="Auto"
                                                            Width="Auto"
                                                            Source="/Insight.ModuleUser;component/Images/delete.png" 
                                                            Visibility="Visible" />
                                            </Button.Content>
                                        </Button>
                                    </Grid>
                                </Grid>
                            </Border>
                        </DataTemplate>
                    </sdk:DataGridTemplateColumn.CellTemplate>
                </sdk:DataGridTemplateColumn>
            </sdk:DataGrid.Columns>
        </sdk:DataGrid>
    </Grid>
</UserControl>

AddressListView后面的代码:

Imports System.Collections.ObjectModel
Imports Insight.DataServices.Primitives

Partial Public Class AddressListView
Inherits UserControl

Public ReadOnly AddressesProperty As DependencyProperty = DependencyProperty.Register("Addresses", GetType(ObservableCollection(Of Address)), GetType(AddressListView), New PropertyMetadata(Nothing, New PropertyChangedCallback(AddressOf OnAddressesChanged)))

Public Sub New()
    InitializeComponent()
End Sub

Public Property Addresses As ObservableCollection(Of Address)
    Get
        Return DirectCast(GetValue(AddressesProperty), ObservableCollection(Of Address))
    End Get
    Set(value As ObservableCollection(Of Address))
        SetValue(AddressesProperty, value)
    End Set
End Property

Public Sub OnAddressesChanged()
    Me.dgAddresses.ItemsSource = Addresses
End Sub

End Class

基本页面:

<UserControl x:Class="Insight.ModuleUser.Views.EditUserView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"    
    xmlns:prism="clr-namespace:Microsoft.Practices.Prism.Interactivity.InteractionRequest;assembly=Microsoft.Practices.Prism.Interactivity"
    xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"  
    xmlns:cm="clr-namespace:System.ComponentModel;assembly=System.Windows"
    xmlns:data="clr-namespace:System.Windows.Data;assembly=System.Windows"
    xmlns:vm="clr-namespace:Insight.ModuleUser.ViewModels"
    xmlns:command="clr-namespace:PrismFramework.Implementors.Commanding;assembly=PrismFramework"
    xmlns:controls="clr-namespace:Insight.Controls;assembly=Insight.Controls"
    xmlns:modalDialogs="clr-namespace:Insight.Controls.ModalDialogViews;assembly=Insight.Controls"
    mc:Ignorable="d"
    d:DesignHeight="500" d:DesignWidth="1144" 
    d:DataContext="{d:DesignData /Insight.ModuleUser;component/SampleData/EditUserViewModelSampleData.xaml}">

    <UserControl.Resources>
        <command:ObservableCommand x:Name="OpenProjectCommand" Value="{Binding OpenProjectCmd}"/>
        <command:ObservableCommand x:Name="OpenPaymentCommand" Value="{Binding OpenPaymentCmd}"/>
        <command:ObservableCommand x:Name="OpenInvoiceCommand" Value="{Binding OpenInvoiceCmd}"/>
        <command:ObservableCommand x:Name="OpenPaymentItemCommand" Value="{Binding OpenPaymentItemCmd}"/>

        <command:ObservableCommand x:Name="EditPhoneCommand" Value="{Binding EditPhoneNumberCmd}"/>
        <command:ObservableCommand x:Name="DeletePhoneCommand" Value="{Binding DeletePhoneNumberCmd}"/>
        <command:ObservableCommand x:Name="EditEmailAddressCommand" Value="{Binding EditEmailAddressCmd}"/>
        <command:ObservableCommand x:Name="DeleteEmailAddressCommand" Value="{Binding DeleteEmailAddressCmd}"/>

    </UserControl.Resources>

    <Grid x:Name="LayoutRoot" >


                <controls:AddressListView x:Name="ctrlAddressListView" 
                    Addresses="{Binding User.Addresses}" />

    </Grid>
</UserControl>

【问题讨论】:

    标签: silverlight mvvm user-controls dependency-properties


    【解决方案1】:

    这似乎是一个非常合理的方法。但是,您可以在用户控件视图中使用绑定,而不是在代码中设置项目源。

    为此,您需要将用户控件的DataContext 设置为您的用户控件类型。这可以在用户控件背后的代码中完成(设置this.DataContext = this),也可以通过 XAML 中的元素绑定来完成:

    <UserControl
    ...
     x:Name="MyName"
     DataContext="{Binding ElementName=MyName}"
    

    但是,我的方法是根本不使用用户控件,因为您真正谈论的是视图组合以及在其他视图之间重用视图的特定部分。

    使用 MVVM 框架(例如 Caliburn.Micro),视图组合非常简单。在这种情况下,您将拥有AddressViewModelAddressView,并使用ContentControlAddressView 注入基本视图:

    <ContentControl x:Name="AddressViewModel" />
    

    【讨论】:

    • 我同意这个非常简单。这是我对其他几个人的概念证明,我拥有的多个嵌套控件等复杂得多。我不熟悉 DependencyProperties,所以我想确保我使用的是最佳实践方法,而不是从臀部射击,然后后来发现我在踢自己的脚。 :)
    猜你喜欢
    • 2012-06-06
    • 2015-02-16
    • 2013-06-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多