Создание обобщенных пользовательских элементов управления с помощью MVVM Light
Как создать общий пользовательский элемент управления с помощью MVVM Light?
Все основные виды в приложении работают нормально. Тем не менее, общий контроль, кажется, не принимает привязки. Это мое FileDiplay
контроль. Значок и TextBlock отображают имя файла рядом с ним.
использование
В одном из основных представлений я пытаюсь связать FileName внутри ItemsTemplate
из ItemsControl
, Указание литерала, например FileName="xxx"
работает нормально, но привязка - нет.
<local:FileLink FileName="{Binding FileName}" />
Я играл с DependencyProperty
а также INotifyPropertyChanged
много. И, похоже, нет способа обойти DependencyProperty, так как он не может быть связан иначе. При использовании простого TextBlock
вместо этого пользовательского элемента управления принимается привязка.
Я не включил локатор или управляющий элемент, чтобы избежать слишком большого количества кода. На самом деле, я думаю, что это очень простая проблема, решение которой я еще не нашел. Я действительно считаю, что иметь DataContext, установленный в ViewModel, правильно, так как никакая привязка к списку или реальное разделение UserControl невозможны. Я также отлаживал сеттеры и пробовал разные подходы.
FileLink.xaml
<local:UserControlBase
x:Class="....FileLink"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:..."
mc:Ignorable="d" DataContext="{Binding FileLink, Source={StaticResource Locator}}">
<Grid>
<StackPanel Orientation="Horizontal">
<Image Source="{Binding Icon}" Margin="0,0,5,0" />
<TextBlock Text="{Binding FileName}" />
</StackPanel>
</Grid>
</local:UserControlBase>
FileLink.xaml.cs
using System.Windows;
using System.Windows.Media;
namespace ...
{
public partial class FileLink : UserControlBase
{
private FileLinkViewModel ViewModel => DataContext as FileLinkViewModel;
public static DependencyProperty FileNameProperty = DependencyProperty.Register(nameof(FileName), typeof(string), typeof(FileLink));
public ImageSource Icon
{
get
{
return App.GetResource("IconFileTypeCsv.png"); // TODO:...
}
}
public string FileName
{
get
{
return ViewModel.FileName;
}
set
{
ViewModel.FileName = value;
}
}
public FileLink()
{
InitializeComponent();
}
}
}
FileLinkViewModel.cs
using GalaSoft.MvvmLight;
namespace ...
{
public class FileLinkViewModel : ViewModelBase
{
private string _FileName;
public string FileName
{
get
{
return _FileName;
}
set
{
Set(() => FileName, ref _FileName, value);
}
}
}
}
1 ответ
Не устанавливайте явно DataContext вашего UserControl, потому что он эффективно предотвращает наследование элемента управления DataContext от его родительского элемента управления, чего вы ожидаете в Binding, например
<local:FileLink FileName="{Binding FileName}" />
Кроме того, не переносите свойства модели представления, как вы сделали со свойством FileName. Если модель представления имеет свойство FileName, вышеуказанная привязка работает "из коробки", без переноса модели представления.
Если вам действительно нужно FileName
свойство в UserControl, оно должно быть обычным свойством зависимости
public partial class FileLink : UserControlBase
{
public FileLink()
{
InitializeComponent();
}
public static readonly DependencyProperty FileNameProperty =
DependencyProperty.Register(nameof(FileName), typeof(string), typeof(FileLink));
public string FileName
{
get { return (string)GetValue(FileNameProperty); }
set { SetValue(FileNameProperty, value); }
}
}
и вы должны привязаться к нему, указав UserControl как RelativeSource:
<local:UserControlBase ...> <!-- no DataContext assignment -->
<StackPanel Orientation="Horizontal">
<Image Source="IconFileTypeCsv.png" Margin="0,0,5,0" />
<TextBlock Text="{Binding FileName,
RelativeSource={RelativeSource AncestorType=UserControl}}" />
</StackPanel>
</local:UserControlBase>