Creating generalized user controls with MVVM Light

怎甘沉沦 提交于 2019-12-12 04:34:29

问题


How to create a general user control using MVVM Light?

All the main views in the application seem to work fine. However, general controls doesn't seem to accept bindings. This is my FileDiplay control. An icon and a TextBlock displaying a filename next to it.


Utilization

In one of the main views, I try to bind a FileName inside an ItemsTemplate of an ItemsControl. Specifying a literal, like FileName="xxx" works fine, but binding doesn't.

<local:FileLink FileName="{Binding FileName}" />

I've been playing around with DependencyProperty and INotifyPropertyChanged a lot. And seemingly there's no way around a DependencyProperty, since it can't be bound otherwise. When using a simple TextBlock instead of this user control, binding is accepted.


I didn't include the locator or the utilizing control in order to avoid too much code. In fact, I think this is a very simple problem that I haven't found the solution for, yet. I do think that having the DataContext set to the ViewModel is correct, since no list binding or real UserControl separation is possible. I've also debugged into the setters and tried the different approaches.

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:


Do not explicitly set the DataContext of your UserControl, because it effectively prevents that the control inherits the DataContext from its parent control, which is what you expect in a Binding like

<local:FileLink FileName="{Binding FileName}" />

Also, do not wrap the view model properties like you did with the FileName property. If the view model has a FileName property, the above binding works out of the box, without any wrapping of the view model.

If you really need a FileName property in the UserControl, it should be a regular dependency property

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); }
    }
}

and you should bind to it by specifying the UserControl as 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>


来源:https://stackoverflow.com/questions/41089950/creating-generalized-user-controls-with-mvvm-light

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!