Подтвердить что ты не робот

Пользовательский контроль WPF ад с MVVM и свойствами зависимостей

Это то, что я пытаюсь сделать:

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

    <lib:ControlView ControlsText={Binding Path=UsersOwnViewModelText} />
    
  • Я использую шаблон MVVM.

  • Я привязываю свои ViewModels к их представлению с помощью <DataTemplates>

    <DataTemplate DataType="{x:Type local:ControlViewModel}">  
        <local:ControlView />  
    </DataTemplate>
    

У меня есть два вопроса:

  • Я правильно понимаю, что если UserControl потребляется в XAML, тогда UserControl должен установить ViewModel как его DataContext, когда событие управления Loaded срабатывает вместо использования метода <DataTemplate>?

  • Как я могу разрешить пользователям привязывать данные к моим свойствам зависимостей управления, сохраняя при этом данные, привязанные к моей ViewModel?

4b9b3361

Ответ 1

Во-первых, я не думаю, что MVVM - хороший выбор, если вы разрабатываете UserControl, который будет потребляться другими. Беспокойный контроль - это то, что вы действительно должны развивать. У Джеремии Моррилл есть сообщение в блоге об этой теме.

С учетом сказанного вы можете установить datacontext с помощью XAML, если у вас есть стандартный конструктор по умолчанию.

Внутри ControlView.xaml put:

<UserControl.DataContext>
    <local:ControlViewModel />
</UserControl.DataContext>

Ответ 2

Вы должны разделить два варианта использования:

  • Элемент управления (user), который будет использоваться другими разработчиками.
  • Пользовательский элемент управления, который будет использоваться вашим приложением.

Важно то, что последнее зависит от первого, а не наоборот.

Использование case 1 будет использовать свойства зависимостей, привязки шаблонов, все, что входит в создание регулярного элемента управления WPF:

MyControl.cs:

public class MyControl : Control
{
    // dependency properties and other logic
}

Generic.xaml:

<ControlTemplate Type="local:MyControl">
    <!-- define the default look in here, using template bindings to bind to your d-props -->
</ControlTemplate>

Затем вы определяете пример использования 2 как:

MyViewModel.cs:

public class MyViewModel : ViewModel
{
    // properties and business logic
}

MyView.xaml:

<UserControl ...>
    <local:MyControl SomeProperty="{Binding SomePropertyOnViewModel}" .../>
</UserControl>

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

Ответ 3

A UserControl является частью "View" в "MVVM", так же как элементы управления TextBox или ListView являются частью представления.

Если вы решите использовать MVVM для разработки своего UserControl или записать его в QBASIC (не рекомендуется), он не нарушит шаблон MVVM для потребителей вашего UserControl, если они могут делать все, что им нужно с помощью UserControl, привязав к DependencyProperty, выставленному на вашем UserControl. т.е. ваш UserControl должен показывать свойства, от которых он зависит (отсюда и название). Как только вы поймете, этот DependencyProperty внезапно приобретет большой смысл, и вы хотите, чтобы они были полезны для измененных обработчиков событий и значений по умолчанию, которые вы указываете в своем конструкторе.

Если ваш UserControl находится в другой сборке или нет, я не вижу, как это имеет значение.

Тем не менее многие будут выступать за то, чтобы вы создали свой UserControl с использованием шаблона MVVM для всех хороших причин, связанных с MVVM, например. помогая другому разработчику смотреть на ваш код. Однако некоторые вещи просто невозможны и/или намного сложнее и менее эффективны, взломав XAML, чтобы сделать это - я не говорю о вашем садовом разнообразии. Добавить пользовательскую форму, но, например, UserControl обрабатывает макет тысяч визуальных эффектов. Кроме того, поскольку вы работаете в своем представлении, вы НЕ хотите, чтобы ваши тэги UserControl ViewModels смешивались с вашими приложениями!

В основном я говорю, что в MVVM хорошо использовать MVVM на вашем представлении!

Ответ 4

В принципе, вместо привязки вашего datacontext UserControl к userControlViewModel лучше сделать это на первом дочернем элементе пользовательского элемента управления. Таким образом, все ссылки, которые вы делаете в элементе управления, будут привязаны к userControlViewModel, но свойства зависимостей могут быть установлены из набора контекстов данных, в котором вы хотите использовать свой UserControl.

Это из проекта, над которым я работаю:

<UserControl x:Class="Six_Barca_Main_Interface.MyUserControl"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:Six_Barca_Main_Interface"
             xmlns:System="clr-namespace:System;assembly=mscorlib" 
             mc:Ignorable="d" 
             d:DesignHeight="900" d:DesignWidth="900">

    <DockPanel  x:Name="rootDock" >
        <TextBlock>{Binding SomethingInMyUserControlViewModel}</TabControl>
    </DockPanel>
</UserControl>

Затем на код позади:

public partial class MyUserControl : UserControl
{
    UserControlViewModel _vm;

    public MyUserControl()
    {
        InitializeComponent();

        //internal viewModel set to the first child of MyUserControl
         rootDock.DataContext = new UserControlViewModel();

        _vm = (UserControlViewModel)rootDock.DataContext;


        //sets control to be able to use the viewmodel elements

     }

     #region Dependency properties 
     public string textSetFromApplication
     {
         get{return (string)GetValue(textSetFromApplicationProperty);}
         set{SetValue(textSetFromApplicationProperty, value);}
     }

     public static readonly DependencyProperty textSetFromApplicationProperty = DependencyProperty.Register("textSetFromApplication", typeof(string), typeof(MyUserControl), new PropertyMetadata(null, OnDependencyPropertyChanged));

     private static void  OnDependencyPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
     {
        ((MyUserControl)d)._vm.SomethingInMyUserControlViewModel = 
             e.NewValue as string;
     }
#endregion

Затем, когда вы используете это в своем основном представлении, вы можете установить свойство зависимостей со значением, которое вы хотите передать в MyUSerControl