Копирование TabItem со структурой MVVM

Это попытка расширить этот вопрос. В моей программе WPF я клонировал tabItems, используя XamlWriter в функции с именем TrycloneElement. Первоначально я нашел эту функцию здесь, но функцию также можно посмотреть в ссылке на мой предыдущий вопрос.

Теперь, когда я начинаю беспокоиться о функциональности своей программы, я обнаружил, что функция TrycloneElement не копирует какие-либо функции кода программной части, назначенные клонируемому ею tabItem.

Из-за ссылки High Core и комментариев к моему предыдущему вопросу я решил начать реализацию функциональности на моем tabItems через привязку данных с моей ViewModel.

Вот пример команды, которую я реализовал:

public viewModel()
{
    allowReversing = new Command(allowReversing_Operations);
}

public Command AllowReversing
{
       get { return allowReversing; }
} 

private Command allowReversing; 

private void allowReversing_Operations()
{
       //Query for Window1
       var mainWindow = Application.Current.Windows
           .Cast<Window1>()
           .FirstOrDefault(window => window is Window1) as Window1;

       if (mainWindow.checkBox1.IsChecked == true) //Checked
       {
           mainWindow.checkBox9.IsEnabled = true;
           mainWindow.groupBox7.IsEnabled = true;
       }
       else //UnChecked
       {
           mainWindow.checkBox9.IsEnabled = false;
           mainWindow.checkBox9.IsChecked = false;
           mainWindow.groupBox7.IsEnabled = false;
       }
} 

*ПРИМЕЧАНИЕ. Я знаю, что я обманывал и напрямую взаимодействовал с моим представлением в приведенном выше коде, но я не знал, как еще запускать эти команды. Если это проблема или есть другой способ, пожалуйста, покажите мне, как я могу запускать те же самые команды, не взаимодействуя с представлением, как я.

Теперь вопрос:

После изменения моего кода и добавления команд в мою ViewModel функция TrycloneElement больше не работает. Во время выполнения во время клонирования вкладки я получаю XamlParseException в строке, object x = XamlReader.Load(xmlReader);, которая гласит: введите описание изображения здесь

Я согласен отказаться от этой функции, если есть лучший способ, и он мне больше не нужен. Но, в конце концов, как мне взять дизайн и функциональность tabItem и клонировать их? (Пожалуйста, имейте в виду, что я действительно пытаюсь исправить свою структуру)

Спасибо за помощь.

Пересмотр ответа Лео

Это текущая версия ответа Лео, которую я компилирую. (Были некоторые синтаксические ошибки)

public static IList<DependencyProperty> GetAllProperties(DependencyObject obj)
{
       return (from PropertyDescriptor pd in TypeDescriptor.GetProperties(obj, new Attribute[] { new PropertyFilterAttribute(PropertyFilterOptions.SetValues) })
                    select DependencyPropertyDescriptor.FromProperty(pd)
                   into dpd
                   where dpd != null
                   select dpd.DependencyProperty).ToList();
}

public static void CopyPropertiesFrom(this FrameworkElement controlToSet,
                                                   FrameworkElement controlToCopy)
{
       foreach (var dependencyValue in GetAllProperties(controlToCopy)
                    .Where((item) => !item.ReadOnly)
                    .ToDictionary(dependencyProperty => dependencyProperty, controlToCopy.GetValue))
       {
           controlToSet.SetValue(dependencyValue.Key, dependencyValue.Value);
       }
}

person Eric after dark    schedule 04.09.2013    source источник
comment
Можете ли вы опубликовать код, где находится CircularButtonPrototypeHelpers.Command?   -  person 123 456 789 0    schedule 05.09.2013
comment
Если вы хотите клонировать его, вопрос в том, отличается ли поведение этих элементов вкладки от других? Как вы создаете эти элементы вкладок и когда они клонируются?   -  person 123 456 789 0    schedule 05.09.2013
comment
@Leo Код в CircularButtonPrototype.Helpers.Command представляет собой реализацию ICommand, около 190 строк. Это то, что я вынес из этого руководства: codeproject.com/Articles/ 274982/Commands-in-MVVM#example1 У меня есть 5 различных типов вкладок. Однако пользователю разрешено создавать новые. Так, например... если вкладка зеленая, и пользователь хочет создать новую зеленую вкладку, клонируется основная зеленая вкладка. Чтобы ответить на ваш другой вопрос, они клонируются динамически.   -  person Eric after dark    schedule 05.09.2013
comment
Привет, Эрик, похоже, вы новичок в WPF/MVVM, и если это так, вы можете проверить ссылки в моем ответе здесь о переходе с Winforms на WPF. В вашем случае все свойства элемента вкладки, такие как IsEnabled и IsChecked, должны быть в вашей ViewModel (или модели), а ваш XAML (в данном случае TabItem) — это просто довольно удобный интерфейс, используемый для отображения ViewModel пользователю . Чтобы создать новую вкладку, вы действительно хотите создать новую ViewModel и добавить ее в коллекцию, которая будет автоматически отрисовываться с использованием нового TabItem.   -  person Rachel    schedule 05.09.2013
comment
Значит, это нормально, что я взаимодействовал с моим главным окном через свои команды?   -  person Eric after dark    schedule 05.09.2013


Ответы (2)


Вот мой пример правильно реализованного динамического TabControl в WPF.

Основная идея заключается в том, что каждый Tab Item — это отдельный виджет, содержащий свою логику и данные, которые обрабатываются ViewModel, а UI делает то, что должен делать UI: show данные, а не contain данные.

Суть в том, что все данные и функциональность управляются на уровнях ViewModel/Model, и, поскольку TabControl привязан к ObservableCollection, вы просто добавляете еще один элемент в эту коллекцию всякий раз, когда вам нужно добавить новую вкладку.

Это устраняет необходимость «клонирования» пользовательского интерфейса или каких-либо других странных манипуляций с ним.

person Federico Berasategui    schedule 04.09.2013
comment
Это просто предположение, что DataContext элемента управления TabItem - это TabViewModel, где он показывает данные в пользовательском интерфейсе, это не решило, где он хочет манипулировать и копировать свойства зависимостей TabItem, что вы собираетесь здесь предложить? Прикрепить свойства? Стили? Шаблоны данных? - person 123 456 789 0; 05.09.2013
comment
О, так вы говорите, что SolidColorBrush должен быть в свойстве ViewModel, потому что вы сказали, что все будет привязано к соответствующим свойствам в ViewModel/Model, что неверно? - person 123 456 789 0; 05.09.2013

1.) Чтобы исправить это исключение XamlParseException, убедитесь, что у вас есть общедоступный конструктор, такой как пустой, вы, вероятно, определили конструктор, и когда вы пытались сериализовать этот объект и десериализовать, он не может. Вы должны явно добавить конструктор по умолчанию.

2.) Мне не нравится слово клон, но я бы сказал, когда хотят скопировать. Я вручную создам новый элемент управления вкладкой, а затем поразмышляю над ним.

У меня есть этот код, который я сделал

  public static IList<DependencyProperty> GetAllProperties(DependencyObject obj)
    {
        return (from PropertyDescriptor pd in TypeDescriptor.GetProperties(obj, new Attribute[] {new PropertyFilterAttribute(PropertyFilterOptions.SetValues)})
                select DependencyPropertyDescriptor.FromProperty(pd)
                into dpd where dpd != null select dpd.DependencyProperty).ToList();
    }


    public static void CopyPropertiesFrom(this FrameworkElement controlToSet,
                                               FrameworkElement controlToCopy)
    {
        foreach (var dependencyValue in GetAllProperties(controlToCopy)
                .Where((item) => !item.ReadOnly))
                .ToDictionary(dependencyProperty => dependencyProperty, controlToCopy.GetValue))
        {
            controlToSet.SetValue(dependencyValue.Key, dependencyValue.Value);
        }
    }

Так что это было бы как

var newTabItem = new TabItem();
newTabItem.CopyPropertiesFrom(masterTab);
person 123 456 789 0    schedule 04.09.2013
comment
Хорошо, № 1 отлично сработал. Теперь в Реализации № 2, что мне нужно изменить в этой функции, чтобы сделать ее специфичной для моей программы? И я думаю, что вы, возможно, имели в виду: newTabItem.CopyPropertiesFrom(masterTab); - person Eric after dark; 05.09.2013
comment
В частности, у меня проблемы с GetAllProperties, .ToDictionary и dependencyValue. - person Eric after dark; 05.09.2013
comment
Это метод расширения, поэтому убедитесь, что CopyPropertiesFrom определен в классе статистики. - person 123 456 789 0; 05.09.2013
comment
И пока он находится в static class, он должен работать правильно? - person Eric after dark; 05.09.2013
comment
Он должен скопировать значения, которые вы буквально хотите клонировать, в новый элемент. - person 123 456 789 0; 05.09.2013
comment
@LeoLorenzoLuis, конечно, это противоречит всем известным передовым практикам в WPF и является ужасно плохим советом для тех, кто пытается реализовать правильно сформированный шаблон. - person Federico Berasategui; 05.09.2013
comment
@HighCore Что заставляет тебя так говорить? Вы знаете, что клонирование более ужасно, и его сериализация, а затем десериализация просто для клонирования. - person 123 456 789 0; 05.09.2013
comment
Затем измените FrameworkContentElement на TabItem, это был пример кода. - person 123 456 789 0; 05.09.2013
comment
@HighCore Я знаю это, но я не думаю, что сериализация и десериализация пользовательского интерфейса только для клонирования - это правильно. Я даже ничего не делаю с пользовательским интерфейсом. Это все равно, что сказать, что динамическое создание элементов управления пользовательским интерфейсом означает, что «пользовательский интерфейс — это не данные»? Таким образом, вы нарушаете его тогда. Не стесняйтесь предложить ему другой вариант тогда. - person 123 456 789 0; 05.09.2013
comment
@HighCore Кстати, я не упоминал, что он должен поместить это в ViewModel. - person 123 456 789 0; 05.09.2013
comment
Лмао, конечно, но нет. Это зависит от сценария, в котором вам обязательно нужно динамически создавать элементы управления пользовательского интерфейса. В WPF все еще существуют сценарии, в которых вам необходимо динамически создавать элемент управления/манипулировать свойствами зависимостей. Не ведите себя так, как будто вы очень хорошо знаете WPF. - person 123 456 789 0; 05.09.2013
comment
Я должен стоять с HighCore на этом. Процедурное создание элементов управления пользовательского интерфейса в WPF предполагает отсутствие знаний о том, на что действительно способен XAML. Вы можете подсчитать количество раз, которое вам действительно нужно сделать, пальцами одной руки. - person Yandros; 05.09.2013
comment
@HighCore Создайте приложение, в котором есть режим отслеживания изменений (где он показывает пользователю вставленный/удаленный символ), когда кто-то нажимает на них с помощью FlowDocuments. - person 123 456 789 0; 05.09.2013
comment
О, и имейте в виду. Содержимое RichTextBox зависит от данных, поступающих из базы данных, и когда пользователь теряет фокус, вам нужно сделать его недоступным для редактирования. - person 123 456 789 0; 05.09.2013
comment
@HighCore, и если вы не согласны с моим решением, вы можете предложить человеку, который задает вопрос, другое решение, которое, по вашему мнению, поможет ему решить его проблему. Как бы вы клонировали элемент вкладки? Предоставление аргумента, в котором вы не предоставляете никакой альтернативы, здесь не поможет. - person 123 456 789 0; 05.09.2013
comment
@HighCore Теперь вы говорите, что это другое дело, я только что дал вам сценарий, и он подпадает под WPF. Вы не можете поместить все, используя прикрепленные свойства, потому что не все доступно в данном классе в FrameworkContentElements, вам нужно копнуть глубже. Могу я спросить вас, насколько вы опытны с FrameworkContentElements? - person 123 456 789 0; 05.09.2013
comment
Вы спросили меня, какой сценарий я бы использовал для процедурного создания пользовательского интерфейса, и я дал вам один. Какое-то высокомерие здесь, я вижу, - person 123 456 789 0; 05.09.2013
comment
давайте продолжим обсуждение в чате - person 123 456 789 0; 05.09.2013
comment
Эй, @Leo, не мог бы ты еще раз проверить эту функцию? Либо я что-то упускаю, либо ты. Если у вас это реализовано и работает в программе, вы также можете отправить его мне, чтобы я мог увидеть его в действии, если это проще. Спасибо. - person Eric after dark; 05.09.2013
comment
Обновлено с помощью GetAllProperties() - person 123 456 789 0; 05.09.2013
comment
Хорошо, понял. Однако .ToDictionary и dependancyValue не существуют в текущем контексте. Почему я получаю это? - person Eric after dark; 05.09.2013
comment
У вас есть ссылка на System.Linq? - person 123 456 789 0; 05.09.2013
comment
Да, у меня есть System.Linq - person Eric after dark; 05.09.2013
comment
давайте продолжим это обсуждение в чате - person Eric after dark; 05.09.2013