以编译方式创建一个带有Caliburn Micro初始化的Child元素的Popup

时间:2013-12-22 13:41:20

标签: c# wpf mvvm windows-store-apps caliburn.micro

Windows.Media.Captures有一个方便的CameraCaptureUI类,可以按如下方式实例化,以显示用户捕获照片或视频的对话框:

// Create dialog to Capture Video
CameraCaptureUI dialog = new CameraCaptureUI();
dialog.VideoSettings.Format = CameraCaptureUIVideoFormat.Mp4;

StorageFile file = await dialog.CaptureFileAsync(CameraCaptureUIMode.Video);
if (file != null)
{
   // Do something with file...
}

我想创建自己的自定义音频捕获类,它以非常类似的方式工作:

// Create dialog to Capture Audio
AudioCaptureUI dialog = new AudioCaptureUI();

StorageFile file = await dialog.CaptureFileAsync();
if (file != null)
{
   // Do something with file...
}

为了做到这一点,我创建了以下三个文件:

  • AudioCaptureUI - 用户实例化以显示音频捕获对话框的类
  • AudioCaptureView - 用于音频捕获体验的UI视图
  • AudioCaptureViewModel - 包含所有音频捕获逻辑的ViewModel

要创建全屏音频捕获对话框,我发现最好的方法是使用Popup并将其子项设置为AudioCaptureView。我对这种方法的问题在于它推动我使用View-First模式。由于我使用的是Caliburn Micro,我希望能够通过首先创建ViewModel来使用CM来实例化View。

我目前所拥有的内容如下:

public class AudioCaptureUI
{
    private Popup _popup;
    private TaskCompletionSource<StorageFile> _taskCompletionSource;

    public IAsyncOperation<StorageFile> CaptureFileAsync()
    {
        // Force my View to be full screen
        AudioCaptureView audioCaptureView = new AudioCaptureView
        {
            Width = Window.Current.Bounds.Width,
            Height = Window.Current.Bounds.Height
        };

        // Creating View, instead of a ViewModel. Renders Caliburn Micro useless!
        _popup = new Popup { Child = audioCaptureView };

        if (_popup.Child != null)
        {
            SubscribeEvents();
            _popup.IsOpen = true;
        }

        return AsyncInfo.Run(WaitForInput);
    }

    ...
}

上述模式有效。但是,我被迫手动连接所有动作​​,无法利用Caliburn Micro的MVVM优点。

我应该如何从我的AudioCaptureUI类以编程方式实例化ViewModel?

同样重要的是要强调我正在使用 Windows应用商店应用并使用WinRT CM端口。

2 个答案:

答案 0 :(得分:0)

Caliburn.Micro WindowManager可能会取得一些成功。在官方文档中没有太多关于它(你最好搜索谷歌和CM的讨论)。我在我的一个应用程序中使用它,我需要在新窗口中托管特定的ViewModel,并希望利用所有Caliburn.Micro善良(以及我现有的Views

看一下Caliburn.Micro.IWindowManager界面,你会看到一些方便的方法,你可以从一个WindowManager实例调用(取决于你之后的弹出窗口类型)。

public interface IWindowManager
{
    bool? ShowDialog(object rootModel, object context = null, IDictionary<string, object> settings = null);
    void ShowPopup(object rootModel, object context = null, IDictionary<string, object> settings = null);
    void ShowWindow(object rootModel, object context = null, IDictionary<string, object> settings = null);
}

在我的应用程序中,要使用我选择的ViewModel弹出我的窗口,我在这些行中做了一些事情(插入了你的名字):

// Some basic Window settings.
dynamic settings = new ExpandoObject();
settings.Title = "Test Window";
settings.WindowStartupLocation = WindowStartupLocation.Manual;
settings.SizeToContent = SizeToContent.Manual;
settings.Width = 450;
settings.Height = 300;

var localAudioCaptureViewModel new AudioCaptureViewModel ();
WindowManagerFactory.WindowManager.ShowWindow(localAudioCaptureViewModel, null, settings); // I didn't require context (null)

Caliburn.Micro应该将你的视图解析为正确的ViewModel,你很高兴。

答案 1 :(得分:0)

您始终可以在自己的项目中将WindowManager移植到WinRT。看看来源我不认为太多需要改变。 https://caliburnmicro.codeplex.com/SourceControl/latest#src/Caliburn.Micro.Platform/net40/WindowManager.cs

你也可以带接口并使用DI,但为了时间的缘故,这里是独立的课程。模型第一次绑定的主要部分是ViewLocator.LocateForModel,它从ViewModel返回视图(又称魔术)

using System;
using System.Collections.Generic;
using Windows.UI.Xaml.Controls.Primitives;

namespace Caliburn.Micro
{
    public class WindowManager
    {    
        public virtual void ShowPopup(object rootModel, object context = null, IDictionary<string, object> settings = null)
        {
            var popup = CreatePopup(rootModel, settings);
            var view = ViewLocator.LocateForModel(rootModel, popup, context);

            popup.Child = view;
            //popup.SetValue(View.IsGeneratedProperty, true);

            ViewModelBinder.Bind(rootModel, popup, null);
            Caliburn.Micro.Action.SetTargetWithoutContext(view, rootModel);

            var activatable = rootModel as IActivate;
            if (activatable != null)
            {
                activatable.Activate();
            }

            var deactivator = rootModel as IDeactivate;
            if (deactivator != null)
            {
                popup.Closed += delegate { deactivator.Deactivate(true); };
            }

            popup.IsOpen = true;
            //popup.CaptureMouse();
        }

        protected virtual Popup CreatePopup(object rootModel, IDictionary<string, object> settings)
        {
            var popup = new Popup();

            ApplySettings(popup, settings);

            return popup;
        }

        bool ApplySettings(object target, IEnumerable<KeyValuePair<string, object>> settings)
        {
            if (settings != null)
            {
                var type = target.GetType();

                foreach (var pair in settings)
                {
                    var propertyInfo = type.GetPropertyCaseInsensitive(pair.Key);

                    if (propertyInfo != null)
                    {
                        propertyInfo.SetValue(target, pair.Value, null);
                    }
                }

                return true;
            }

            return false;
        }
    }
}

然后你需要做的就是创建一个实例并给它一个ViewModel:

var windowManager = new WindowManager();
windowManager.ShowPopup(new MyPopupThingViewModel());

注意:我在8.1应用程序中只使用了这个,所以不能100%确定它是否完全适用于8.0