Пользовательский контроль 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?
Ответы
Ответ 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