使用MVVM模式动态创建视图和添加控件以查看的最佳实践是什么?

时间:2011-09-12 14:14:43

标签: c#-4.0 silverlight-4.0 mvvm-light

任何人都可以提供在运行时使用控件的最佳实践,例如创建新视图,在视图中添加视图,使用MVVM模式向容器添加控件而不破坏mvvm模式吗?

我正在使用MVVMlight工具包..

请在这方面帮助我..

提前致谢......

1 个答案:

答案 0 :(得分:0)

This post讨论了从视图模型创建视图(对话框)的策略。

修改

从你的评论中我认为你有一个带有添加和删除按钮的用户界面。添加按钮应该向ItemsControl添加一个项目(类型?)...希望这是正确的。

那么,我该怎么做呢,我会创建一个ObservableCollecion<ItemViewModel>的视图模型。 ItemViewModle是视图模式,表示应添加到ItemsControl的项目(因此在您的情况下支持“rangeView”的视图模型)。

然后我会添加两个处理项目添加和删除的命令。这两个命令只是从您的集合中添加/删除ItemViewModels

要显示视图中的项目,我会将ItemControl.ItemsSource属性绑定到主视图模型中的集合(即持有ItemViewModel实例的集合)。我会提供一个ItemTemplate来渲染屏幕上的项目。

好的,这是我认为你想要做的一个例子(至少在概念上)。 Complete Source Code here。在示例中,我使用了ListBox,因为它允许我轻松确定选择了哪个项目,这取决于您的szenario。另请注意,您可以完全自由地自定义Template,ItemPanelTemplate和DataTemplate以满足您的需求。您甚至可以使用此方法创建PanoramaPages in WP7

第二次修改ItemsControl没有SelectedItem属性。要实现它,您必须使用从Selector继承的控件(例如我所做的ListBox),或者您可以直接使用Selector

<强> ItemViewModel:

public class ItemViewModel : ViewModelBase
{
    #region [Name]

    public const string NamePropertyName = "Name";

    private string _name = null;

    public string Name {
        get {
            return _name;
        }

        set {
            if (_name == value) {
                return;
            }

            var oldValue = _name;
            _name = value;

            RaisePropertyChanged(NamePropertyName);
        }
    }

    #endregion
}

<强> MainViewModel:

public class MainViewModel : ViewModelBase
{
    public MainViewModel() {
        if (IsInDesignMode) {
            this.Items = new ObservableCollection<ItemViewModel>(Enumerable.Range(0, 10).Select((x, i) => new ItemViewModel() { Name = "Design Time Item " + i }));
        } else {
            // Code runs "for real"
        }
    }

    #region [AddCommand]

    private RelayCommand _addCommand;

    public RelayCommand AddCommand {
        get {
            return _addCommand ?? (_addCommand = new RelayCommand(
                () => {
                    this.Items.Add(new ItemViewModel() { Name = "New item - " + DateTime.Now });
                }
            ));
        }
    }

    #endregion

    #region [DeleteCommand]

    private RelayCommand _deleteCommand;

    public RelayCommand DeleteCommand {
        get {
            return _deleteCommand ?? (_deleteCommand = new RelayCommand(
                () => {
                    this.Items.Remove(this.SelectedItem);
                },
                () => { return this.SelectedItem != null; }
            ));
        }
    }

    #endregion

    #region [Items]

    public const string ItemsPropertyName = "Items";

    private ObservableCollection<ItemViewModel> _items = new ObservableCollection<ItemViewModel>();

    public ObservableCollection<ItemViewModel> Items {
        get {
            return _items;
        }

        set {
            if (_items == value) {
                return;
            }

            var oldValue = _items;
            _items = value;

            RaisePropertyChanged(ItemsPropertyName);
        }
    }

    #endregion

    #region [SelectedItem]

    public const string SelectedItemPropertyName = "SelectedItem";

    private ItemViewModel _selectedItem = null;

    public ItemViewModel SelectedItem {
        get {
            return _selectedItem;
        }

        set {
            if (_selectedItem == value) {
                return;
            }

            var oldValue = _selectedItem;
            _selectedItem = value;

            RaisePropertyChanged(SelectedItemPropertyName);

            // important in SL to notify command that can execute has changed !
            this.DeleteCommand.RaiseCanExecuteChanged();
        }
    }

    #endregion
}

<强> MainPage.xaml中

<UserControl 
    x:Class="MvvmLight1.MainPage"
    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"
    mc:Ignorable="d"
    Height="300"
    Width="300"
    DataContext="{Binding Main, Source={StaticResource Locator}}"
>

    <UserControl.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="Skins/MainSkin.xaml" />
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </UserControl.Resources>

    <Grid x:Name="LayoutRoot">
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition Height="auto"/>
        </Grid.RowDefinitions>
        <ListBox Grid.Row="0" ItemsSource="{Binding Items}" SelectedItem="{Binding SelectedItem, Mode=TwoWay}">
            <ListBox.ItemContainerStyle>
                <Style TargetType="ListBoxItem">
                    <Setter Property="HorizontalContentAlignment" Value="Stretch"/>
                    <Setter Property="Margin" Value="0"/>
                    <Setter Property="Padding" Value="0"/>
                </Style>
            </ListBox.ItemContainerStyle>
            <ListBox.ItemTemplate>
                    <DataTemplate>
                    <!-- we are dealing with ItemViewModels now -->
                    <Border BorderThickness="0,0,0,1" BorderBrush="Gray" Padding="10,5">
                        <TextBlock Text="{Binding Name}"/>
                    </Border>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
        <StackPanel Grid.Row="1" Orientation="Horizontal" HorizontalAlignment="Right">
            <Button Margin="5,10" Content="Add" Command="{Binding AddCommand}" Width="70"/>
            <Button Margin="5,10" Content="Delete" Command="{Binding DeleteCommand}" Width="70"/>
        </StackPanel>
    </Grid>
</UserControl>