0

Can anyone give out the best practices for playing around with controls at runtime such as creating a new view,adding views inside a view,adding controls to containers using MVVM pattern without breaking mvvm pattern??

I am using MVVMlight toolkit..

please help me out in this regard..

Thanks in advance......

1 Answers1

0

This post discusses the strategies for creating views (dialogs) from your view models.

Edit:

From your comment I take it that you got an user interface that has an add and delete button. The add button should add an item (type ?) to a ItemsControl ... hope that's correct.

So, how would I do this, well I would create a view model that has an ObservableCollecion<ItemViewModel>. The ItemViewModle is the view mode that represents the item that should be added to the ItemsControl (so in your case the view model backing your "rangeView").

Then I would add two commands that handle the addition and deletion of items. Both commands just add/remove ItemViewModels from your collection.

To show the items in the view I would bind the ItemControl.ItemsSource property to the collection in your main view model (i.e. the one holding the ItemViewModel instances). The I would supply an ItemTemplate to render the items on the screen.

Ok, here is an example of what I think you are trying to do (at least conceptionally). Complete Source Code here. In the example I used a ListBox as it allows me easily to determine which item is selected, this depends on your szenario. Also note that you have complete freedom to customize the Template, the ItemPanelTemplate, and DataTemplate to fit your needs. You can even use this approacht to create PanoramaPages in WP7!

2nd edit: ItemsControl does not have a SelectedItem property. To get to it you have to use a control inheriting from Selector (e.g. a ListBox as I did) or you can use the Selector directly.

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>
Community
  • 1
  • 1
AxelEckenberger
  • 16,628
  • 3
  • 48
  • 70
  • Dear Obalix,Thank you for the link..But it did not help me much..Let me tell you my scenario..I got a button for user to click and every click adds up a new view(rangeView) to itemscontrol in my main view.i willing to add delete functionality by clicking on the delete button on the rangeview.I know that im breaking mvvm.but could not find a better solution..and when user clicks on delete button i have to get the rangeview that has to be deleted in my viewmodel so that i can remove it from the observable collection bind to the itemscontrol in main view..Hope you got my scenario.. – Kedarnath kanaka Sep 14 '11 at 07:30
  • See Edit, and ... Obalix is fine ;-) – AxelEckenberger Sep 14 '11 at 22:41
  • Dear Obalix my heartfelt thanks to you.the solution you have suggested works for me.i am impressed.in the example you have suggested you are using a listbox and it has got a selected item property.well i have to use itemscontrol to hold my collection of items..Is there a way to get selected item in the itemscontrol bound to a property in viewmodel.... – Kedarnath kanaka Sep 15 '11 at 10:13
  • As I said, if the ItemsSource does not have a selected item, however your can either use a ListBox and change the styles, or you can use the `Selector` control ([see](http://bit.ly/p2VpA8) documentation). In facht I think the sample should work by replacing `ListBox` with `Selector` (not tested though). The using `Selector` instead of `ItemsSource` (your case) should also work as `Selector` inherits from `ItemsSource`. Oh yes, accepting the answer would be great (for us both), accepting and upvoting even better (for me) ... ;-) PS: see edit. – AxelEckenberger Sep 15 '11 at 11:39
  • Dear obalix thanks for everything I can say you saved me.....i gladly accepted your answer... – Kedarnath kanaka Sep 24 '11 at 07:41