Mil*_*leu 0 c# wpf xaml user-controls mvvm
MySpecialView是一个复杂的图像控件,我想从不同的角度重用它,并ViewModel像本例一样传递它。
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>
<local:MySpecialView ViewModel="{Binding MySpecialViewModel}"></local:MySpecialView>
</Grid>
Run Code Online (Sandbox Code Playgroud)
主视图模型
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"));
}
}
Run Code Online (Sandbox Code Playgroud)
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>
Run Code Online (Sandbox Code Playgroud)
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();
}
}
Run Code Online (Sandbox Code Playgroud)
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;
}
}
Run Code Online (Sandbox Code Playgroud)
但是每当我MySpecialViewModel从中分配属性时MainViewModel,该RaisePropertyChange事件不会强制Image元素或其他绑定从中更新MySpecialViewModel。
我在这里做错了什么?这是一般的错误方法吗?
您也太习惯了“先查看先查看”(VFA)。您最好使用“ ViewModel-First-Approach”(VMFA)。在VFA中,您可以从主视图中放置子视图,每个子视图都通过链接到各自的ViewModel DataContext。
在VMFA中,您的ViewModel包含子ViewModels的引用。您可以通过属性绑定公开这些ViewModel引用,而View通过可以显示它们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>
Run Code Online (Sandbox Code Playgroud)
主视图模型
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"));
}
}
Run Code Online (Sandbox Code Playgroud)
MySpecialView不需要DependencyProperty,也不需要设置DataContext。将DataContext被自动设置的DataTemplate一部分。您MySpecialViewModel可以保持原样。
我只是意识到您的MainWindow也没有DataContext正确执行。
MainWindow.xaml.cs
public partial class MainWindow: Window
{
public MainWindow()
{
InitializeComponents();
this.DataContext = new MainViewModel();
}
}
Run Code Online (Sandbox Code Playgroud)