c# - 以编程方式创建一个带有由 Caliburn Micro 初始化的子元素的弹出窗口

标签 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 View
  • AudioCaptureViewModel - 包含所有音频捕获逻辑的 ViewModel

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

最佳答案

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

您也可以引入接口(interface)并使用 DI,但为了时间的缘故,这里是独立类。模型优先绑定(bind)的主要部分是 ViewLocator.LocateForModel,它从 ViewModel 返回 View (又名魔法)

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

关于c# - 以编程方式创建一个带有由 Caliburn Micro 初始化的子元素的弹出窗口,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20730061/

相关文章:

wpf - 如何阻止在 DotNetBrowser 中加载远程内容?

c# - 绑定(bind)到不带参数的成员函数?

c# - 如何将列表列表绑定(bind)到 View ?

java - 为什么 DES 加密和 DESede 加密结果相同?

c# - MS Dynamics 365 - 生成自定义序列号,确保唯一性

c# - SqlParameter(string, object) 无法处理常量值

c# - 如何在 C# 中执行 fsync()?

c# - 将标签内容绑定(bind)到嵌套类中的值而不是 Datacontext

wpf - 在 XAML 或代码中绑定(bind) GrivdViewColumn 的 Width 属性?

c# - 当许多方法想要更改相同的属性时,如何避免通过引用参数?