将 ViewModel 传递给 UserControl [英] Pass ViewModel to UserControl

查看:46
本文介绍了将 ViewModel 传递给 UserControl的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

MySpecialView 是一个复杂的图像控件,我想从不同的视图中重用它,并在这个例子中传递它的 ViewModel.

MySpecialView is a complex image control, I would like to reuse it from different views and pass its ViewModel as in this example.

主窗口.xaml

<Window x:Class="YouBug.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:YouBug"
    mc:Ignorable="d"
    DataContext="{Binding MainViewModel}"
    Title="MainWindow" Height="350" Width="525">
<Grid>
    <local:MySpecialView ViewModel="{Binding MySpecialViewModel}"></local:MySpecialView>
</Grid>

主视图模型

    public class MainViewModel
{
    public MySpecialViewModel MySpecialViewModel { get; set; }

    public MainViewModel()
    {
        MySpecialViewModel = new MySpecialViewModel();
        //gets not displayed!
        Task.Run(() => MySpecialViewModel.changeImage(5000, "C:\\Users\\user\\Pictures\\Capture.PNG"));
    }
}

MySpecialView.xaml

MySpecialView.xaml

<UserControl x:Class="YouBug.MySpecialView"
         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:YouBug"
         mc:Ignorable="d" 
         d:DesignHeight="300" d:DesignWidth="300">
<Grid>
    <Image Source="{Binding ImageSource}" />
</Grid>

MySpecialView.xaml.cs

MySpecialView.xaml.cs

    public partial class MySpecialView : UserControl
{
    public static readonly DependencyProperty ViewModelProperty = DependencyProperty.Register("ViewModel", typeof(MySpecialViewModel), typeof(MySpecialView), new FrameworkPropertyMetadata(new MySpecialViewModel(), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));

    public MySpecialViewModel ViewModel { get { return (MySpecialViewModel)GetValue(ViewModelProperty); } set { SetValue(ViewModelProperty, value); } }

    public MySpecialView()
    {
        DataContext = ViewModel;
        InitializeComponent();
    }
}

MySpecialViewModel

MySpecialViewModel

    public class MySpecialViewModel : ViewModelBase
{
    public BitmapSource imageSource { get; set; }
    public BitmapSource ImageSource { get { return imageSource; }
        set { if (value != imageSource)
            {
                imageSource = value; RaisePropertyChanged("ImageSource");
            }
        } }

    public MySpecialViewModel()
    {
        //gets displayed
        ImageSource = new BitmapImage(new Uri("C:\\Users\\user\\Pictures\\test.jpg"));

        //gets displayed aswell
        Task.Run(() => changeImage(10000, "C:\\Users\\user\\Pictures\\clickMe.png"));
    }

    public async void changeImage(int sleep, string uri)
    {
        await Task.Delay(sleep);
        BitmapSource source = new BitmapImage(new Uri(uri));
        source.Freeze();
        ImageSource = source;
    }

}

但是每当我从 MainViewModel 分配 MySpecialViewModel 的属性时,RaisePropertyChange 事件不会强制 Image 元素或从 MySpecialViewModel 更新的其他绑定.

But whenever I assign MySpecialViewModels Properties from MainViewModel, the RaisePropertyChange event does not force the Image element or other bindings to update from the MySpecialViewModel.

我在这里做错了什么?这是一个普遍的错误方法吗?

What am I doing wrong here? Is this a general wrong approach?

推荐答案

你太习惯View-First-Approach"了(VFA).您的情况最好使用ViewModel-First-Approach";(VMFA).在 VFA 中,您将子视图放置在主视图中,每个子视图通过 DataContext 链接到各自的 ViewModel.

You are too used to "View-First-Approach" (VFA). Your situation is better off using "ViewModel-First-Approach" (VMFA). In VFA, you place your child views from the main View, and each subview is linked to the respective ViewModel via DataContext.

在 VMFA 中,您的 ViewModel 包含子 ViewModel 的引用.您通过属性绑定公开这些 ViewModel 引用,而 View 通过 DataTemplate 显示它们.

In VMFA, your ViewModel holds references of sub-ViewModels. You expose these ViewModel references through property binding, and the View display them via DataTemplate.

主窗口.xaml

<Window x:Class="YouBug.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:YouBug"
    mc:Ignorable="d"
    DataContext="{Binding MainViewModel}"
    Title="MainWindow" Height="350" Width="525">
<Grid>
    <Grid.Resources>
        <DataTemplate DataType="{x:Type vm:MySpecialViewModel}">
            <local:MySpecialViewModel />
        </DataTemplate>
    </Grid.Resources>
    <ContentControl Content={Binding MySpecialView}" />
</Grid>

主视图模型

public class MainViewModel : ViewModelBase // Not sure why you didn't subclass ViewModelBase in your question
{
    private MySpecialViewModel _mySpecialViewModel;
    public MySpecialViewModel MySpecialViewModel
    {
        get
        {
            return _mySpecialViewModel;
        }
        set
        {
            if (value != _mySpecialViewModel)
            {
                _mySpecialViewModel = value;
                RaisePropertyChanged(); // The property changed method call
            }
        }
    }

    public MainViewModel()
    {
        MySpecialViewModel = new MySpecialViewModel();
        //gets not displayed!
        Task.Run(() => MySpecialViewModel.changeImage(5000, "C:\\Users\\user\\Pictures\\Capture.PNG"));
    }
}

MySpecialView 不需要那个 DependencyProperty,也不需要设置 DataContext.DataContextDataTemplate 部分自动设置.您的 MySpecialViewModel 可以保持原样.

MySpecialView does not need that DependencyProperty, nor set the DataContext. The DataContext is set automatically by the DataTemplate part. Your MySpecialViewModel can stay as it is now.

我刚刚意识到您的 MainWindow 也没有正确执行 DataContext.

I just realized your MainWindow is not doing the DataContext correctly either.

MainWindow.xaml.cs

MainWindow.xaml.cs

public partial class MainWindow: Window
{
    public MainWindow()
    {
        InitializeComponents();
        this.DataContext = new MainViewModel();
    }
}

这篇关于将 ViewModel 传递给 UserControl的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆