Куда мне поместить методы, которые сильно связаны с View, но имеют большой размер при использовании шаблона MVVM? - PullRequest
0 голосов
/ 20 декабря 2011

Продолжая мой предыдущий вопрос о загроможденном состоянии моей модели представления Как я могу избежать беспорядка команд во ViewModel? Предыдущий вопрос У меня новый вопрос.Для школьного проекта я делаю настольное приложение для редактирования изображений в WPF, используя шаблон MVVM.Из-за всех опций редактирования (изменение размера и т. Д.) Существует довольно много команд, - которые вызывают методы с интенсивным использованием кода, которые используют свойства и методы GDI +, а также события.ATM - модель просмотра, насчитывающая 770 строк, и мне хочется плакать.Куда должны пойти такие методы, как эти два (о, пожалуйста, имейте в виду, что я начал программировать четыре месяца назад)?

    private void ToGrayscale()
    {
        Bitmap template = CurrentImage.LoadedImage.ToBitmap();
        var drawing = new Bitmap(template.Width, template.Height);
        var drawingsurface = Graphics.FromImage(drawing);
        var attributes = new ImageAttributes();
        attributes.SetColorMatrix(ImageFilters.GrayScaleMatrix);
        drawingsurface.DrawImage(template, new System.Drawing.Rectangle(0, 0, template.Width, template.Height),
                                   0, 0, template.Width, template.Height, GraphicsUnit.Pixel, attributes);
        drawingsurface.Dispose();
        AddSnapshot(drawing, "Desaturate");
        CurrentImage.LoadedImage = drawing.ToBitmapImage();
        UiImageContainer.Source = CurrentImage.LoadedImage;
    }



         private void OnMouseMove(object sender, MouseEventArgs args)
    {
        if (UiImageContainer.IsMouseCaptured && args.GetPosition(UiImageContainer).X > 0 &&
            args.GetPosition(UiImageContainer).Y < UiImageContainer.Source.Height && args.GetPosition(UiImageContainer).Y > 0 &&
            args.GetPosition(UiImageContainer).X < UiImageContainer.Source.Width)
        {
            if (_rubberBand == null)
            {
                _rubberBand = new System.Windows.Shapes.Rectangle();
                _rubberBand.VerticalAlignment = VerticalAlignment.Top;
                _rubberBand.HorizontalAlignment = HorizontalAlignment.Left;
                var partiallyTransparentSolidColorBrush = new SolidColorBrush(Colors.White);
                partiallyTransparentSolidColorBrush.Opacity = 0.25;
                _rubberBand.Fill = partiallyTransparentSolidColorBrush;
                _rubberBand.Stroke = new SolidColorBrush(Colors.LightGray);
                ContentGrid.Children.Add(_rubberBand);
            }
            var width = Math.Abs(_mouseLeftDownPoint.X - CurrentImagePoint.X);
            var height = Math.Abs(_mouseLeftDownPoint.Y - CurrentImagePoint.Y);
            var left = Math.Min(_mouseLeftDownPoint.X, CurrentImagePoint.X);
            var top = Math.Min(_mouseLeftDownPoint.Y, CurrentImagePoint.Y);

            _rubberBand.Width = width;
            _rubberBand.Height = height;
            var size = new Thickness(left, top, 0, 0);
            _rubberBand.Margin = size;
        }
    }

Ответы [ 4 ]

3 голосов
/ 20 декабря 2011

Например, вы можете делать такие вещи

// your original ToGreyscale modified
    private void ToGrayscale()      
    {      
        Bitmap greyscaleImage = ConvertToGreyscale(CurrentImage.LoadedImage.ToBitmap());      
        AddSnapshot(greyscaleImage, "Desaturate");      
        CurrentImage.LoadedImage = greyscaleImage .ToBitmapImage();      
        UiImageContainer.Source = CurrentImage.LoadedImage;      
    }      

// put this in another class
    private Bitmap ConvertToGrayscale(Bitmap originalImage) 
    { 
        var drawing = new Bitmap(originalImage.Width, originalImage.Height); 
        var drawingsurface = Graphics.FromImage(drawing); 
        var attributes = new ImageAttributes(); 
        attributes.SetColorMatrix(ImageFilters.GrayScaleMatrix); 
        drawingsurface.DrawImage(originalImage, new System.Drawing.Rectangle(0, 0, originalImage.Width, originalImage.Height), 
                                   0, 0, template.Width, template.Height, GraphicsUnit.Pixel, attributes); 
        drawingsurface.Dispose(); 

       return drawing
                    } 

Еще более «сексуальный» способ сделать это - сделать ConvertToGreyscale методом расширения в Bitmap.

0 голосов
/ 20 декабря 2011

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

Чтобы избежать тесной связи, убедитесь, что вы используете сервисные агенты и что эти сервисные агенты реализуют применимые интерфейсы вместо прямой ссылки на эти новые объекты, чтобы вашему приложению не приходилось ссылаться на эту библиотеку классов.

Использование объектно-ориентированных шаблонов проектирования и трех столпов ОО-проектирования (инкапсуляция, наследование и полиморфизм) для правильной организации кода в библиотеке классов и достижения СУХОГО (не повторяющегося) состояния этих объектов.

Продолжайте задавать более подробные вопросы с этим именем пользователя / фотографией, что позволит вам быстро получить много хороших ответов ...

0 голосов
/ 20 декабря 2011

Если у вас сложное поведение, подумайте, как можно разбить его на более мелкие части (отдельные классы).

Представьте себе здание небоскреба.Это одна большая вещь?Или это коллекция более мелких деталей, каждая из которых выполняет определенную работу (колонны, балки, окна и т. Д.)?И, возможно, балка состоит из балок, соединенных болтами.Любая система может быть разбита на более мелкие компоненты, пока каждый компонент не выполнит одну четко определенную задачу.

С точки зрения вашего класса представления, попытайтесь отделить пользовательский интерфейс от выполняемой работы - например, ToGreyscaleотличный пример «функции обработки изображений», которая может содержаться в классе.Другие функции обработки изображений могут быть записаны в аналогичные классы, все они получены из одного и того же базового класса или интерфейса, так что они становятся взаимозаменяемыми компонентами.

Организовав свой код таким образом, вы можете сделать очень сложное приложение измного маленьких, простых компонентов, и очень легко добавлять новые компоненты, чтобы расширить программу за пределы ее первоначального дизайна.

0 голосов
/ 20 декабря 2011

ваша _rubberBand должна в конечном итоге стать классом, может быть, RubberBand,

, затем выполнить _rubberBand.HandleMouseMove (...);

По сути, переместите вещи в отдельные методы, которые не связаны свашей модели представления, а затем посмотрите на перемещение этих методов в другие классы.Этот процесс заставит вас много думать о том, как вам нужно структурировать вещи.Вы обнаружите, что когда вам нужно переместить вещи в другие классы, эти классы должны взаимодействовать с вашей моделью / пользовательским интерфейсом View.Вы подумаете: «Хм, я не хочу, чтобы они прямо ссылались на мой UI / VM и т. Д.», И вы начинаете думать, ну, возможно, мне нужно придумать некоторые интерфейсы, через которые мои классы могли бы работать .....затем заставьте мой VM / UI реализовать эти интерфейсы. Например,

, вы можете найти OnMouseMove, что происходит, зависит от «контекста», а затем у вас есть контекст «RubberBandSelection» или что-то в этом роде.Затем вы придумаете общий способ иметь разные контексты.

...