我使用Visual Studio 2013的設計器在WPF中創建我的用戶控件,並使用MVVM方法。ViewModel的設計時設置
我試圖找到最佳方法來讓我的viewmodel具有「設計時」設置,以便我立即在設計器中看到更改屬性值的效果。我用不同的設計和技術來支持這個,但沒有什麼是我想要的。我想知道如果有人有更好的想法...
情況(簡體): 所以我有一個「設備」,我想要一個UserControl顯示狀態和操作。從上至下:
- 我其中有一個領域
bool IsConnected {get;}
(和狀態的變化適當通知) - 我有一個FakeDeviceModel它實現IDeviceModel一個IDeviceModel,從而使我能夠不依賴於實際設備上用於設計時和測試
- DeviceViewModel,它包含一個IDeviceModel並封裝模型的屬性。 (是的,它有它正確的INotifyPropertyChanged的通知)
- 我的用戶,將有型DeviceViewModel的一個DataContext,並且將有一個自定義風格的複選框是
IsChecked={Binding IsConnected, Mode=OneWay
- 我的目標:我要預覽設計時如何做該型號的IsConnected狀態會影響我的用戶(所以它可能會影響其他的東西不僅僅是器isChecked)
框架:
- 我使用MVVM光ViewModelLocator的想法,返回非靜態字段(所以新一世ViewModels的物質)。
編譯時的解決方案
簡單地編寫代碼:在運行時,真正的datacontext將由一個instanciating這個用戶控件
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);
優點:簡單
缺點:這是始終不會改變的值代碼,重新編譯,回去的設計師認爲,等待結果的資源
實例,並保持較長的迭代靜態ViewModelLocator
因此,我在XAML中創建一個實例,並嘗試在設計器使用的當前ViewModel中推送它。不乾淨的方法,但工作了簡單的情況,而(是有一些wierdness與收藏,但與我可以有多個設備和當前的想法)
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中的實例,我可以修改布爾值,並且我會得到-immediate-反饋它如何影響我的UserControl。所以在簡單的情況下,CheckBox的「經過」狀態會改變,我可以改變我的實時造型,而無需重新編譯
缺點:
它停在另外一個項目工作,而這本身我找不到原因。但重新編譯和更改東西后,設計師會給我看起來像「不能將FakeDeviceModel」轉換爲「FakeDeviceModel」的異常!我的猜測是Designer在內部爲這些類型編譯和使用緩存(C:\ Users \ firstname.lastname \ AppData \ Local \ Microsoft \ VisualStudio \ 12.0 \ Designer \ ShadowCache)。在我的解決方案中,根據事物的順序,我創建了一個分配給靜態實例的「FakeDeviceModel」,並且在「稍後」,下一次ViewModelLocator被要求提供ViewModel時,它會使用實例。但是,如果在此期間他「重新編譯」或使用不同的緩存,那麼它不是「完全」相同的類型。所以我必須殺死設計器(XDescProc)並重新編譯才能正常工作,然後在幾分鐘後再次失敗。如果有人能糾正我,這將是偉大的。
多綁定爲d:DataContext的和自定義轉換器
以前的解決方案的問題是指向我的視圖模型和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();
}
}
優點: -Works超好聽!當在DataContext綁定請求視圖模型,我趁轉換器來修改視圖模型並將其返回
缺點之前注入我的設備:
我們intelissense失去(與ReSharper的),因爲他不」 t知道轉換器返回的是什麼類型
我能解決這個問題的其他想法或修改?
你在Blend試過這個嗎?使用Visual Studio 2010,在Blend中處理這種模式比使用Visual Studio更容易,因爲設計器更健壯。我不確定Blend如何與VS2013進行比較。 – 2014-09-30 19:15:05
你是如何處理Blend的? – FrankyB 2014-10-01 08:23:00
VS和Blend現在共享同一個設計器,儘管不是所有相同的功能都是。儘管VS不再使用蘋果酒設計師,但你現在仍然可以在VS中融入很多東西。 – 2014-10-07 20:00:53