Pass ViewModel to UserControl

后端 未结 2 1484
臣服心动
臣服心动 2021-01-28 07:34

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

MainWindow.x

相关标签:
2条回答
  • 2021-01-28 08:11

    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.

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

    MainWindow.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>
    

    MainViewModel

    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 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.

    Edit

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

    MainWindow.xaml.cs

    public partial class MainWindow: Window
    {
        public MainWindow()
        {
            InitializeComponents();
            this.DataContext = new MainViewModel();
        }
    }
    
    0 讨论(0)
  • 2021-01-28 08:13

    Do not specify viewmodel property in you view, use DataContext. See the following code.

    public partial class MySpecialView : UserControl
    {
    
        public MySpecialView()
        {
            InitializeComponent();
        }
    }
    

    ViewModel for special:

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

    In XAML special:

        <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>
    

    For main:

    public class MainViewModel : ViewModelBase
    {
        public MySpecialViewModel SpecialViewModel
        { 
            get { return _specialViewModel; }
            set
            {
              if (value != _specialViewModel)
              {
                 _specialViewModel= value;
                 RaisePropertyChanged("SpecialViewModel");
              }
            } 
         }
    
        private MySpecialViewModel _specialViewModel;
    
            public MainViewModel()
            {
                MySpecialViewModel = new MySpecialViewModel();
                //gets not displayed!
                Task.Run(() => MySpecialViewModel.changeImage(5000, "C:\\Users\\user\\Pictures\\Capture.PNG"));
            }
        }
    

    And in 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"
        Title="MainWindow" Height="350" Width="525">
    <Window.DataContext>
        <MainWindowViewModel/
    </Window.DataContext>
    <Grid>
        <local:MySpecialView DataContext="{Binding Path=SpecialViewModel}"></local:MySpecialView>
    </Grid>
    
    0 讨论(0)
提交回复
热议问题