प्रिज्म डेवलपर की गाइड - भाग 6, उन्नत एमवीवीएम लिपियों

सामग्री की तालिका
  1. परिचय
  2. प्रारम्भिक प्रिज्म अनुप्रयोग
  3. घटकों के बीच निर्भरता का प्रबंधन
  4. मॉड्यूलर अनुप्रयोग विकास
  5. एमवीवीएम पैटर्न को लागू करना
  6. उन्नत MVVM परिदृश्य
  7. उपयोगकर्ता इंटरफ़ेस निर्माण
    1. उपयोगकर्ता इंटरफ़ेस दिशानिर्देश
  8. नेविगेशन
    1. दृश्य-आधारित नेविगेशन
  9. शिथिल युग्मित घटकों के बीच पारस्परिक क्रिया

पिछले अध्याय में बताया गया है कि यूजर इंटरफेस, प्रेजेंटेशन लॉजिक और बिजनेस लॉजिक को अलग-अलग वर्गों (प्रेजेंटेशन, प्रेजेंटेशन मॉडल और मॉडल) में अलग करके MVVM पैटर्न के मुख्य तत्वों को कैसे बनाया जाए, उनके बीच इंटरेक्शन लागू करें (डेटा, कमांड्स और डेटा वैलिडिटी इंटरफेस को बाइंड करके)। , उनके निर्माण और अनुकूलन को व्यवस्थित करें।

इन मूल तत्वों का उपयोग करके MVVM पैटर्न को लागू करने से आपके एप्लिकेशन में अधिकांश परिदृश्य फिट होने की संभावना है। हालाँकि, आप अधिक जटिल परिदृश्यों का सामना कर सकते हैं जिनके लिए MVVM पैटर्न के विस्तार, या अधिक उन्नत विधियों के उपयोग की आवश्यकता होती है। ऐसा होने की सबसे अधिक संभावना है यदि आपका आवेदन बड़ा या जटिल है, लेकिन यह कई छोटे अनुप्रयोगों में पाया जा सकता है। प्रिज्म लाइब्रेरी ऐसे घटक प्रदान करती है जो इनमें से कई तरीकों को लागू करते हैं, जिससे आप आसानी से अपने अनुप्रयोगों में इनका उपयोग कर सकते हैं।

यह अध्याय कुछ जटिल परिदृश्यों का वर्णन करता है और एमवीवीएम पैटर्न उनका समर्थन कैसे करता है। अगला खंड दिखाता है कि टीमों को कैसे जंजीर से जोड़ा जा सकता है या बच्चे के विचारों से जोड़ा जा सकता है, और उन्हें कस्टम आवश्यकताओं का समर्थन करने के लिए कैसे बढ़ाया जा सकता है। निम्न अनुभागों का वर्णन है कि उपयोगकर्ता इंटरफ़ेस के साथ अतुल्यकालिक डेटा अनुरोधों और बाद की बातचीत को कैसे संभालना है, साथ ही एक दृश्य और एक दृश्य मॉडल के बीच बातचीत के अनुरोधों को कैसे संभालना है।

एडवांस्ड क्रिएशन एंड कस्टमाईज़ेशन सेक्शन, इनविटेशन इंजेक्शन कंटेनर, जैसे कि एकता एप्लीकेशन ब्लॉक (यूनिटी), या मैनेज एक्स्टेंसिबिलिटी फ्रेमवर्क (MEF) का उपयोग करते समय घटकों को बनाने और कस्टमाइज़ करने का एक सिंहावलोकन प्रदान करता है। अंतिम खंड एमवीवीएम अनुप्रयोगों का परीक्षण करने का तरीका बताता है, और इकाई परीक्षण मॉडल कक्षाओं और प्रस्तुति मॉडल के साथ-साथ व्यवहार परीक्षण का परिचय देता है।

आदेशों


UI. , . , «» 5, , , , : , Command, .
. WPF.
H , , , MVVM WPF , ( Silverlight ). WPF UI. , UI , . , UI, , . WPF , code-behind , .


, , , , . , , .

, , , , . , Save All Save, , .

SaveAll.

Prism CompositeCommand.

CompositeCommand , . , . , UI, -, , .

, CompositeCommand Stock Trader RI, SubmitAllOrders, Submit All buy/sell . Submit All, SubmitCommand, buy/sell .

CompositeCommand ( DelegateCommand ). Execute CompositeCommand Execute . CanExecute CanExecute , - , CanExecute false. , , CompositeCommand , .


RegisterCommand UnregisterCommand. Stock Trader RI, , Submit Cancel buy/sell SubmitAllOrders CancelAllOrders, (. OrdersController ).

commandProxy.SubmitAllOrdersCommand.RegisterCommand(
    orderCompositeViewModel.SubmitCommand);
commandProxy.CancelAllOrdersCommand.RegisterCommand(
    orderCompositeViewModel.CancelCommand);


commandProxy Submit Cancel, . , StockTraderRICommands.cs .


, UI, , , , . , , , . , DelegateCommand CompositeCommand Prism.

Prism ( , «» 7) UI. , UI. , . , EditRegion, UI TabControl, .

EditRegion,    Tab control.

, , . , , , Save All, . , . , , . , Zoom , , .

EditRegion,    Tab control.

, Prism IActiveAware. IActiveAware IsActive, true, , IsActiveChanged, , .

IActiveAware . , , , . , , . , TabControl, , , .

DelegateCommand IActiveAware. true monitorCommandActivity , CompositeCommand , DelegateCommand ( CanExecute ). true, CompositeCommand DelegateCommand, CanExecute Execute.

monitorCommandActivity true, CompositeCommand :

, , . IActiveAware , , . , . , Zoom, .


, , — UI , ( ).

, , , ListBox. , , , Delete, .

.

Delete, , Delete UI , Delete, . - , ListBox , Delete.

– , ElementName , , . XAML .

<Grid x:Name="root">
    <ListBox ItemsSource="{Binding Path=Items}">
        <ListBox.ItemTemplate>
            <DataTemplate>
                <Button Content="{Binding Path=Name}"
                        Command="{Binding ElementName=root,
                        Path=DataContext.DeleteCommand}" />
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>
</Grid>

Name . Delete. . CommandParameter, , , , ( CollectionView ).


Silverlight 3 , Silverlight , . ICommand , Command, ICommand. MVVM Silverlight 3, Prism ( 2.0) , Silverlight , . WPF, Silverlight, WPF.

, Prism , , .

<Button Content="Submit All"
   prism:Click.Command="{Binding Path=SubmitAllCommand}"
   prism:Click.CommandParameter="{Binding Path=TickerSymbol}" />

Silverlight 4 Command Hyperlink ButtonBase , WPF. Command "Commands" 5, "Implementing the MVVM Pattern". , Prism , .

. , , , . Microsoft Expression Blend , InvokeCommandAction CallMethodAction, , «Invoking Command Methods from the View» 5, "Implementing the MVVM Pattern", Expression Blend Behaviors SDK . Expression Blend , . Expression Blend, . "Creating Custom Behaviors" MSDN.

Silverlight 4 Expression Blend Behaviors SDK Prism, , .


. , , , . : . . , .

, Click ButtonBase - , ButtonBaseClickCommandBehavior. ButtonBase, ButtonBaseClickCommandBehavior, ICommand, .

ButtonClick  IComman.

, , Click ButtonBase, , , , , . / .

Prism CommandBehaviorBase , , ICommand . CanExecuteChanged , Silverlight, WPF.

, , CommandBehaviorBase , . , . , . ButtonBaseClickCommandBehavior .

public class ButtonBaseClickCommandBehavior : CommandBehaviorBase<ButtonBase> {
    public ButtonBaseClickCommandBehavior(ButtonBase clickableObject) : base(clickableObject) {
        clickableObject.Click += OnClick;
    }
    private void OnClick(object sender, System.Windows.RoutedEventArgs e) {
        ExecuteCommand();
    }
}

CommandBehaviorBase , . , , . , , , , , CanExecute , .

, . XAML. . . Prism , , , . , . , , , Click , Command . Click.Command , .

. .

public static readonly DependencyProperty CommandProperty =
                              DependencyProperty.RegisterAttached(
                                      "Command",
                                      typeof(ICommand),
                                      typeof(Click),
                                      new PropertyMetadata(OnSetCommandCallback));

private static readonly DependencyProperty ClickCommandBehaviorProperty =
                              DependencyProperty.RegisterAttached(
                                      "ClickCommandBehavior",
                                      typeof(ButtonBaseClickCommandBehavior),
                                      typeof(Click),
                                      null);

Command ButtonBaseClickCommandBehavior , OnSetCommandCallback , .

private static void OnSetCommandCallback(DependencyObject dependencyObject,
DependencyPropertyChangedEventArgs e) {
     ButtonBase buttonBase = dependencyObject as ButtonBase;
     if (buttonBase != null)  {
        ButtonBaseClickCommandBehavior behavior = GetOrCreateBehavior(buttonBase);
        behavior.Command = e.NewValue as ICommand;
     }
}
private static void OnSetCommandParameterCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e) {
    ButtonBase buttonBase = dependencyObject as ButtonBase;
    if (buttonBase != null) {
        ButtonBaseClickCommandBehavior behavior = GetOrCreateBehavior(buttonBase);
        behavior.CommandParameter = e.NewValue;
    }
}
private static ButtonBaseClickCommandBehavior GetOrCreateBehavior(ButtonBase buttonBase ) {
    ButtonBaseClickCommandBehavior behavior =
        buttonBase.GetValue(ClickCommandBehaviorProperty) as ButtonBaseClickCommandBehavior;
    if ( behavior == null ) {
        behavior = new ButtonBaseClickCommandBehavior(buttonBase);
        buttonBase.SetValue(ClickCommandBehaviorProperty, behavior);
    }
    return behavior;
}

, Attached Properties Overview MSDN.


. , Silverlight, -, , , . , .

, ( ) , , . UI , UI.

-


- , IAsyncResult . , , , GetQuestionnaire , : BeginGetQuestionnaire EndGetQuestionnaire . , BeginGetQuestionnaire . , , EndGetQuestionnaire .

.NET Framework 4.5 await async *Async . "Asynchronous Programming with Async and Await (C# and Visual Basic)".

, EndGetQuestionnaire , , () BeginGetQuestionnaire . , , EndGetQuestionnaire , .

IAsyncResult asyncResult = this.service.BeginGetQuestionnaire(
	GetQuestionnaireCompleted, 
	null //  ,     
);
private void GetQuestionnaireCompleted(IAsyncResult result) {
   try {
     questionnaire = this.service.EndGetQuestionnaire(ar);
   }
   catch (Exception ex) {
     //  -   .
   }
}

, End* ( , EndGetQuestionnaire ), , . , , UI. , , .

UI, -, UI, UI, Dispatcher SynchronizationContext . WPF Silverlight, Dispatcher .

Questionnaire , QuestionnaireView . Silverlight CheckAccess , , UI. , BeginInvoke , UI.

var dispatcher = System.Windows.Deployment.Current.Dispatcher;
if (dispatcher.CheckAccess()) {
    QuestionnaireView.DataContext = questionnaire;
}
else {
    dispatcher.BeginInvoke(() => { Questionnaire.DataContext = questionnaire; });
}

MVVM RI , , IAsyncResult , . , . , .

this.questionnaireRepository.GetQuestionnaireAsync(
    result => {
        this.Questionnaire = result.Result;
    });

result , , , , . , .

this.questionnaireRepository.GetQuestionnaireAsync(
    result => {
        if (result.Error == null) {
          this.Questionnaire = result.Result;
          ...
        }
        else {
          // Handle error.
        }
    })


, . , , . , , , .

, MVVM, , . , -MVVM , MessageBox code-behind UI, . MVVM , .

MVVM, , . , , , , .

MVVM. , , , , . , , , . .


. , . , . .

, , , . , . , . , WPF Silverlight, .

,    .

, MessageBox , , , .

var result =
    interactionService.ShowMessageBox(
        "Are you sure you want to cancel this operation?",
        "Confirm",
        MessageBoxButton.OK);
if (result == MessageBoxResult.Yes) {
    CancelRequest();
}

, - , , Silverlight. . . .

interactionService.ShowMessageBox(
    "Are you sure you want to cancel this operation?",
    "Confirm",
    MessageBoxButton.OK,
    result => {
        if (result == MessageBoxResult.Yes) {
            CancelRequest();
        }
    });

, . , WPF MessageBox , ; Silverlight , .


– . , . , . , , , .

.

, , – , , – . , , , UI .

MVVM, , , . , , , .

Prism IInteractionRequest InteractionRequest . IInteractionRequest , . , . InteractionRequest IInteractionRequest Raise , , , , .


InteractionRequest . Raise ( T ) , , . , . , . , , .
public interface IInteractionRequest {
    event EventHandler<InteractionRequestedEventArgs> Raised;
}

public class InteractionRequest<T> : IInteractionRequest {
    public event EventHandler<InteractionRequestedEventArgs> Raised;

    public void Raise(T context, Action<T> callback) {
        var handler = this.Raised;
        if (handler != null) {
            handler(
                this,
                new InteractionRequestedEventArgs(context, () => callback(context)));
        }
    }
}

Prism , . Notification . , . – Title Content , . , , , , .

Confirmation NotificationConfirmed , , , . Confirmation , MessageBox , / . , Notification , , .

InteractionRequest , InteractionRequest , . , Raise , , , .

public IInteractionRequest ConfirmCancelInteractionRequest {
    get {
        return this.confirmCancelInteractionRequest;
    }
}

this.confirmCancelInteractionRequest.Raise(
    new Confirmation("Are you sure you wish to cancel?"),
    confirmation => {
        if (confirmation.Confirmed) {
            this.NavigateToQuestionnaireList();
        }
    });
}

MVVM Reference Implementation (MVVM RI) , IInteractionRequest InteractionRequest , (. QuestionnaireViewModel.cs ).


, . , . UI .

. Microsoft Expression Blend Behaviors Framework . , , .

EventTrigger , Expression Blend, , , , . , Prism EventTrigger , InteractionRequestTrigger , Raised IInteractionRequest . XAML .

, , InteractionRequestTrigger . Silverlight Prism PopupChildWindowAction , . , . ContentTemplate PopupChildWindowAction , , UI, Content . Title .

, , PopupChildWindowAction , . Notification NotificationChildWindow , ConfirmationConfirmationChildWindow . NotificationChildWindow , , ConfirmationChildWindow OK Cancel, . , , ChildWindow PopupChildWindowAction .

, InteractionRequestTrigger PopupChildWindowAction , RI MVVM.

<i:Interaction.Triggers>
    <prism:InteractionRequestTrigger
            SourceObject="{Binding ConfirmCancelInteractionRequest}">
        <prism:PopupChildWindowAction
                  ContentTemplate="{StaticResource ConfirmWindowTemplate}"/>
    </prism:InteractionRequestTrigger>
</i:Interaction.Triggers>

<UserControl.Resources>
    <DataTemplate x:Key="ConfirmWindowTemplate">
        <Grid MinWidth="250" MinHeight="100">
            <TextBlock TextWrapping="Wrap" Grid.Row="0" Text="{Binding}"/>
        </Grid>
    </DataTemplate>
</UserControl.Resources>


ContentTemplate , UI Content . Content , , TextBlock Content .

, , , . , , , , . , RI MVVM, Confirmed Confirmation true , OK.

, . Prism InteractionRequestTrigger PopupChildWindowAction .


MVVM, , , , . ( , , , ). , , , .

, . Managed Extensibility Framework (MEF) Unity Application Block (Unity) , , .

, , , , ( ) . , , . , , .

, MEF


MEF, , Import , , , Export . , .

, QuestionnaireView RI MVVM, , Import . , MEF . set , .

[Import]
public QuestionnaireViewModel ViewModel {
    set { this.DataContext = value; }
}

, .

[Export]
public class QuestionnaireViewModel : NotificationObject {
    ...
}

, .

public QuestionnaireView() {
     InitializeComponent();
}
[ImportingConstructor]
public QuestionnaireView(QuestionnaireViewModel viewModel) : this() {
    this.DataContext = viewModel;
}


MEF, Unity. , , . , Visual Studio Expression Blend, , , . , , , , InitializeComponent .

, Unity


Unity, , MEF. , . , . , .

, , , . , , .

public QuestionnaireView() {
    InitializeComponent();
}
public QuestionnaireView(QuestionnaireViewModel viewModel) : this() {
    this.DataContext = viewModel;
}


, , Visual Studio Expression Blend.

, , . Unity set , .

public QuestionnaireView() {
    InitializeComponent();
}

[Dependency]
public QuestionnaireViewModel ViewModel {
    set { this.DataContext = value; }
}

Unity.

container.RegisterType<QuestionnaireViewModel>();

, .

var view = container.Resolve<QuestionnaireView>();

,


, , . , MEF Unity, .

. , UI, .

, RI MVVM , , . , . ShowView UI.

private void NavigateToQuestionnaireList() {
    //     "questionnaire list".
    this.uiService.ShowView(ViewNames.QuestionnaireTemplatesList);
}

UI UI . UI. ShowView UIService (, ), , .

public void ShowView(string viewName) {
    var view = this.ViewFactory.GetView(viewName);
    this.MainWindow.CurrentView = view;
}


Prism . , , , . , , "View-Based Navigation" 8, "Navigation".

MVVM


MVVM . - mocking . , , .

INotifyPropertyChanged


INotifyPropertyChanged , . , ; , , , , .


, , PropertyChanged , . , ChangeTracker , MVVM, , . . , .

var changeTracker = new PropertyChangeTracker(viewModel);
viewModel.CurrentState = "newState";
CollectionAssert.Contains(changeTracker.ChangedProperties, "CurrentState");

, , INotifyPropertyChanged , , , .


, , set , . , , , , .

var changeTracker = new PropertyChangeTracker(viewModel);

var question = viewModel.Questions.First() as OpenQuestionViewModel;
question.Question.Response = "some text";

CollectionAssert.Contains(changeTracker.ChangedProperties, "UnansweredQuestions");


INotifyPropertyChanged , PropertyChanged , , , , . , .

INotifyDataErrorInfo


, , , , IDataErrorInfo , ( Silverlight) INotifyDataErrorInfo . INotifyDataErrorInfo , , , , , .

INotifyDataErrorInfo : , , , , ErrorsChanged , GetErrors , .


, , . , GetErrors , , , . , , , , . , .

//  .
var notifyErrorInfo = (INotifyDataErrorInfo)question;
question.Response = -15;
Assert.IsTrue(notifyErrorInfo.GetErrors("Response").Cast<ValidationResult>().Any());
//  .
var notifyErrorInfo = (INotifyDataErrorInfo)question;
question.Response = 15;
Assert.IsFalse(notifyErrorInfo.GetErrors("Response").Cast<ValidationResult>().Any());

, , .

INotifyDataErrorInfo


GetErrors , INotifyDataErrorInfo , ErrorsChanged GetErrors . , HasErrors , .

INotifyDataErrorInfo . , , , - . , INotifyDataErrorInfo (, ).

, , :
  • HasErrors . , .
  • ErrorsChanged , , GetErrors . ( , ) , . GetErrors ErrorsChanged .

INotifyPropertyChanged , , NotifyDataErrorInfoTestHelper MVVM, INotifyDataErrorInfo , . , , , . .
var helper =
    new NotifyDataErrorInfoTestHelper<NumericQuestion, int?>(
        question,
        q => q.Response);

helper.ValidatePropertyChange(
    6,
    NotifyDataErrorInfoBehavior.Nothing);
helper.ValidatePropertyChange(
    20,
    NotifyDataErrorInfoBehavior.FiresErrorsChanged
    | NotifyDataErrorInfoBehavior.HasErrors
    | NotifyDataErrorInfoBehavior.HasErrorsForProperty);
helper.ValidatePropertyChange(
    null,
    NotifyDataErrorInfoBehavior.FiresErrorsChanged
    | NotifyDataErrorInfoBehavior.HasErrors
    | NotifyDataErrorInfoBehavior.HasErrorsForProperty);
helper.ValidatePropertyChange(
    2,
    NotifyDataErrorInfoBehavior.FiresErrorsChanged);


MVVM, , . , , .

, , , . , , , , , IAsyncResult , - , , UI.

, , , . , . , UI, , , , , " UI."

, , . , , mock-, , , , , .

UI, , . , , , . , . , , .

questionnaireRepositoryMock
    .Setup(
        r =>
            r.SubmitQuestionnaireAsync(
                It.IsAny<Questionnaire>(),
                It.IsAny<Action<IOperationResult>>()))
    .Callback<Questionnaire, Action<IOperationResult>>(
        (q, a) => callback = a);

uiServicemock
    .Setup(svc => svc.ShowView(ViewNames.QuestionnaireTemplatesList))
    .Callback<string>(viewName => requestedViewName = viewName);
submitResultMock
    .Setup(sr => sr.Error)
    .Returns<Exception>(null);

CompleteQuestionnaire(viewModel);
viewModel.Submit();
//      UI .
callback(submitResultMock.Object);
//    –     .
Assert.AreEqual(ViewNames.QuestionnaireTemplatesList, requestedViewName);


, .


, . "Trees in WPF" MSDN: http://msdn.microsoft.com/en-us/library/ms753391.aspx

, . "Attached Properties Overview" MSDN: http://msdn.microsoft.com/en-us/library/cc265152(VS.95).aspx

MEF, ."Managed Extensibility Framework Overview" MSDN: http://msdn.microsoft.com/en-us/library/dd460648.aspx.

Unity, ."Unity Application Block" MSDN: http://www.msdn.com/unity.

DelegateCommand , .Chapter 5, "Implementing the MVVM Pattern."

Microsoft Expression Blend, ."Working with built-in behaviors" MSDN: http://msdn.microsoft.com/en-us/library/ff724013(v=Expression.40).aspx.

Microsoft Expression Blend, ."Creating Custom Behaviors" MSDN: http://msdn.microsoft.com/en-us/library/ff724708(v=Expression.40).aspx.

Microsoft Expression Blend, ."Creating Custom Triggers and Actions" MSDN: http://msdn.microsoft.com/en-us/library/ff724707(v=Expression.40).aspx.

WPF Silverlight, ."Threading Model" "The Dispatcher Class" MSDN: http://msdn.microsoft.com/en-us/library/ms741870.aspx
http://msdn.microsoft.com/en-us/library/ms615907(v=VS.95).aspx.

unit- Silverlight, ."Unit Testing with Silverlight 2": http://www.jeff.wilcox.name/2008/03/silverlight2-unit-testing/.

, . "View-Based Navigation" in Chapter 8, "Navigation."

, , ."Event-based Asynchronous Pattern Overview" MSDN: http://msdn.microsoft.com/en-us/library/wewwczdw.aspx

IAsyncResult , ."Asynchronous Programming Overview" MSDN: http://msdn.microsoft.com/en-us/library/ms228963.aspx

Source: https://habr.com/ru/post/In176869/


All Articles