Jakie podejścia są dostępne dla fikcyjnych danych czasu projektowania w WPF?

97

Pracuję bez mieszania wyrażeń i po prostu używam edytora XAML w vs2010. Pomijając tę ​​mądrość, coraz częściej dostrzegam potrzebę wiązania danych w czasie projektowania. W prostych przypadkach FallbackValuewłaściwość działa bardzo dobrze (pola tekstowe i bloki tekstowe itp.). Ale zwłaszcza w przypadku ItemsControli tym podobnych, naprawdę potrzebne są przykładowe dane, które są widoczne w projektancie, aby można było dostosowywać i dostosowywać kontrolki i szablony danych bez konieczności uruchamiania pliku wykonywalnego.

Wiem, że ObjectDataProviderpozwala to na powiązanie z typem, a tym samym może dostarczyć dane czasu projektowania do wizualizacji, ale jest trochę żonglowania, aby umożliwić powiązanie rzeczywistych danych w czasie wykonywania bez marnowania zasobów poprzez ładowanie zarówno czasu projektowania, dane dummied i powiązania środowiska uruchomieniowego.

Naprawdę potrzebuję możliwości, aby, powiedzmy, „Jan”, „Paul”, „George” i „Ringo” pojawiały się w projektancie XAML jako elementy do stylizacji w moim ItemsControl, ale rzeczywiste dane pokazują się, gdy aplikacja biegnie.

Wiem również, że Blend pozwala na pewne wymyślne atrybuty, które definiują dane związane z czasem projektowania, które są skutecznie ignorowane przez WPF w warunkach wykonywania.

Więc moje pytania to:

1. W jaki sposób mogę wykorzystać wiązania czasu projektowania kolekcji i nietrywialnych danych w projektancie XAML programu Visual Studio, a następnie płynnie zamienić się na powiązania środowiska uruchomieniowego?

2. Jak inni rozwiązali ten problem z danymi w czasie projektowania i wykonywania? W moim przypadku nie mogę łatwo użyć tych samych danych do obu (jak można by to zrobić, powiedzmy, zapytaniem do bazy danych).

3. Czy ich alternatywy dla mieszanki wyrażeń, których mógłbym użyć do projektowania XAML ze zintegrowanymi danymi? (Wiem, że istnieją alternatywy, ale konkretnie chcę czegoś, czego mogę użyć i zobaczyć powiązane przykładowe dane itp.)

el2iot2
źródło

Odpowiedzi:

120

Korzystając z VS2010, możesz używać atrybutów czasu projektowania (działa zarówno dla SL, jak i WPF). I tak zwykle mam pozorowane źródło danych, więc to tylko kwestia:

  • Dodanie deklaracji przestrzeni nazw

    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
  • Dodawanie pozorowanego kontekstu danych do zasobów okien / kontroli

    <UserControl.Resources>
      <ViewModels:MockXViewModel x:Key="DesignViewModel"/>
    </UserControl.Resources>
  • Ustalanie kontekstu danych w czasie projektowania

    <Grid d:DataContext="{Binding Source={StaticResource DesignViewModel}}" ...

Działa wystarczająco dobrze.

Goran
źródło
2
Jeśli masz problemy z używaniem d:DataContext, możesz znaleźć pomoc w tym pytaniu: stackoverflow.com/questions/8303803/ ...
Martin Liversage
27
Czy ten przykład nie spowodowałby załadowania wystąpienia MockXViewModel do zasobów w celu kompilacji wydania? Czy to nie jest problem?
jpierson,
12
Do Twojej wiadomości: Potrzebujesz również następujących elementów, w przeciwnym razie kompilator VS2012 nie skompiluje pliku xaml: xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"imc:Ignorable="d"
Orion Edwards,
51
jpierson ma rację. Wolę używać <Grid d:DataContext="{d:DesignInstance Type=ViewModels:MockXViewModel, IsDesignTimeCreatable=True}" .... W ten sposób symulowany model widoku zostanie utworzony tylko w projektancie, a nie podczas uruchamiania aplikacji. Pamiętaj, że to podejście wymaga, aby model widoku próbnego miał konstruktora bez parametrów. Ale tak samo jest w przykładzie podanym powyżej w odpowiedzi.
René,
2
@ René Twoje podejście jest znacznie lepsze. Dodaj to jako odpowiedź, a ja zagłosuję na to
dss539,
15

Jako połączenie zaakceptowanej odpowiedzi Gorana i doskonałego komentarza Rene.

  • Dodaj deklarację przestrzeni nazw. xmlns:d="http://schemas.microsoft.com/expression/blend/2008"

  • Odwołaj się do kontekstu danych czasu projektowania z kodu.
    <Grid d:DataContext="{d:DesignInstance Type=ViewModels:MockXViewModel, IsDesignTimeCreatable=True}" ...

John Stritenberger
źródło
1
Kusi mnie, aby oznaczyć to jako nową odpowiedź, ale być może uda nam się wyciągnąć pozostałe szczegóły.
el2iot2
To wymaga większej widoczności lub należy je wciągnąć w zaakceptowaną odpowiedź. To znacznie lepsze rozwiązanie.
Lauraducky
Dlaczego tak jest lepiej? Początkowo myślałem, że zaakceptowana odpowiedź niepotrzebnie wytworzy modele symulacyjne również w czasie wykonywania, ale przetestowałem to i w rzeczywistości nie. Zasoby nie są tworzone, jeśli nie są używane.
Paweł
@Paul To naprawdę kwestia preferencji, ale ta odpowiedź utrzymuje cały kontekst danych czasu projektowania w jednej deklaracji, a nie w dwóch miejscach. Ułatwia zmiany
John Stritenberger
1
@JohnStritenberger To nie tylko preferencja, zaakceptowana odpowiedź niepotrzebnie ładuje zasoby do pamięci przez cały czas, nie tylko dla projektanta.
UuDdLrLrSs
4

Karl Shifflett opisuje podejście, które powinno działać równie dobrze w przypadku VS2008 i VS2010:

Wyświetlanie danych czasu projektowania w programie Visual Studio 2008 Cider Designer w projektach WPF i Silverlight

Laurent Bugnion ma podobne podejście, które koncentruje się na mieszaniu wyrażeń. To może działać dla VS2010, ale jeszcze tego nie potwierdziłem.

Symulowanie danych w trybie projektowania w programie Microsoft Expression Blend

dthrasher
źródło
dziękuję za zwrócenie mi na to uwagi. Podoba mi się koncepcja DesignAndRunTimeDataContext.
el2iot2
1
Karl Shifflett ma zaktualizowany artykuł dotyczący programu Visual Studio 2010: Przykładowe dane w programie WPF i Silverlight Designer
totorocat
1
Istota treści linku powinna naprawdę zostać dodana do odpowiedzi, zwłaszcza że pierwszy link jest teraz martwy.
Lauraducky,
4

Może nowe funkcje czasu projektowania w programie Visual Studio 2010 i Expression Blend 4 są dla Ciebie opcją.

Sposób działania jest pokazany w przykładowej aplikacji BookLibrary platformy WPF Application Framework (WAF) . Proszę pobrać wersję .NET4.

jbe
źródło
Dzięki za link. Czy istnieje określony plik kodu lub konstrukcja, na którą powinienem się przyjrzeć, aby zobaczyć podejście? (krótki przegląd byłby świetny)
el2iot2
Przyjrzyj się projektowi BookLibrary.Presentation. W tym projekcie znajdziesz folder „DesignData”, który jest używany przez UserControls w folderze „Views”.
jbe
1
+1. Właśnie to obejrzałem. Dla wszystkich zainteresowanych przykładowy model widoku danych jest zadeklarowany w języku XAML i przywoływany za pośrednictwem d: DataContext = "{d: DesignData Source = .. / DesignData / SampleLendToViewModel.xaml}"
RichardOD
4

Używam tego podejścia do generowania danych czasu projektowania w .NET 4.5 i Visual Studio 2013.

Mam tylko jeden ViewModel. Model widoku ma właściwość, IsInDesignModektóra mówi, czy tryb projektowania jest aktywny, czy nie (patrz klasa ViewModelBase). Następnie możesz skonfigurować dane czasu projektowania (np. Wypełnianie kontrolki elementów) w konstruktorze modeli widoku.

Poza tym nie ładowałbym rzeczywistych danych w konstruktorze modeli widoku, może to prowadzić do problemów w czasie wykonywania, ale ustawienie danych na czas projektowania nie powinno stanowić problemu.

public abstract class ViewModelBase
{
    public bool IsInDesignMode
    {
        get
        {
            return DesignerProperties.GetIsInDesignMode(new DependencyObject());
        }
    }
}

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

    private void LoadDesignTimeData()
    {
        // Load design time data here
    }       
}
Jaskółka oknówka
źródło
4

Korzystając z programu Visual Studio 2017, starałem się postępować zgodnie ze wszystkimi przewodnikami i pytaniami, takimi jak to, i wciąż miałem do czynienia z narzędziem, <ItemsControl>które po prostu nie wykonało kodu, który miałem w konstruktorze, DesignFooViewModelktóry dziedziczy FooViewModel. Potwierdziłem, że część „nie wykonała” po tym „poręcznym” przewodniku MSDN (spoiler: MessageBoxdebugowanie). Chociaż nie jest to bezpośrednio związane z pierwotnym pytaniem, mam nadzieję, że zaoszczędzi to innym dużo czasu.

Okazuje się, że nie robiłem nic złego. Problem polegał na tym, że moja aplikacja musi być zbudowana na x64. Ponieważ program Visual Studio jest nadal w 2018 roku procesem 32-bitowym i najwyraźniej nie może obrócić 64-bitowego procesu hosta dla części projektanta, nie może używać moich klas x64. Naprawdę złe jest to, że nie ma błędów, które można znaleźć w żadnym dzienniku, który przychodzi mi do głowy.

Więc jeśli natkniesz się na to pytanie, ponieważ widzisz fałszywe dane w swoim modelu widoku czasu projektowania (na przykład: <TextBlock Text="{Binding Name}"/>pojawia się Namebez względu na to, czy ustawisz właściwość), prawdopodobnie przyczyną jest twoja kompilacja x64. Jeśli nie możesz zmienić konfiguracji kompilacji na anycpu lub x86 z powodu zależności, rozważ utworzenie nowego projektu, który jest w pełni anycpu i nie ma zależności (ani żadnych zależności). W efekcie kończy się podzielenie większości lub wszystkich części kodu oprócz inicjalizacyjnych z projektu „WPF App” na projekt „biblioteki klas C #”.

Jeśli chodzi o podstawę kodu, nad którą pracuję, myślę, że wymusi to zdrowe oddzielenie problemów kosztem powielenia kodu, co prawdopodobnie jest pozytywną rzeczą netto.

joonas
źródło
3

Podobna do najlepiej ocenianej odpowiedzi, ale moim zdaniem lepsza: Możesz utworzyć właściwość statyczną, aby zwrócić wystąpienie danych projektowych i odwołać się do niej bezpośrednio z XAML, tak jak poniżej:

<d:UserControl.DataContext>
    <Binding Source="{x:Static designTimeNamespace:DesignTimeViewModels.MyViewModel}" />
</d:UserControl.DataContext>

Pozwala to uniknąć konieczności używania UserControl.Resources. Twoja statyczna właściwość może funkcjonować jako fabryka, umożliwiając konstruowanie nietrywialnych typów danych - na przykład jeśli nie masz domyślnego ctora, możesz tutaj wywołać fabrykę lub kontener, aby wstrzyknąć je w odpowiednich zależnościach.

Jack Ukleja
źródło