MVVM Light UserControl未在MainWindow中显示

时间:2016-01-25 21:55:18

标签: c# wpf xaml mvvm-light

对于通过ImagePositionView加载和显示的UserControl视图(MainWindow),我有点迷失了。我一直在使用MVVM Light作为框架来促进这一点。目前所发生的一切是ViewModel的命名空间路径显示在MainWindow中,而不是预期的图像。

以下是相关文件,所以希望这是一件简单易行的事情。

ImagePositionView.xaml:

<UserControl x:Class="PixelPosition.View.ImagePositionView"
             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:i="http://schemas.microsoft.com/expression/2010/interactivity"
             xmlns:cmd="http://www.galasoft.ch/mvvmlight"
             xmlns:local="clr-namespace:PixelPosition"
             DataContext="{Binding ImagePosition, Source={StaticResource Locator}}"
             mc:Ignorable="d" 
             d:DesignHeight="600" d:DesignWidth="1000" Background="White">
    <Grid>

        <Viewbox HorizontalAlignment="Center">
            <Grid>
                <Image x:Name="ColourImage" Source="{Binding ColourImage}" Stretch="UniformToFill" />
            </Grid>
        </Viewbox>

    </Grid>

</UserControl>

MainViewModel.cs:

using System.Windows.Input;
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;

namespace PixelPosition.ViewModel
{

    public class MainViewModel : ViewModelBase
    {
        private string title = "This stupid thing isn't working :(";

        public string Title
        {
            get { return this.title; }
            set
            {
                if (this.title == value) return;
                this.title = value;
                RaisePropertyChanged("Title");
            }
        }

        /// <summary>
        /// Initializes a new instance of the MainViewModel class.
        /// </summary>
        public MainViewModel()
        {
        }
    }
}

ImagePositionViewModel.cs:

using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using GalaSoft.MvvmLight;

namespace PixelPosition.ViewModel
{
    public class ImagePositionViewModel : ViewModelBase
    {

        private WriteableBitmap colourBitmap = null;

        public ImageSource ColourImage
        {
            get
            {
                return this.colourBitmap;
            }
        }

        public ImagePositionViewModel()
        {
            // Open image to writeablebitmap
            string path = @"C:\Some\Path\To\ColorImage.png";

            Stream imageStreamSource = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read);
            var decoder = new PngBitmapDecoder(imageStreamSource, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);
            BitmapSource source = decoder.Frames[0];

            int width = source.PixelWidth;
            int height = source.PixelHeight;
            int stride = source.Format.BitsPerPixel / 8 * width;
            byte[] data = new byte[stride * height];
            source.CopyPixels(data, stride, 0);

            this.colourBitmap = new WriteableBitmap(width, height, 96.0, 96.0, source.Format, null);
            this.colourBitmap.WritePixels(new Int32Rect(0, 0, width, height), data, stride, 0);

        }

    }
}

ViewModelLocator.cs:

using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Ioc;
using Microsoft.Practices.ServiceLocation;

namespace PixelPosition.ViewModel
{

    public class ViewModelLocator
    {

        public ViewModelLocator()
        {
            ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);

            SimpleIoc.Default.Register<MainViewModel>();
            SimpleIoc.Default.Register<ImagePositionViewModel>();
        }

        public MainViewModel Main
        {
            get
            {
                return ServiceLocator.Current.GetInstance<MainViewModel>();
            }
        }

        public ImagePositionViewModel ImagePosition
        {
            get
            {
                return ServiceLocator.Current.GetInstance<ImagePositionViewModel>();
            }
        }

        public static void Cleanup()
        {
            // TODO Clear the ViewModels
        }
    }
}   

的App.xaml:

<Application x:Class="PixelPosition.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:PixelPosition"
             StartupUri="MainWindow.xaml"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:vm="clr-namespace:PixelPosition.ViewModel"
             d1p1:Ignorable="d"
             xmlns:d1p1="http://schemas.openxmlformats.org/markup-compatibility/2006">
  <Application.Resources>
    <ResourceDictionary>
      <vm:ViewModelLocator x:Key="Locator" d:IsDataSource="True" />
    </ResourceDictionary>
  </Application.Resources>
</Application>

MainWindow.xaml:

<Window x:Class="PixelPosition.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:PixelPosition"
        DataContext="{Binding Main, Source={StaticResource Locator}}"
        mc:Ignorable="d"
        Title="{Binding Title}" Height="800" Width="1000">
    <Grid Margin="10 0 10 0">
        <Border Background="GhostWhite" BorderBrush="LightGray" BorderThickness="1" CornerRadius="5">
            <ContentControl Content="{Binding ImagePosition, Source={StaticResource Locator}}" />
        </Border>

    </Grid>
</Window>

2 个答案:

答案 0 :(得分:1)

在MainWindow.xaml的Resources <Window.Resources> <DataTemplate DataType="{x:Type local:ImagePositionViewModel}"> <local:ImagePositionView /> </DataTemplate> </Window.Resources> 集合中添加此内容:

local

请注意,您的命名空间可能不同,我的名字是ImagePositionViewModel

ContentControl已正确加载到DataTemplate,问题在于它只是不知道如何实际渲染&#34;它,所以我们为它提供了Sub FindMyResults(ByVal sName as string) Dim Result as Variant Dim ResultRange as Range Dim N as Long Result = FindAllOnWorksheets(InWorkbook:=ThisWorkbook, _ InWorksheets:="Sheet1:Sheet3", _ SearchAddress:="$B:$B", _ FindWhat:=sName, _ LookIn:=xlValues, _ LookAt:=xlWhole, _ SearchOrder:=xlByRows, _ MatchCase:=False) For N = LBound(Result) To UBound(Result) If Not Result(N) Is Nothing Then 'There is at least one result For Each ResultRange In Result(N).Cells 'Do something with your results. Next ResultRange End If Next N End Sub

答案 1 :(得分:1)

您的代码有几个问题,我会尝试逐个枚举它们:

<强>第一

在MainWindow视图中,ContentControl的内容与ImagePositionViewModel实例绑定,这是错误的,内容需要绑定到UserControl的实例:

 <Border Background="GhostWhite" BorderBrush="LightGray" BorderThickness="1" CornerRadius="5">
        <ContentControl  >
            <YourNameSpace:ImagePositionView/>
        </ContentControl>
    </Border>

您可以考虑将ContentControl的Content属性绑定到 MainViewModel 中定义的属性,该属性将保存对您要显示的UserControl的引用。< / p>

<强>第二

ImagePositionViewModel中,您需要正确定义ColourImage属性并使用bitmapImage进行设置,而不是设置字段colourBitmap,这样会通知用户界面因为RaisePropertyChanged将被调用:

public const string ColourImagePropertyName = "ColourImage";
    private WriteableBitmap  colourBitmap =  null;
    public WriteableBitmap  ColourImage
    {
        get
        {
            return colourBitmap ;
        }

        set
        {
            if (Equals(colourBitmap, value))
            {
                return;
            }

            colourBitmap  = value;
            RaisePropertyChanged(ColourImagePropertyName);
        }
    }

并设置属性而不是fild:

 //...
 int stride = source.Format.BitsPerPixel / 8 * width;
 byte[] data = new byte[stride * height];
 source.CopyPixels(data, stride, 0);
 var cb = new WriteableBitmap(width, height, 96.0, 96.0, source.Format, null);
 cb.WritePixels(new Int32Rect(0, 0, width, height), data, stride, 0);
 ColourImage=cb;

<强>最后

你的代码现在应该可以工作,但是,在VM的构造函数中加载图像是个坏主意,你应该在UserControl的ViewModel中定义一个Loaded命令并绑定使用Loaded向该命令发送EventToCommand事件,因此在ImagePosition Vm中定义LoadedCommand,如下所示:

 private RelayCommand _loadedCommand;
    public RelayCommand LoadedCommand 
    {
        get
        {
            return _loadedCommand
                ?? (_loadedCommand = new RelayCommand(
                () =>
                {
                    // Open image to writeablebitmap
                    string path = @"C:\Some\Path\To\ColorImage.png";

                    Stream imageStreamSource = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read);
                    var decoder = new PngBitmapDecoder(imageStreamSource, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);
                    BitmapSource source = decoder.Frames[0];

                    int width = source.PixelWidth;
                    int height = source.PixelHeight;
                    int stride = source.Format.BitsPerPixel / 8 * width;
                    byte[] data = new byte[stride * height];
                    source.CopyPixels(data, stride, 0);

                    var cb = new WriteableBitmap(width, height, 96.0, 96.0, source.Format, null);
                    cb.WritePixels(new Int32Rect(0, 0, width, height), data, stride, 0);
                    ColourImage = cb;
                }));
        }
    }

*并从Vm构造函数中删除图像加载代码,

然后在ImagePositionView usercontrol中将loaded事件绑定到您已定义的命令:

    //..
    d:DesignHeight="600" d:DesignWidth="1000" Background="White" >

<i:Interaction.Triggers>
    <i:EventTrigger EventName="Loaded">
        <command:EventToCommand Command="{Binding Mode=OneWay, Path=LoadedCommand}"
                        PassEventArgsToCommand="True" />
    </i:EventTrigger>
</i:Interaction.Triggers>

    <Grid>
 //..

您应该添加以下命名空间:

xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:command="http://www.galasoft.ch/mvvmlight"