2014-09-26 7 views
12

का डिज़ाइन-टाइम सेटअप मैं WPF में अपना उपयोगकर्ता नियंत्रण बनाने के लिए विजुअल स्टूडियो 2013 के डिजाइनर का उपयोग कर रहा हूं, और मैं एक एमवीवीएम दृष्टिकोण का उपयोग कर रहा हूं।व्यूमोडेल

मैं अपने व्यूमोडेल के "डिज़ाइन-टाइम" सेटअप का सबसे अच्छा तरीका खोजने का प्रयास कर रहा हूं ताकि मैं तुरंत संपत्ति के मूल्य को बदलने के डिजाइनर में प्रभाव को देख सकूं। मैंने इसका समर्थन करने के लिए विभिन्न डिज़ाइन और तकनीकों का उपयोग किया है, लेकिन कुछ भी नहीं है जो मैं चाहता हूं। मैं सोच रहा हूं कि किसी के पास बेहतर विचार हैं ...

स्थिति (सरलीकृत): तो मेरे पास एक "डिवाइस" है जिसे मैं उपयोगकर्ता नियंत्रण को राज्य और संचालन दिखाने के लिए चाहता हूं। ऊपर से नीचे तक:

  • मैं एक IDeviceModel जो एक क्षेत्र bool IsConnected {get;} (और राज्य में परिवर्तन की उचित अधिसूचना)
  • मैं एक FakeDeviceModel जो IDeviceModel लागू करता है है है, और इस तरह मुझे सक्षम बनाता है एक असली डिवाइस पर भरोसा नहीं करने के लिए डिजाइन-समय और परीक्षण के लिए
  • एक डिवाइस व्यूमोडेल, जिसमें IDeviceModel है, और मॉडल के गुणों को समाहित करता है। (हाँ उसमें उचित INotifyPropertyChanged सूचनाएं है)
  • मेरे UserControl किस प्रकार DeviceViewModel की एक DataContext होगा, और जो है IsChecked={Binding IsConnected, Mode=OneWay
  • मेरे लक्ष्य एक कस्टम स्टाइल चेकबॉक्स हैं: मैं डिजाइन समय कैसे करता है पर पूर्वावलोकन करना चाहते मॉडल के IsConnected राज्य मेरी UserControl को प्रभावित (तो यह सिर्फ IsChecked के अलावा अन्य चीजों को प्रभावित कर सकता)

फ्रेमवर्क:

  • मैं MVVM लाइट ViewModelLocator के विचार का उपयोग करें, गैर स्थिर फ़ील्ड (ताकि नई मैं ViewModels के nstances)।

    संकलन समय समाधान

    सीधे शब्दों में कोड डाल दें: रनटाइम पर, वास्तविक DataContext एक instanciating इस 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); 

पेशेवरों: सरल

विपक्ष: यह हमेशा की तरह, कोड में मान बदलने के लिए पुनः संकलित, डिजाइनर दृश्य पर लौटने के, संसाधनों में परिणाम के लिए प्रतीक्षा

उदाहरण और रखा जा रहा की लंबी पुनरावृत्तियों है ViewModelLocator

इसलिए मैं एक्सएएमएल में एक उदाहरण बनाता हूं और मैं इसे डिजाइनर द्वारा उपयोग किए गए वर्तमान व्यू मॉडेल में धक्का देने की कोशिश करता हूं।नहीं स्पष्ट तरीका है, लेकिन सरल स्थिति में थोड़ी देर के लिए काम किया है (हाँ, संग्रह के साथ कुछ 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(); 
      } 
     } 
    } 
} 

सकारात्मक:

  • एक प्रोजे पर सुपर महान काम किया टी। एक्सएएमएल में जो उदाहरण था, मैं बूलियन को संशोधित कर सकता था और मुझे -मेडिएट-फीडबैक मिलेगा कि यह मेरे UserControl को कैसे प्रभावित करता है। तो साधारण स्थिति में, चेकबॉक्स का "चेक किए गए" राज्य बदल जाएगा और मैं

विपक्ष पुन: संयोजित करने के लिए जरूरत के बिना वास्तविक समय में मेरी स्टाइल को संशोधित कर सकता है,:

यह एक अन्य परियोजना में काम करना बंद कर, और इस अपने आप से कारण मुझे नहीं मिला। लेकिन सामान को बदलने और बदलने के बाद, डिजाइनर मुझे "FakeDeviceModel" को "FakeDeviceModel" नहीं डाला जा सकता है जैसे "अपवाद" मेरा अनुमान है कि डिजाइनर आंतरिक रूप से उन प्रकारों के लिए कैश का संकलन और उपयोग करता है (सी: \ उपयोगकर्ता \ firstname.lastname \ AppData \ Local \ Microsoft \ VisualStudio \ 12.0 \ Designer \ ShadowCache)। और यह कि मेरे समाधान में, चीजों के क्रम के आधार पर, मैं "FakeDeviceModel" बना रहा था जिसे एक स्थिर उदाहरणों और "बाद में" को सौंपा गया था, अगली बार ViewModelLocator को व्यूमोडेल के लिए कहा जाएगा, यह उस का उपयोग करेगा उदाहरण। हालांकि, अगर इस दौरान वह "recompiles" या एक अलग कैश का उपयोग करता है, तो यह एक ही प्रकार "बिल्कुल" नहीं है। तो मुझे डिजाइनर (XDescProc) को मारना पड़ा और इसके लिए काम करने के लिए पुन: संकलित करना पड़ा, और उसके बाद कुछ मिनट बाद फिर से विफल हो गया। अगर कोई मुझे इस पर सही कर सकता है तो यह बहुत अच्छा होगा।

बहु बाइंडिंग घ के लिए: DataContext और कस्टम कनवर्टर

पिछले समाधान की समस्या मुझे तथ्य यह है कि 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(); 
    } 
} 

सकारात्मक: -Works सुपर अच्छा! DataContext के लिए बाध्यकारी पूछता है ViewModel के लिए, मैं कनवर्टर का लाभ लेने कि ViewModel को संशोधित करने और यह लौटने

विपक्ष से पहले अपने डिवाइस सुई:

हम (ReSharper के साथ) intelissense खो देते हैं, क्योंकि वह नहीं करता है ' टी कनवर्टर

द्वारा इस प्रकार को हल करने के लिए कोई अन्य विचार या संशोधन मैं कर सकता हूं?

+0

आप मिश्रण में इस की कोशिश की है ले? विजुअल स्टूडियो 2010 के साथ, विजुअल स्टूडियो की तुलना में ब्लेंड में इस पैटर्न के साथ काम करना आसान था क्योंकि डिजाइनर अधिक मजबूत था। मुझे यकीन नहीं है कि कैसे मिश्रण VS2013 से तुलना करता है। –

+0

आप इसे मिश्रण में कैसे प्रबंधित कर रहे थे? – FrankyB

+0

वीएस और ब्लेंड अब एक ही डिजाइनर को साझा करते हैं, हालांकि किसी भी माध्यम से सभी समान कार्यक्षमता नहीं। हालांकि वीएस अब साइडर डिजाइनर का उपयोग नहीं करता है, फिर भी आप अब भी वीएस में मिश्रण में क्या कर सकते हैं/कर सकते हैं। –

उत्तर

4

आप एक डिजाइन समय ViewModel कि IsConnected = सच (FakeDeviceViewModel) रिटर्न बना सकते हैं और एक डिजाइन समय डेटा संदर्भ के रूप में सेट कर सकते हैं:

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

मैं बिल्कुल प्रलेखित किया है कि कैसे मैं सही सेटअप पाने में कामयाब रहे विजुअल स्टूडियो में लाइव डिज़ाइन टाइम डेटा देखने के लिए।

इस पृष्ठ पर Hint 9 - Design Time DataContext पर

देखो:

ReSharper WPF error: "Cannot resolve symbol "MyVariable" due to unknown DataContext"

0
  1. मैं जैसे एक अलग XAML में नकली देखें मॉडल का एक उदाहरण बन जाएगा DeviceViewModelDataSample.xaml (नीचे उदाहरण देखें)

  2. सेट बिल्ड कार्रवाई DesignData संदर्भ के लिए

  3. ऐसे

    <UserControl x:Class="YourNameSpace.YourControl" 
           xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
           mc:Ignorable="d" 
           d:DataContext="{d:DesignData Source=/DataSample/DeviceViewModelDataSample.xaml}"> 
    <!-- Skiped details for brevity --> 
    </UserControl> 
    

के रूप में फ़ाइल DeviceViewModelDataSample.xaml

<vm:DeviceViewModel xmlns:dm="clr-namespace:YourNameSpace.DataModel" 
       xmlns:vm="clr-namespace:YourNameSpace.ViewModel"> 
    <vm:DeviceViewModel.DeviceManager> <!-- Assuming this is a collection --> 
     <dm:DeviceModel DeviceName="Fake Device" IsConnected ="true" /> <!-- This creates an instance at design time --> 
    </vm:DeviceViewModel.DeviceManager>  
</vm:DeviceViewModel> 
0

मैं एक वैकल्पिक समाधान का प्रस्ताव देना चाहता हूं।

आप डिज़ाइन समय डेटा और सामान्य रनटाइम के लिए उसी व्यू मॉडल का उपयोग कर सकते हैं, और अपने (सिंगल) व्यूमोडेल में जांच सकते हैं कि डिज़ाइनर सक्रिय है या फिर डिज़ाइन समय डेटा लोड करें।

आपके विचार मॉडल में आप कुछ इस तरह करना होगा:

public class ExampleViewModel : ViewModelBase 
{ 
    public ExampleViewModel() 
    { 
     if (IsInDesignMode == true) 
     { 
      LoadDesignTimeData(); 
     } 
    } 

    private void LoadDesignTimeData() 
    { 
     // Load design time data here 
    }  
} 

IsInDesignMode संपत्ति आपके विचार मॉडल आधार वर्ग में रखा जा सकता है - अगर आपके पास है - इस तरह और दिखता है:

DesignerProperties.GetIsInDesignMode(new DependencyObject()); 

कृपया मेरा उत्तर पर एक नज़र here

संबंधित मुद्दे