gpt4 book ai didi

wpf - ViewModel 的设计时设置

转载 作者:行者123 更新时间:2023-12-03 23:54:15 25 4
gpt4 key购买 nike

我正在使用 Visual Studio 2013 的设计器在 WPF 中创建我的用户控件,并且我使用的是 MVVM 方法。

我正在尝试找到对我的 View 模型进行“设计时”设置的最佳方法,以便我立即看到设计器中更改属性值的效果。我使用了不同的设计和技术来支持这一点,但没有什么是我想要的。我想知道是否有人有更好的想法...

情况(简化):
所以我有一个“设备”,我想要一个 UserControl 来显示状态和操作。从上到下:

  • 我有一个 IDeviceModel,它有一个字段 bool IsConnected {get;} (以及状态变化的适当通知)
  • 我有一个实现 IDeviceModel 的 FakeDeviceModel,因此我可以不依赖真实设备进行设计和测试
  • 一个 DeviceViewModel,它包含一个 IDeviceModel,并封装了模型的属性。 (是的,它有适当的 INotifyPropertyChanged 通知)
  • 我的 UserControl 将有一个 DeviceViewModel 类型的 DataContext,并且有一个自定义样式的 CheckBox,它是 IsChecked={Binding IsConnected, Mode=OneWay
  • 我的目标:我想在设计时预览模型的 IsConnected 状态如何影响我的 UserControl(因此它可能会影响其他东西,而不仅仅是 IsChecked)

  • 框架:
  • 我使用 MVVM Light ViewModelLocator 的想法,返回非静态字段(因此是 ViewModel 的新实例)。在运行时,真正的数据上下文将由实例化此 UserControl 的人提供
  • d:DataContext="{Binding DeviceViewModelDesignTime, Source={StaticResource ViewModelLocator}}"
     public class ViewModelLocator
    {
    private static MainWindowViewModel _mainWindowViewModel;
    public MainWindowViewModel MainWindowViewModelMainInstance
    {
    get
    {
    if (_mainWindowViewModel == null)
    {
    _mainWindowViewModel = new MainWindowViewModel();
    }
    return _mainWindowViewModel;
    }
    }

    public DeviceViewModel DeviceViewModelDesignTime
    {
    get
    {
    //Custom initialization of the dependencies here
    //Could be to create a FakeDeviceModel and assign to constructor
    var deviceViewModel = new DeviceViewModel();

    //Custom setup of the ViewModel possible here
    //Could be: deviceViewModel.Model = new FakeDeviceModel();

    return deviceViewModel;
    }
    }

    我试过的解决方案:

    编译时解决方案

    只需在 ViewModelLocator 中对 ViewModel 的设置进行编码。
    var deviceViewModel = new DeviceViewModel(fakeDeviceModel);
    var fakeDeviceModel = new FakeDeviceModel();
    fakeDeviceModel.IsConnected = true;
    deviceViewModel.AddDevice(fakeDeviceModel);

    优点:简单

    缺点:总是要更改代码中的值、重新编译、返回设计器 View 、等待结果的迭代时间更长

    在资源中实例化并在 ViewModelLocator 中保持静态

    因此,我在 XAML 中创建了一个实例,并尝试将其推送到设计器使用的当前 ViewModel 中。不是最干净的方式,但在简单的情况下工作了一段时间(是的,该系列有些奇怪,但我的想法是我可以拥有多个设备和一个当前设备)

    XAML:
    <UserControl x:Class="Views.StepExecuteView"
    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"
    mc:Ignorable="d"
    d:DataContext="{Binding DeviceViewModelDesignTime, Source={StaticResource ViewModelLocator}}">
    <UserControl.Resources>
    <viewModels:DesignTimeDeviceManager x:Key="DesignTimeDeviceManager">
    <viewModels:DesignTimeDeviceManager.DesignTimeDevices>
    <device:FakeDeviceModel IsConnected="True"
    IsBusy="False"
    IsTrayOpen="True"
    NumberOfChipSlots="4"
    />
    </viewModels:DesignTimeDeviceManager.DesignTimeDevices>

    [... CheckBox binding to datacontext and so on...]

    和 ViewModelLocator.cs:
     public class ViewModelLocator
    {
    private static MainWindowViewModel _mainWindowViewModel;
    public MainWindowViewModel MainWindowViewModelMainInstance
    {
    get
    {
    if (_mainWindowViewModel == null)
    {
    _mainWindowViewModel = new MainWindowViewModel();
    }
    return _mainWindowViewModel;
    }
    }

    public static FakeDeviceModel DeviceModelToAddInDesignTime;
    public DeviceViewModel DeviceViewModelDesignTime
    {
    get
    {
    var deviceViewModel = new DeviceViewModel();
    if (DeviceModelToAddInDesignTime != null)
    deviceViewModel.AddDevice(DeviceModelToAddInDesignTime );

    return deviceViewModel;
    }
    }
    }

    public class DesignTimeDeviceManager
    {
    private ObservableCollection<FakeDeviceModel> _DesignTimeDevices;
    public ObservableCollection<FakeDeviceModel> DesignTimeDevices
    {
    get { return _DesignTimeDevices; }
    set
    {
    if (_DesignTimeDevices != value)
    {
    _DesignTimeDevices = value;
    ViewModelLocator.DeviceModelToAddInDesignTime = value.FirstOrDefault();
    }
    }
    }
    }

    优点:
  • 在一个项目上工作得非常好。我在 XAML 中拥有的实例,我可以修改 bool 值,我会立即获得关于它如何影响我的 UserControl 的反馈。所以在简单的情况下,CheckBox 的“Checked”状态会改变,我可以实时修改我的样式,而无需重新编译

  • 缺点:

    它停止在另一个项目中工作,这本身我找不到原因。但是在重新编译和更改内容后,设计师会给我一些异常,例如“无法将“FakeDeviceModel”转换为“FakeDeviceModel””!!我的猜测是设计器在内部编译并使用这些类型的缓存(C:\Users\firstname.lastname\AppData\Local\Microsoft\VisualStudio\12.0\Designer\ShadowCache)。在我的解决方案中,根据事物的顺序,我正在创建一个分配给静态实例的“FakeDeviceModel”,并且“稍后”,下次将要求 ViewModelLocator 提供一个 ViewModel 时,它会使用那个实例。但是,如果同时他“重新编译”或使用不同的缓存,那么它就不是“完全”相同的类型。所以我不得不杀死设计器(XDescProc)并重新编译它才能工作,然后几分钟后再次失败。如果有人可以纠正我,那就太好了。

    d:DataContext 和自定义转换器的多重绑定(bind)

    上一个解决方案的问题是,我指出 ViewModel 和 FakeDeviceModel 是在不同时间创建的(给出类型/转换问题),为了解决它,我需要同时创建它们

    XAML:
    <UserControl x:Class="MeltingControl.Views.DeviceTabView"
    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"
    mc:Ignorable="d">
    <d:UserControl.DataContext>
    <MultiBinding Converter="{StaticResource DeviceDataContextConverter}">
    <Binding Path="DeviceViewModelDesignTime" Source="{StaticResource ViewModelLocator}" />
    <Binding>
    <Binding.Source>
    <device:FakeDeviceModel IsConnected="False"
    IsBusy="False"
    IsTrayOpen="False"
    SerialNumber="DesignTimeSerie"
    />
    </Binding.Source>
    </Binding>
    </MultiBinding>
    </d:UserControl.DataContext>

    public class DeviceDataContextConverter: IMultiValueConverter
    {
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
    if (values == null || values.Length == 0)
    return null;

    var vm = (DeviceViewModel)values[0];
    if (values.Length >= 2)
    {
    var device = (IDeviceModel)values[1];
    vm.AddDevice(device);
    }

    return vm;
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
    {
    throw new NotImplementedException();
    }
    }

    优点:
    - 作品 super 好!当 DataContext 的绑定(bind)请求 ViewModel 时,我利用 Converter 修改该 ViewModel 并在返回之前注入(inject)我的设备

    缺点:

    我们失去了智能感知(使用 ReSharper),因为他不知道转换器返回的是什么类型

    我可以做出任何其他想法或修改来解决这个问题吗?

    最佳答案

    您可以创建一个返回 IsConnected = true 的设计时 ViewModel。基于您的 View 模式( FakeDeviceViewModel ),然后将其设置为设计时数据上下文:

    d:DataContext="{d:DesignInstance viewModels:FakeDeviceViewModel, 
    IsDesignTimeCreatable=True}"

    哪里 viewModels:是实际 View 模型的 xaml 命名空间。

    关于wpf - ViewModel 的设计时设置,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26058308/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com