и ProjectVarioViewModel выполнить реализацию iProjectViewModel . Первый из каждого получает один экземпляр своего представления, но следующий из одного типа получит один и тот же экземпляр представления, что и первый, что является проблематичным, поскольку первое представление, потом не совпадает с последующими видами. Другой. Тот же тип тела и один экземпляр зрения на просмотр модели в заголовке? И как получить один экземпляр просмотра на просмотр модели в теле? Чтобы проверить это визуально, создайте как минимум 2 проекта одного и того же типа и убедитесь, что уникальный ID представления одинаков.
Когда я удаляю полностью tabcontrol.itemcontainerstyle , я получаю 1 экземпляр просмотра на заголовок Tabitem, но только 1 экземпляр просмотра в содержании Tabitem, как показано на рисунке ниже:
Когда я выбираю Tabitem, нажав на заголовок, я получаю правильное изменение ViewModel, но экземпляр View подтверждается, чтобы быть одинаковым для всех видов, экземпляра, то же самое. Mainwindow.xaml :
У меня есть TabControl Показ представлений из ObservableCollection Projects . [code]ProjectViewModel[/code] и ProjectVarioViewModel выполнить реализацию iProjectViewModel . Первый из каждого получает один экземпляр своего представления, но следующий из одного типа получит один и тот же экземпляр представления, что и первый, что является проблематичным, поскольку первое представление, потом не совпадает с последующими видами. Другой. Тот же тип тела и один экземпляр зрения на просмотр модели в заголовке? И как получить один экземпляр просмотра на просмотр модели в теле? Чтобы проверить это визуально, создайте как минимум 2 проекта одного и того же типа и убедитесь, что уникальный ID представления одинаков.[code]
[/code] Когда я удаляю полностью tabcontrol.itemcontainerstyle , я получаю 1 экземпляр просмотра на заголовок Tabitem, но только 1 экземпляр просмотра в содержании Tabitem, как показано на рисунке ниже:
Когда я выбираю Tabitem, нажав на заголовок, я получаю правильное изменение ViewModel, но экземпляр View подтверждается, чтобы быть одинаковым для всех видов, экземпляра, то же самое. Mainwindow.xaml : [code]
new tri new vario
< /code> Просмотреть модели: < /p> using System.Collections.ObjectModel; using System.ComponentModel; using System.Runtime.CompilerServices; using System.Windows.Input;
namespace MultiTab;
public interface IProjectViewModel : ICloneable { public string ProjectTitle { get; set; } public float Margin { get; set; } public int W { get; } public int H { get; } }
public class Project : IProjectViewModel { public Project(string name) { ProjectTitle = name; } public float Margin { get; set; } public string ProjectTitle { get; set; } public int W { get; protected set; } public int H { get; protected set; } public object Clone() => MemberwiseClone(); public override string ToString() => $"{ProjectTitle} {W}x{H}"; }
public class ProjectViewModel : Project { public ProjectViewModel(string name) : base(name) { W = 2; H = 2; } }
public class ProjectVarioViewModel : Project { private Random _r = new(); public ProjectVarioViewModel(string name) : base(name) { W = _r.Next(2, 16); H = _r.Next(2, 16); } }
public enum ProjectType { Triptych, Vario, }
public class MainViewModel : INotifyPropertyChanged { private IProjectViewModel? _selectedProject; private DelegateCommandListen? _newProjectCommand; private ICommand? _closeProjectCommand;
public ObservableCollection Projects { get; } = new();
public IProjectViewModel? SelectedProject { get => _selectedProject; set => SetField(ref _selectedProject, value); }
public ICommand NewProjectCommand { get { return _newProjectCommand ?? (_newProjectCommand = new DelegateCommandListen( s => { var ptype = _argToProjectType[(string) s]; var name = $"{GetNewProjectTitle()} [{ptype.ToString()}]"; CreateNewProject(name, ptype); }, s => true)); } }
public ICommand CloseProjectCommand => _closeProjectCommand ?? (_closeProjectCommand = new DelegateCommandListen( s => { var closingvm = (IProjectViewModel)s; Projects.Remove(closingvm); }, s => s is not null));
public void CreateNewProject(string projectname, ProjectType ptype) { IProjectViewModel vm; switch (ptype) { case ProjectType.Triptych: vm = new ProjectViewModel(projectname); break; default: case ProjectType.Vario: vm = new ProjectVarioViewModel(projectname); break; }
Projects.Add(vm); SelectedProject = vm; }
#region inpc
public event PropertyChangedEventHandler? PropertyChanged;
< /code> varioview codebehind: < /p> public partial class VarioView : UserControl { private static Random _r = new ();
private SolidColorBrush GetRnColor() { var rgb = new byte[3]; _r.NextBytes(rgb); return new SolidColorBrush(Color.FromRgb(rgb[0], rgb[1], rgb[2])); }
public ProjectVarioViewModel ViewModel { get => (ProjectVarioViewModel)DataContext; set => DataContext = value; }
public UniqueId NameID { get; } = new();
public VarioView() { InitializeComponent(); Loaded += ApplyGrid; }
private void ApplyGrid(object sender, RoutedEventArgs e) { var totCols = ViewModel.W; var totRows = ViewModel.H;
var zoneWLen = new GridLength(1, GridUnitType.Star);
for (int x = 0; x < totCols; x++) GridZonesContainer.ColumnDefinitions.Add(new ColumnDefinition { Width = zoneWLen }); for (int y = 0; y < totRows; y++) GridZonesContainer.RowDefinitions.Add(new RowDefinition { Height = zoneWLen });
for (int x = 0; x < totCols; x++) for (int y = 0; y < totRows; y++) AddZone(x, y); }
private void AddZone(int gridx, int gridy) { var mz = new Rectangle { Fill = GetRnColor() }; GridZonesContainer.Children.Add(mz); Grid.SetRow(mz, gridy); Grid.SetColumn(mz, gridx); } } < /code> Утилита DelegateCommandListen: < /p> using System.ComponentModel; using System.Linq.Expressions; using System.Windows.Input;
namespace MultiTab;
/// /// Implementation of ICommand with listening to 1+ properties change (INPC) /// ICommand Zcommand = new DelegateCommandListen { /// ExecuteDelegate = ZExecuteCommand, /// CanExecuteDelegate = CanExecuteZCommand }.ListenOn(this, o => o.INPCpropFromVM);; /// public class DelegateCommandListen : ICommand { private readonly List _controlEvent; private Action _executeDelegate;
/// /// Implementation of ICommand with listening to 1+ properties change (INPC) /// ICommand Zcommand = new DelegateCommandListen { /// ExecuteDelegate = ZExecuteCommand, /// CanExecuteDelegate = CanExecuteZCommand }.ListenOn(this, o => o.INPCpropFromVM);; /// public DelegateCommandListen() { _controlEvent = new List(); }
/// /// Implementation of ICommand with listening to 1+ properties change (INPC) /// ///
/// public DelegateCommandListen(Action executeDelegate, Predicate canExecuteDelegate) { _controlEvent = new List(); ExecuteDelegate = executeDelegate; CanExecuteDelegate = canExecuteDelegate; }
public List PropertiesToListenTo { get; set; }
public Predicate CanExecuteDelegate { get; set; }
public Action ExecuteDelegate { get { return _executeDelegate; } set { _executeDelegate = value; ListenForNotificationFrom((INotifyPropertyChanged)_executeDelegate.Target); } }
public void RaiseCanExecuteChanged() { if (_controlEvent is { Count: > 0 }) _controlEvent.ForEach(ce => { ((EventHandler)ce.Target)?.Invoke(null, EventArgs.Empty); }); }
public DelegateCommandListen ListenOn (TObservedType viewModel, Expression propertyExpression) where TObservedType : INotifyPropertyChanged { var propertyName = GetPropertyName(propertyExpression); viewModel.PropertyChanged += (s, e) => { if (e.PropertyName == propertyName) RaiseCanExecuteChanged(); }; return this; }
public void ListenForNotificationFrom(TObservedType viewModel) where TObservedType : INotifyPropertyChanged { viewModel.PropertyChanged += (s, e) => RaiseCanExecuteChanged(); }
private static string GetPropertyName(Expression expression) where T : INotifyPropertyChanged { var lambda = expression as LambdaExpression; var memberInfo = GetMemberExpression(lambda).Member; return memberInfo.Name; }
private static MemberExpression GetMemberExpression(LambdaExpression lambda) { MemberExpression memberExpression; if (lambda.Body is UnaryExpression body) { var unaryExpression = body; memberExpression = unaryExpression.Operand as MemberExpression; } else memberExpression = lambda.Body as MemberExpression; return memberExpression; }
#region ICommand Members
public bool CanExecute(object parameter) => CanExecuteDelegate == null || CanExecuteDelegate(parameter);