Saltar al contenido

Enlace de datacontext de wpf usando MVVM entre viewmodel y view

Si encuentras algún fallo con tu código o trabajo, recuerda probar siempre en un ambiente de testing antes aplicar el código al proyecto final.

Solución:

En primer lugar. Establecer dependencias de proyectos. ViewModel debe tener acceso Model. (Los proyectos de vista y modelo no tienen que hacer referencia a otros proyectos). Si yo fuera usted, haría un proyecto de inicio para transferir el control a ViewModel. Este proyecto “StartUp” debe ser WPF, todos los demás deben ser “biblioteca de clases”, pero no olvide agregar las referencias requeridas a los proyectos (por ejemplo, system.xaml para que su proyecto de vista cree controles de usuario).

Dependencias de proyectos: – Inicio -> ViewModel; (- ViewModel -> Ver; o evite esto con DI) – ViewModel -> Modelo; (Debería hacer otro proyecto para interfaces solo que estas son solo mis perversiones).

Proyecto de inicio: Ahora, en su proyecto de inicio (WPF) debe contener en (app.xaml.cs):

protected override void OnStartup(StartupEventArgs e)

    // delete the startupuri tag from your app.xaml
    base.OnStartup(e);
    //this MainViewModel from your ViewModel project
    MainWindow = new MainWindow(new MainViewModel());
 

La única cosa (Ventana) en su proyecto de inicio de wpf (para mostrar sus UserControls).

Contenido de MainWindow.xaml:


        

(y xaml.cs)

  public partial class MainWindow : Window
    
        public MainWindow(INotifyPropertyChanged ViewModel)
        
            InitializeComponent();
            this.DataContext = ViewModel;
            this.Show();
        
    

Y eso es todo su proyecto StartUp WPF. De esta forma le dimos el control a su proyecto ViewModel.

(Está bien, es solo un extra, pero debería hacer un “ViewService” para manejar mis UserControls)

Interfaz para encontrar todas las vistas y hacer coincidir la vista con ViewModel.

public interface IControlView

    INotifyPropertyChanged ViewModel  get; set; 

Creé un singleton para almacenar y hacer coincidir mis vistas con mis modelos de vista. (Puede omitir esta parte). Definí esto en Modelo proyecto.

 public class ViewService where T : IControlView
    
        private readonly List cache;

        public delegate void ShowDelegate(T ResultView);
        public event ShowDelegate Show;
        public void ShowControl(INotifyPropertyChanged ViewModel)
        
            if (Show != null)
                Show(GetView(ViewModel));
        

        #region Singleton

        private static ViewService instance;
        public static ViewService GetContainer
        
            get
            
                if (instance == null)
                
                    instance = new ViewService();
                
                return instance;
            
        

        private ViewService()
        
            cache = new List();
            var types = AppDomain.CurrentDomain.GetAssemblies().SelectMany(s => s.GetTypes()).Where(r => typeof(T).IsAssignableFrom(r) && !r.IsInterface && !r.IsAbstract && !r.IsEnum);

            foreach (Type type in types)
            
                cache.Add(new WeakReference((T)Activator.CreateInstance(type)));
            
        

        #endregion

        private T GetView(INotifyPropertyChanged ViewModel)
        
            T target = default(T);
            foreach (var wRef in cache)
            
                if (wRef.IsAlive && wRef.Target.GetType().IsEquivalentTo(typeof(Z)))
                
                    target = (T)wRef.Target;
                    break;
                
            

            if(target==null)
                target = (T)Activator.CreateInstance(typeof(Z));

            if(ViewModel != null)
                target.ViewModel = ViewModel;

            return target;
        

    

Y ahora tiene un “servicio” para mostrar sus UserControls en la ventana principal de su
ViewModel:

public class MainViewModel : INotifyPropertyChanged
    

        private IControlView _control;
        public IControlView Control
        
            get
            
                return _control;
            
            set
            
                _control = value;
                OnPropertyChanged();
            
        

        public MainViewModel()
           //Subscribe for the ViewService event:   
            ViewService.GetContainer.Show += ShowControl;
            // in this way, here is how to set a user control to the window.
            ViewService.GetContainer.ShowControl(new TheViewModel(yourDependencyItems));
           //you can call this anywhere in your viewmodel project. For example inside a command too.
        

        public void ShowControl(IControlView ControlView)
        
            Control = ControlView;
        

        //implement INotifyPropertyChanged...
        protected void OnPropertyChanged([CallerMemberName] string name = "propertyName")
        
           PropertyChangedEventHandler handler = PropertyChanged;
           if (handler != null)
           
               handler(this, new PropertyChangedEventArgs(name));
           
        

           public event PropertyChangedEventHandler PropertyChanged;
    

Si no desea utilizar este “ViewService”. Simplemente cree una instancia de UserControl, haga coincidir DataContext of View con su ViewModel y otorgue esta vista a la propiedad Control. Aquí está su ViewModel con lista (todavía en el proyecto ViewMoldel).

public class TheViewModel
    
        private readonly ObservableCollection listOfItems;
        public ObservableCollection ListOfItems 
        
            get  return listOfItems; 
        

        public ICommand SaveCheckedItemsText
            get return new RelayCommand(CollectNamesOfSelectedElements);
        

        public IEnumerable GetSelectedElements
        
            get  return listOfItems.Where(item=>item.CheckStatus); 
        

        public TheViewModel(IList dependencyItems)
        
            listOfItems= new ObservableCollection(dependencyItems);
        

        //here is your list...
        private List selectedNames

        //use this...
        private void CollectNamesOfSelectedElements()
        
           selectedNames = new List();
           foreach(ISelectable item in GetSelectedElements)
           
             //you should override the ToString in your model if you want to do this...
             selectedNames.Add(item.ToString());
           
        

    

Artículo de RelayCommand

Vista: (Guarde aquí todos sus controles de usuario).

En su UserControl (xaml):


Y con la interfaz aquí está el código xaml.cs (para UserControls):

public partial class ListViewDatabaseStyle : UserControl, IControlView
    
        public ListViewDatabaseStyle ()
        
            InitializeComponent();
        

        public INotifyPropertyChanged ViewModel
        
            get
            
                return (INotifyPropertyChanged)DataContext;
            
            set
            
                DataContext = value;
            
        
    

Y el ultimo es el Modelo proyecto con sus modelos:

 public interface ISelectable
    
        bool CheckStatus  get; set; 
    

public class CheckBoxListModel : INotifyPropertyChanged, ISelectable

    private string text;
    public string Text
    
        get  return text; 
        set
        
            text = value;
            RaiseChanged("Text");
        
    

    private bool checkStatus;
    public bool CheckStatus
    
        get  return checkStatus; 
        set
        
            checkStatus = value;
            RaiseChanged("CheckStatus");
        
    

    private void RaiseChanged(string propName)
    
        if (PropertyChanged != null)
        
            PropertyChanged(this, new PropertyChangedEventArgs(propName));
        
    

    public event PropertyChangedEventHandler PropertyChanged;
   
}

Disculpe los errores gramaticales en inglés, espero que haya entendido mi publicación.

Actualizar:
Utilice la técnica DI. para evitar la referencia a ver desde viewmodel. El servicio DI inyectará el objeto correcto con la inyección del constructor.

Nos puedes confirmar nuestra ocupación escribiendo un comentario y dejando una puntuación te damos las gracias.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *