none
Aplicação Silverlight com MVVM e MEF RRS feed

  • Pergunta

  • Bom dia.

    Estou estudando os conceitos sobre MVVM e MEF e tenho algumas dúvidas para iniciar o desenvolvimento.

    Na janela principal do Sistema tenho 5 botões. No clique de cada botão ele deverá carregar dinamicamente um controle Accordion que fica nesta mesma janela ao lado esquerdo

    Usando o conceito de MEF:

    Para cada Item do Accordion, eu criei um projeto Silverlight separado de modo que o download de cada projeto é realizado de acordo com a seleção do accordion. Esta correto esta divisão de projetos? Este sistema será grande.

    Usando o conceito de MVVM:

    O menu accordion será criado dinamicamente baseado no clique dos botões. Como tenho 5 botões, eu terei 5 estruturas diferentes para o menu esquerdo (accordion). Como devo criar estas interfaces usando MVVM? Devo criar as estruturas dos 5 menus no proprio xaml e ir habilitando e desabilitando conforme a necessidade ou devo criar via codigo c# na viewmodel de acordo com a seleção? 

    Outra questão: Além dos itens do menu serem carregados dinamicamente, pode ser que um determinado usuario não tenha permissão para visualizar o item 3 do menu. Neste caso para este usuario ele não deverá ser carregado. 

    Estou com dúvidas, alguém pode me ajudar?

    Att.

    Teles

    terça-feira, 21 de agosto de 2012 12:14

Respostas

  • Oi Teles,

        No momento não tive tempo pra testar... mas seria algo assim:

    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Text;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Input;
    using System.Xml.Serialization;
    
    namespace SilverlightApplication2.NewFolder1 {
        public class Menu: Accordion {
            public static readonly DependencyProperty MenuItemsSourceProperty = DependencyProperty.Register("MenuItemsSource", typeof(string), typeof(Menu), new PropertyMetadata(null, MenuItemsSourcePropertyChangedCallback));
            public static readonly DependencyProperty MenuItemsProperty = DependencyProperty.Register("MenuItems", typeof(IEnumerable<MenuItem>), typeof(Menu), new PropertyMetadata(null, MenuItemsPropertyChangedCallback));
            public static readonly DependencyProperty CommandProperty = DependencyProperty.Register("Command", typeof(ICommand), typeof(Menu), new PropertyMetadata(null));
            public static readonly DependencyProperty CommandParameterProperty = DependencyProperty.Register("CommandParameter", typeof(object), typeof(Menu), new PropertyMetadata(null));
    
            public static void MenuItemsPropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e) {
                if (d is Menu) {
                    var root = (d as Menu);
                    root.Items.Clear();
    
                    var value = (IEnumerable<MenuItem>)e.NewValue;
                    if (value == null) return;
    
                    foreach (MenuItem menu in value) {
                        var panel = new StackPanel();
                        foreach (string item in menu.Items) {
                            var link = new HyperlinkButton { Content = item };
                            link.Click += root.OnMenuLinkClick;
                            panel.Children.Add(link);
                        }
    
                        root.Items.Add(new AccordionItem {
                            Header = menu.Header,
                            Content = panel
                        });
                    }
                }
            }
    
            public static void MenuItemsSourcePropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e) {
                if (d is Menu) {
                    var root = (d as Menu);
                    var value = (String)e.NewValue;
                    if (String.IsNullOrWhiteSpace(value)) {
                        root.MenuItems = null;
                    } else {
                        root.MenuItems = SilverlightApplication2.NewFolder1.MenuItems.Parse(value);
                    }
                }
            }
    
            public string MenuItemsSource {
                get { return (string)GetValue(MenuItemsSourceProperty); }
                set { SetValue(MenuItemsSourceProperty, value); }
            }                     
            public IEnumerable<MenuItem> MenuItems {
                get { return (IEnumerable<MenuItem>)GetValue(MenuItemsProperty); }
                set { SetValue(MenuItemsProperty, value); }
            }
            public ICommand Command {
                get { return (ICommand)GetValue(CommandProperty); }
                set { SetValue(CommandProperty, value); }
            }
    
            private void OnMenuLinkClick(object sender, RoutedEventArgs e) {
                if (sender is HyperlinkButton) {
                    var link = (sender as HyperlinkButton);
                    var item = link.Content;
                    if (this.Command != null && this.Command.CanExecute(item)) {
                        this.Command.Execute(item);
                    }
                }
            }
        }
    
        [XmlRoot("Menu")]
        public class MenuItems {
            [XmlAttribute("header")]
            public string Header { get; set; }
    
            [XmlElement("item")]
            public string[] Items { get; set; }
    
            public static IEnumerable<MenuItem> Parse(string xml) {
                using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(xml))) {
                    var formatter = new XmlSerializer(typeof(MenuItem[]));
                    return (MenuItem[])formatter.Deserialize(stream);
                }
            }
        }
    }
    
    

    Dessa forma voce faria um Binding nas propriedade MenuItensSource passando o XML e no Command para saber qual menu foi clicado...

    o xml seria assim:

    <ArrayOfMenuItem>
    <Menu header="Teste">
        <item>aaaaa</item>
        <item>aaaaa</item>
        <item>aaaaa</item>
    </Menu>
    <Menu header="Teste">
        <item>aaaaa</item>
        <item>aaaaa</item>
        <item>aaaaa</item>
    </Menu>
    <Menu header="Teste">
        <item>aaaaa</item>
        <item>aaaaa</item>
        <item>aaaaa</item>
    </Menu>
    </ArrayOfMenuItem>


    Microsoft Community Contributor

    • Marcado como Resposta Teles quarta-feira, 22 de agosto de 2012 19:51
    quarta-feira, 22 de agosto de 2012 14:38
    Moderador

Todas as Respostas

  • Ola Teles,

         O Seu menu ira possuir muitos subniveis ? porque o que vc pode fazer é trocar o accordion por um DataGrid ou ListBox, dessa forma o seu pacote apenas retornaria um array de string de menus, que voce pode carregar via binding na propriedade ItemSource e caputrar a seleção do menu so "set" da propriedade Item do mesmo.

         Se não for, voce pode criar uma interface para passar a hirearquia do menu, ou usar uma string xml, e criar um UserContro que popularia o seu menu e retornaria uma propriedade sempre que um item for selecionado. Se precisar de uma ajuda nesse componente da um toque.

         Sobre o controle de acesso, na sua interface dos pacotes vc pode colocar um metodo para passar o usuario e sempre chamar esse metodo apos a carga do pacote, assim cada pacote pode controlar quais menus ele teria acesso quando for executado o metodo para retornar a lista dos menus...

    Qualquer duvida é so perguntar


    Microsoft Community Contributor

    terça-feira, 21 de agosto de 2012 16:45
    Moderador
  • Bom dia Rui.

    Não haverá subniveis, somente os itens. Pensei em usar um arquivo xml para montar o menu.

    Ao abrir o sistema ele deverá checar algumas configurações e saber o que deverá ser carregado nos menus. 

    Se puder me passar um exemplo de como ficaria este UserControl populando o menu e retornando uma propriedade, eu agradeço.

    Att.

    Teles

    quarta-feira, 22 de agosto de 2012 12:47
  • Oi Teles,

        No momento não tive tempo pra testar... mas seria algo assim:

    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Text;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Input;
    using System.Xml.Serialization;
    
    namespace SilverlightApplication2.NewFolder1 {
        public class Menu: Accordion {
            public static readonly DependencyProperty MenuItemsSourceProperty = DependencyProperty.Register("MenuItemsSource", typeof(string), typeof(Menu), new PropertyMetadata(null, MenuItemsSourcePropertyChangedCallback));
            public static readonly DependencyProperty MenuItemsProperty = DependencyProperty.Register("MenuItems", typeof(IEnumerable<MenuItem>), typeof(Menu), new PropertyMetadata(null, MenuItemsPropertyChangedCallback));
            public static readonly DependencyProperty CommandProperty = DependencyProperty.Register("Command", typeof(ICommand), typeof(Menu), new PropertyMetadata(null));
            public static readonly DependencyProperty CommandParameterProperty = DependencyProperty.Register("CommandParameter", typeof(object), typeof(Menu), new PropertyMetadata(null));
    
            public static void MenuItemsPropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e) {
                if (d is Menu) {
                    var root = (d as Menu);
                    root.Items.Clear();
    
                    var value = (IEnumerable<MenuItem>)e.NewValue;
                    if (value == null) return;
    
                    foreach (MenuItem menu in value) {
                        var panel = new StackPanel();
                        foreach (string item in menu.Items) {
                            var link = new HyperlinkButton { Content = item };
                            link.Click += root.OnMenuLinkClick;
                            panel.Children.Add(link);
                        }
    
                        root.Items.Add(new AccordionItem {
                            Header = menu.Header,
                            Content = panel
                        });
                    }
                }
            }
    
            public static void MenuItemsSourcePropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e) {
                if (d is Menu) {
                    var root = (d as Menu);
                    var value = (String)e.NewValue;
                    if (String.IsNullOrWhiteSpace(value)) {
                        root.MenuItems = null;
                    } else {
                        root.MenuItems = SilverlightApplication2.NewFolder1.MenuItems.Parse(value);
                    }
                }
            }
    
            public string MenuItemsSource {
                get { return (string)GetValue(MenuItemsSourceProperty); }
                set { SetValue(MenuItemsSourceProperty, value); }
            }                     
            public IEnumerable<MenuItem> MenuItems {
                get { return (IEnumerable<MenuItem>)GetValue(MenuItemsProperty); }
                set { SetValue(MenuItemsProperty, value); }
            }
            public ICommand Command {
                get { return (ICommand)GetValue(CommandProperty); }
                set { SetValue(CommandProperty, value); }
            }
    
            private void OnMenuLinkClick(object sender, RoutedEventArgs e) {
                if (sender is HyperlinkButton) {
                    var link = (sender as HyperlinkButton);
                    var item = link.Content;
                    if (this.Command != null && this.Command.CanExecute(item)) {
                        this.Command.Execute(item);
                    }
                }
            }
        }
    
        [XmlRoot("Menu")]
        public class MenuItems {
            [XmlAttribute("header")]
            public string Header { get; set; }
    
            [XmlElement("item")]
            public string[] Items { get; set; }
    
            public static IEnumerable<MenuItem> Parse(string xml) {
                using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(xml))) {
                    var formatter = new XmlSerializer(typeof(MenuItem[]));
                    return (MenuItem[])formatter.Deserialize(stream);
                }
            }
        }
    }
    
    

    Dessa forma voce faria um Binding nas propriedade MenuItensSource passando o XML e no Command para saber qual menu foi clicado...

    o xml seria assim:

    <ArrayOfMenuItem>
    <Menu header="Teste">
        <item>aaaaa</item>
        <item>aaaaa</item>
        <item>aaaaa</item>
    </Menu>
    <Menu header="Teste">
        <item>aaaaa</item>
        <item>aaaaa</item>
        <item>aaaaa</item>
    </Menu>
    <Menu header="Teste">
        <item>aaaaa</item>
        <item>aaaaa</item>
        <item>aaaaa</item>
    </Menu>
    </ArrayOfMenuItem>


    Microsoft Community Contributor

    • Marcado como Resposta Teles quarta-feira, 22 de agosto de 2012 19:51
    quarta-feira, 22 de agosto de 2012 14:38
    Moderador
  • Vou testar. obrigado
    quarta-feira, 22 de agosto de 2012 19:52