Когда использовать представления со строгим контролем типов?

Отметьте: Этот вопрос собрал хорошую сумму обратной связи, и некоторые люди ниже сделали большие точки, или фиксирует. Поэтому, в то время как я сохраню код здесь (и возможно обновлю его), я имею также , создал проект WpfAppBar на github. Не стесняйтесь отправлять запросы получения по запросу.

Тот же самый проект также создает к пакет WpfAppBar nuget

, я взял код из первой ссылки, предоставленной в вопросе ( http://www.codeproject.com/KB/dotnet/AppBar.aspx ), и изменил его, чтобы сделать две вещи:

  1. Работа с WPF
  2. Быть "автономными" - при помещении этого единственного файла в проект можно назвать AppBarFunctions. SetAppBar (...) без дальнейшей модификации к окну.

Этот подход не создает базовый класс.

Для использования просто звоните, этот код отовсюду в нормальном wpf окне (скажите нажатие кнопки или инициализирование). Обратите внимание, что Вы не можете назвать это, пока окно не инициализируется, если HWND еще не был создан (как в конструкторе), ошибка произойдет.

Делают окно appbar:

AppBarFunctions.SetAppBar( this, ABEdge.Right );

Восстановление окно к нормальному окну:

AppBarFunctions.SetAppBar( this, ABEdge.None );

Вот полный код в файл - примечание , Вы захотите изменить пространство имен на строке 7 к чему-то соответствующему.

using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Interop;
using System.Windows.Threading;

namespace AppBarApplication
{    
    public enum ABEdge : int
    {
        Left = 0,
        Top,
        Right,
        Bottom,
        None
    }

    internal static class AppBarFunctions
    {
        [StructLayout(LayoutKind.Sequential)]
        private struct RECT
        {
            public int left;
            public int top;
            public int right;
            public int bottom;
        }

        [StructLayout(LayoutKind.Sequential)]
        private struct APPBARDATA
        {
            public int cbSize;
            public IntPtr hWnd;
            public int uCallbackMessage;
            public int uEdge;
            public RECT rc;
            public IntPtr lParam;
        }

        private enum ABMsg : int
        {
            ABM_NEW = 0,
            ABM_REMOVE,
            ABM_QUERYPOS,
            ABM_SETPOS,
            ABM_GETSTATE,
            ABM_GETTASKBARPOS,
            ABM_ACTIVATE,
            ABM_GETAUTOHIDEBAR,
            ABM_SETAUTOHIDEBAR,
            ABM_WINDOWPOSCHANGED,
            ABM_SETSTATE
        }
        private enum ABNotify : int
        {
            ABN_STATECHANGE = 0,
            ABN_POSCHANGED,
            ABN_FULLSCREENAPP,
            ABN_WINDOWARRANGE
        }

        [DllImport("SHELL32", CallingConvention = CallingConvention.StdCall)]
        private static extern uint SHAppBarMessage(int dwMessage, ref APPBARDATA pData);

        [DllImport("User32.dll", CharSet = CharSet.Auto)]
        private static extern int RegisterWindowMessage(string msg);

        private class RegisterInfo
        {
            public int CallbackId { get; set; }
            public bool IsRegistered { get; set; }
            public Window Window { get; set; }
            public ABEdge Edge { get; set; }
            public WindowStyle OriginalStyle { get; set; }            
            public Point OriginalPosition { get; set; }
            public Size OriginalSize { get; set; }
            public ResizeMode OriginalResizeMode { get; set; }


            public IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, 
                                    IntPtr lParam, ref bool handled)
            {
                if (msg == CallbackId)
                {
                    if (wParam.ToInt32() == (int)ABNotify.ABN_POSCHANGED)
                    {
                        ABSetPos(Edge, Window);
                        handled = true;
                    }
                }
                return IntPtr.Zero;
            }

        }
        private static Dictionary s_RegisteredWindowInfo 
            = new Dictionary();
        private static RegisterInfo GetRegisterInfo(Window appbarWindow)
        {
            RegisterInfo reg;
            if( s_RegisteredWindowInfo.ContainsKey(appbarWindow))
            {
                reg = s_RegisteredWindowInfo[appbarWindow];
            }
            else
            {
                reg = new RegisterInfo()
                    {
                        CallbackId = 0,
                        Window = appbarWindow,
                        IsRegistered = false,
                        Edge = ABEdge.Top,
                        OriginalStyle = appbarWindow.WindowStyle,                        
                        OriginalPosition =new Point( appbarWindow.Left, appbarWindow.Top),
                        OriginalSize = 
                            new Size( appbarWindow.ActualWidth, appbarWindow.ActualHeight),
                        OriginalResizeMode = appbarWindow.ResizeMode,
                    };
                s_RegisteredWindowInfo.Add(appbarWindow, reg);
            }
            return reg;
        }

        private static void RestoreWindow(Window appbarWindow)
        {
            RegisterInfo info = GetRegisterInfo(appbarWindow);

            appbarWindow.WindowStyle = info.OriginalStyle;            
            appbarWindow.ResizeMode = info.OriginalResizeMode;
            appbarWindow.Topmost = false;

            Rect rect = new Rect(info.OriginalPosition.X, info.OriginalPosition.Y, 
                info.OriginalSize.Width, info.OriginalSize.Height);
            appbarWindow.Dispatcher.BeginInvoke(DispatcherPriority.ApplicationIdle,
                    new ResizeDelegate(DoResize), appbarWindow, rect);

        }

        public static void SetAppBar(Window appbarWindow, ABEdge edge)
        {
            RegisterInfo info = GetRegisterInfo(appbarWindow);
            info.Edge = edge;

            APPBARDATA abd = new APPBARDATA();
            abd.cbSize = Marshal.SizeOf(abd);
            abd.hWnd = new WindowInteropHelper(appbarWindow).Handle;

            if( edge == ABEdge.None)
            {
                if( info.IsRegistered)
                {
                    SHAppBarMessage((int)ABMsg.ABM_REMOVE, ref abd);
                    info.IsRegistered = false;
                }
                RestoreWindow(appbarWindow);
                return;
            }

            if (!info.IsRegistered)
            {
                info.IsRegistered = true; 
                info.CallbackId = RegisterWindowMessage("AppBarMessage");
                abd.uCallbackMessage = info.CallbackId;

                uint ret = SHAppBarMessage((int)ABMsg.ABM_NEW, ref abd);

                HwndSource source = HwndSource.FromHwnd(abd.hWnd);
                source.AddHook(new HwndSourceHook(info.WndProc));
            }

            appbarWindow.WindowStyle = WindowStyle.None;            
            appbarWindow.ResizeMode = ResizeMode.NoResize;
            appbarWindow.Topmost = true;

            ABSetPos(info.Edge, appbarWindow);                
        }

        private delegate void ResizeDelegate(Window appbarWindow, Rect rect);
        private static void DoResize(Window appbarWindow, Rect rect)
        {
            appbarWindow.Width = rect.Width;
            appbarWindow.Height = rect.Height;
            appbarWindow.Top = rect.Top;
            appbarWindow.Left = rect.Left;
        }



        private static void ABSetPos(ABEdge edge, Window appbarWindow)
        {
            APPBARDATA barData = new APPBARDATA();
            barData.cbSize = Marshal.SizeOf(barData);
            barData.hWnd = new WindowInteropHelper(appbarWindow).Handle;
            barData.uEdge = (int)edge;

            if (barData.uEdge == (int)ABEdge.Left || barData.uEdge == (int)ABEdge.Right)
            {
                barData.rc.top = 0;
                barData.rc.bottom = (int)SystemParameters.PrimaryScreenHeight;
                if (barData.uEdge == (int)ABEdge.Left)
                {
                    barData.rc.left = 0;
                    barData.rc.right = (int)Math.Round(appbarWindow.ActualWidth);
                }
                else
                {
                    barData.rc.right = (int)SystemParameters.PrimaryScreenWidth;
                    barData.rc.left = barData.rc.right - (int)Math.Round(appbarWindow.ActualWidth);
                }
            }
            else
            {
                barData.rc.left = 0;
                barData.rc.right = (int)SystemParameters.PrimaryScreenWidth;
                if (barData.uEdge == (int)ABEdge.Top)
                {
                    barData.rc.top = 0;
                    barData.rc.bottom = (int)Math.Round(appbarWindow.ActualHeight);
                }
                else
                {
                    barData.rc.bottom = (int)SystemParameters.PrimaryScreenHeight;
                    barData.rc.top = barData.rc.bottom - (int)Math.Round(appbarWindow.ActualHeight);
                }
            }

            SHAppBarMessage((int)ABMsg.ABM_QUERYPOS, ref barData);
            SHAppBarMessage((int)ABMsg.ABM_SETPOS, ref barData);

            Rect rect = new Rect((double)barData.rc.left, (double)barData.rc.top, 
                (double)(barData.rc.right - barData.rc.left), (double)(barData.rc.bottom - barData.rc.top));
            //This is done async, because WPF will send a resize after a new appbar is added.  
            //if we size right away, WPFs resize comes last and overrides us.
            appbarWindow.Dispatcher.BeginInvoke(DispatcherPriority.ApplicationIdle, 
                new ResizeDelegate(DoResize), appbarWindow, rect);
        }
    }
}

5
задан MetaGuru 15 September 2009 в 14:48
поделиться

6 ответов

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

Я создаю свои собственные строго типизированные представления в любое время, когда мне нужно информация из более чем одного источника для представления.

Например, в моем оформлении заказа мне нужен заказ, а также настройки пользователя для отображения цены; поэтому я создал CheckoutViewModel, у которого есть свойства Order и PriceDisplay.

Надеюсь, что это поможет,

Дэн

2
ответ дан 13 December 2019 в 19:30
поделиться

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

Если ваше представление является чисто информационным, вы можете быть возможность использовать ModelState для передачи небольших фрагментов информации (например, страниц об успехах / ошибках, неавторизованных сообщений и т. д.)

В моих приложениях КАЖДЫЙ вид строго типизирован, так что я могу легко передавать информацию для входа в систему на главную страницу. То есть все мои представления строго типизированы, построены по шаблонам и ограничены базовым классом, который содержит конфигурацию сайта и информацию для входа в систему.

Благодаря этому я могу сделать это:

public class MyBaseMasterPage : ViewMasterPage<MyBaseModel>
{
    public string CurrentTheme
    {
        get
        {
            if (this.Model.CurrentUser != null)
                return this.Model.CurrentUser.Theme;

            else return this.Model.Config.DefaultTheme;
        }
    }

    public User CurrentUser { get { return this.Model.CurrentUser; } }

    public ConfigurationRepository Config { get { return this.Model.Config; } }
}

Обратите внимание, что, поскольку Мастер Страница тематически основана ТОЛЬКО на том, что заполняется в модели, само представление никогда не вызовет попадание в базу данных / кеш.

MyBaseModel настроен следующим образом:

5
ответ дан 13 December 2019 в 19:30
поделиться

Если есть данные, должно быть строго типизированное представление. Период.

3
ответ дан 13 December 2019 в 19:30
поделиться

Всегда. Я бы пошел дальше и использовал строго типизированные элементы управления и действия HtmlHelper. Большинство из них доступно в библиотеке MvcContrib .

1
ответ дан 13 December 2019 в 19:30
поделиться

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

Например, когда вы редактируете или создаете продукт в представлении, было бы определенно посоветовать иметь строго типизированное представление для класса продукта.

Если вы показываете только текст или изображения, фактически не имея связи с чем-либо на нижележащих уровнях базы данных, вероятно, будет проще отказаться от строго типизированного представления.

Это будет все получается довольно естественно, поскольку, по моему опыту, вы больше работаете с MVC.

0
ответ дан 13 December 2019 в 19:30
поделиться

Although I'm repeating what others have eloquently stated I think there is one more point to raise. The View is part of the Model, View, Controller concept and as such is there to present the Model in a visual way to the user. Given that it is, in essence, a representation of the Model it makes sense for it to be strongly typed.

I only ever use ModelState or TempState for passing small pieces of data, like outcome messages from activities like add, delete, etc. Any time I find tempted to use State to pass collections that are unrelated to the View-type then I refactor that functionality into a partial view and present that through a separate controller action.

In my code related types are generally referenced hierarchically from the base type to which the view is strongly-typed, and so are accessible within the View where necessary.

0
ответ дан 13 December 2019 в 19:30
поделиться
Другие вопросы по тегам:

Похожие вопросы: