MVVM + UserControl + UserControl + DependencyProperty

时间:2012-02-09 21:40:02

标签: silverlight mvvm user-controls dependency-properties

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

基本上,页面绑定到usercontrols代码中的依赖项属性,然后通过设置它的itemsource来更新usercontrol的datagrid。在我看来,这打破了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>

1 个答案:

答案 0 :(得分:1)

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

要执行此操作,您需要将用户控件的DataContext设置为您的用户控件类型。这可以在用户控件的后台代码(设置this.DataContext = this)或XAML中的元素绑定中完成:

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

然而,我的方法是根本不使用用户控件,因为你真正谈论的是视图合成并在其他视图之间重用视图的特定部分。

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

<ContentControl x:Name="AddressViewModel" />