Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
V tomto tématu se dozvíte, jak vytvořit vazbu ovládacího prvku (nebo jiného prvku uživatelského rozhraní) na jednu položku nebo vytvořit vazbu ovládacího prvku na kolekci položek v aplikaci pro Univerzální platformu Windows (UPW). Kromě toho si ukážeme, jak řídit vykreslování položek, implementovat zobrazení podrobností na základě výběru a převést data pro zobrazení. Podrobnější informace najdete v části Podrobnosti o datových vazbách.
Požadavky
V tomto tématu se předpokládá, že víte, jak vytvořit základní aplikaci pro UPW. Pokyny k vytvoření první aplikace pro UPW najdete v tématu Začínáme s aplikacemi pro Windows.
Vytvoření projektu
Vytvořte nový prázdný projekt aplikace (Windows Universal). Pojmenujte ho "Rychlý start".
Vazba na jednu položku
Každá vazba se skládá z cíle vazby a zdroje vazby. Cíl je obvykle vlastnost ovládacího prvku nebo jiného prvku uživatelského rozhraní a zdrojem je vlastnost instance třídy (datový model nebo model zobrazení). Tento příklad ukazuje, jak vytvořit vazbu ovládacího prvku na jednu položku. Cílem je vlastnost TextTextBlock. Zdrojem je instance jednoduché třídy s názvem Recording , která představuje záznam zvuku. Podívejme se nejprve na třídu.
Pokud používáte C# nebo C++/CX, přidejte do projektu novou třídu a pojmenujte záznam třídy.
Pokud používáte C++/WinRT, přidejte do projektu nové položky midl File (.idl), které jsou uvedené v příkladu kódu C++/WinRT níže. Nahraďte obsah těchto nových souborů kódem MIDL 3.0 zobrazeným ve výpisu, sestavte projekt pro vygenerování Recording.h a .cppRecordingViewModel.h a .cppa pak přidejte kód do vygenerovaných souborů tak, aby odpovídal výpisu. Další informace o vygenerovaných souborech a o tom, jak je zkopírovat do projektu, najdete v tématu ovládací prvky XAML; přiřazení k vlastnosti C++/WinRT.
namespace Quickstart
{
public class Recording
{
public string ArtistName { get; set; }
public string CompositionName { get; set; }
public DateTime ReleaseDateTime { get; set; }
public Recording()
{
this.ArtistName = "Wolfgang Amadeus Mozart";
this.CompositionName = "Andante in C for Piano";
this.ReleaseDateTime = new DateTime(1761, 1, 1);
}
public string OneLineSummary
{
get
{
return $"{this.CompositionName} by {this.ArtistName}, released: "
+ this.ReleaseDateTime.ToString("d");
}
}
}
public class RecordingViewModel
{
private Recording defaultRecording = new Recording();
public Recording DefaultRecording { get { return this.defaultRecording; } }
}
}
// Recording.idl
namespace Quickstart
{
runtimeclass Recording
{
Recording(String artistName, String compositionName, Windows.Globalization.Calendar releaseDateTime);
String ArtistName{ get; };
String CompositionName{ get; };
Windows.Globalization.Calendar ReleaseDateTime{ get; };
String OneLineSummary{ get; };
}
}
// RecordingViewModel.idl
import "Recording.idl";
namespace Quickstart
{
runtimeclass RecordingViewModel
{
RecordingViewModel();
Quickstart.Recording DefaultRecording{ get; };
}
}
// Recording.h
// Add these fields:
...
#include <sstream>
...
private:
std::wstring m_artistName;
std::wstring m_compositionName;
Windows::Globalization::Calendar m_releaseDateTime;
...
// Recording.cpp
// Implement like this:
...
Recording::Recording(hstring const& artistName, hstring const& compositionName, Windows::Globalization::Calendar const& releaseDateTime) :
m_artistName{ artistName.c_str() },
m_compositionName{ compositionName.c_str() },
m_releaseDateTime{ releaseDateTime } {}
hstring Recording::ArtistName(){ return hstring{ m_artistName }; }
hstring Recording::CompositionName(){ return hstring{ m_compositionName }; }
Windows::Globalization::Calendar Recording::ReleaseDateTime(){ return m_releaseDateTime; }
hstring Recording::OneLineSummary()
{
std::wstringstream wstringstream;
wstringstream << m_compositionName.c_str();
wstringstream << L" by " << m_artistName.c_str();
wstringstream << L", released: " << m_releaseDateTime.MonthAsNumericString().c_str();
wstringstream << L"/" << m_releaseDateTime.DayAsString().c_str();
wstringstream << L"/" << m_releaseDateTime.YearAsString().c_str();
return hstring{ wstringstream.str().c_str() };
}
...
// RecordingViewModel.h
// Add this field:
...
#include "Recording.h"
...
private:
Quickstart::Recording m_defaultRecording{ nullptr };
...
// RecordingViewModel.cpp
// Implement like this:
...
Quickstart::Recording RecordingViewModel::DefaultRecording()
{
Windows::Globalization::Calendar releaseDateTime;
releaseDateTime.Year(1761);
releaseDateTime.Month(1);
releaseDateTime.Day(1);
m_defaultRecording = winrt::make<Recording>(L"Wolfgang Amadeus Mozart", L"Andante in C for Piano", releaseDateTime);
return m_defaultRecording;
}
...
// Recording.h
#include <sstream>
namespace Quickstart
{
public ref class Recording sealed
{
private:
Platform::String^ artistName;
Platform::String^ compositionName;
Windows::Globalization::Calendar^ releaseDateTime;
public:
Recording(Platform::String^ artistName, Platform::String^ compositionName,
Windows::Globalization::Calendar^ releaseDateTime) :
artistName{ artistName },
compositionName{ compositionName },
releaseDateTime{ releaseDateTime } {}
property Platform::String^ ArtistName
{
Platform::String^ get() { return this->artistName; }
}
property Platform::String^ CompositionName
{
Platform::String^ get() { return this->compositionName; }
}
property Windows::Globalization::Calendar^ ReleaseDateTime
{
Windows::Globalization::Calendar^ get() { return this->releaseDateTime; }
}
property Platform::String^ OneLineSummary
{
Platform::String^ get()
{
std::wstringstream wstringstream;
wstringstream << this->CompositionName->Data();
wstringstream << L" by " << this->ArtistName->Data();
wstringstream << L", released: " << this->ReleaseDateTime->MonthAsNumericString()->Data();
wstringstream << L"/" << this->ReleaseDateTime->DayAsString()->Data();
wstringstream << L"/" << this->ReleaseDateTime->YearAsString()->Data();
return ref new Platform::String(wstringstream.str().c_str());
}
}
};
public ref class RecordingViewModel sealed
{
private:
Recording ^ defaultRecording;
public:
RecordingViewModel()
{
Windows::Globalization::Calendar^ releaseDateTime = ref new Windows::Globalization::Calendar();
releaseDateTime->Year = 1761;
releaseDateTime->Month = 1;
releaseDateTime->Day = 1;
this->defaultRecording = ref new Recording{ L"Wolfgang Amadeus Mozart", L"Andante in C for Piano", releaseDateTime };
}
property Recording^ DefaultRecording
{
Recording^ get() { return this->defaultRecording; };
}
};
}
// Recording.cpp
#include "pch.h"
#include "Recording.h"
Dále zpřístupněte zdrojovou třídu vazby z třídy, která představuje vaši stránku značkovacího jazyka. Děláme to přidáním vlastnosti typu RecordingViewModel do MainPage.
Pokud používáte C++/WinRT, nejprve aktualizujte MainPage.idl. Sestavte projekt, který znovu vygeneruje MainPage.h a .cppsloučí změny v těchto vygenerovaných souborech do souborů v projektu.
namespace Quickstart
{
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
this.ViewModel = new RecordingViewModel();
}
public RecordingViewModel ViewModel{ get; set; }
}
}
// MainPage.idl
// Add this property:
import "RecordingViewModel.idl";
...
RecordingViewModel ViewModel{ get; };
...
// MainPage.h
// Add this property and this field:
...
#include "RecordingViewModel.h"
...
Quickstart::RecordingViewModel ViewModel();
private:
Quickstart::RecordingViewModel m_viewModel{ nullptr };
...
// MainPage.cpp
// Implement like this:
...
MainPage::MainPage()
{
InitializeComponent();
m_viewModel = winrt::make<RecordingViewModel>();
}
Quickstart::RecordingViewModel MainPage::ViewModel()
{
return m_viewModel;
}
...
// MainPage.h
...
#include "Recording.h"
namespace Quickstart
{
public ref class MainPage sealed
{
private:
RecordingViewModel ^ viewModel;
public:
MainPage();
property RecordingViewModel^ ViewModel
{
RecordingViewModel^ get() { return this->viewModel; };
}
};
}
// MainPage.cpp
...
MainPage::MainPage()
{
InitializeComponent();
this->viewModel = ref new RecordingViewModel();
}
Poslední částí je připojit TextBlock k vlastnosti ViewModel.DefaultRecording.OneLineSummary.
<Page x:Class="Quickstart.MainPage" ... >
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<TextBlock Text="{x:Bind ViewModel.DefaultRecording.OneLineSummary}"
HorizontalAlignment="Center"
VerticalAlignment="Center"/>
</Grid>
</Page>
Pokud používáte C++/WinRT, budete muset odebrat funkci MainPage::ClickHandler , aby se projekt sestavil.
Tady je výsledek.
Vazba na kolekci položek
Běžným scénářem je navázání na kolekci obchodních objektů. V jazyce C# a Visual Basic je obecná třída ObservableCollection<T> dobrou volbou pro datovou vazbu, protože implementuje rozhraní INotifyPropertyChanged a INotifyCollectionChanged . Tato rozhraní poskytují oznámení o změnách vazbám při přidání nebo odebrání položek nebo změně vlastnosti samotného seznamu. Pokud chcete, aby se vázané ovládací prvky aktualizovaly o změny vlastností objektů v kolekci, měl by obchodní objekt také implementovat INotifyPropertyChanged. Další informace naleznete v tématu , Datové vazby podrobně,.
Pokud používáte C++/WinRT, můžete se dozvědět více o vazbě na pozorovatelnou kolekci v ovládacích prvcích položek XAML; připojte se k kolekci C++/WinRT. Pokud si toto téma přečtete jako první, bude záměr výpisu kódu C++/WinRT uvedeného níže jasnější.
Další příklad svazuje ListView s kolekcí Recording objektů. Začněme přidáním kolekce do našeho modelu zobrazení. Stačí přidat tyto nové členy do Třídy RecordingViewModel .
public class RecordingViewModel
{
...
private ObservableCollection<Recording> recordings = new ObservableCollection<Recording>();
public ObservableCollection<Recording> Recordings{ get{ return this.recordings; } }
public RecordingViewModel()
{
this.recordings.Add(new Recording(){ ArtistName = "Johann Sebastian Bach",
CompositionName = "Mass in B minor", ReleaseDateTime = new DateTime(1748, 7, 8) });
this.recordings.Add(new Recording(){ ArtistName = "Ludwig van Beethoven",
CompositionName = "Third Symphony", ReleaseDateTime = new DateTime(1805, 2, 11) });
this.recordings.Add(new Recording(){ ArtistName = "George Frideric Handel",
CompositionName = "Serse", ReleaseDateTime = new DateTime(1737, 12, 3) });
}
}
// RecordingViewModel.idl
// Add this property:
...
#include <winrt/Windows.Foundation.Collections.h>
...
Windows.Foundation.Collections.IVector<IInspectable> Recordings{ get; };
...
// RecordingViewModel.h
// Change the constructor declaration, and add this property and this field:
...
RecordingViewModel();
Windows::Foundation::Collections::IVector<Windows::Foundation::IInspectable> Recordings();
private:
Windows::Foundation::Collections::IVector<Windows::Foundation::IInspectable> m_recordings;
...
// RecordingViewModel.cpp
// Update/add implementations like this:
...
RecordingViewModel::RecordingViewModel()
{
std::vector<Windows::Foundation::IInspectable> recordings;
Windows::Globalization::Calendar releaseDateTime;
releaseDateTime.Month(7); releaseDateTime.Day(8); releaseDateTime.Year(1748);
recordings.push_back(winrt::make<Recording>(L"Johann Sebastian Bach", L"Mass in B minor", releaseDateTime));
releaseDateTime = Windows::Globalization::Calendar{};
releaseDateTime.Month(11); releaseDateTime.Day(2); releaseDateTime.Year(1805);
recordings.push_back(winrt::make<Recording>(L"Ludwig van Beethoven", L"Third Symphony", releaseDateTime));
releaseDateTime = Windows::Globalization::Calendar{};
releaseDateTime.Month(3); releaseDateTime.Day(12); releaseDateTime.Year(1737);
recordings.push_back(winrt::make<Recording>(L"George Frideric Handel", L"Serse", releaseDateTime));
m_recordings = winrt::single_threaded_observable_vector<Windows::Foundation::IInspectable>(std::move(recordings));
}
Windows::Foundation::Collections::IVector<Windows::Foundation::IInspectable> RecordingViewModel::Recordings() { return m_recordings; }
...
// Recording.h
...
public ref class RecordingViewModel sealed
{
private:
...
Windows::Foundation::Collections::IVector<Recording^>^ recordings;
public:
RecordingViewModel()
{
...
releaseDateTime = ref new Windows::Globalization::Calendar();
releaseDateTime->Year = 1748;
releaseDateTime->Month = 7;
releaseDateTime->Day = 8;
Recording^ recording = ref new Recording{ L"Johann Sebastian Bach", L"Mass in B minor", releaseDateTime };
this->Recordings->Append(recording);
releaseDateTime = ref new Windows::Globalization::Calendar();
releaseDateTime->Year = 1805;
releaseDateTime->Month = 2;
releaseDateTime->Day = 11;
recording = ref new Recording{ L"Ludwig van Beethoven", L"Third Symphony", releaseDateTime };
this->Recordings->Append(recording);
releaseDateTime = ref new Windows::Globalization::Calendar();
releaseDateTime->Year = 1737;
releaseDateTime->Month = 12;
releaseDateTime->Day = 3;
recording = ref new Recording{ L"George Frideric Handel", L"Serse", releaseDateTime };
this->Recordings->Append(recording);
}
...
property Windows::Foundation::Collections::IVector<Recording^>^ Recordings
{
Windows::Foundation::Collections::IVector<Recording^>^ get()
{
if (this->recordings == nullptr)
{
this->recordings = ref new Platform::Collections::Vector<Recording^>();
}
return this->recordings;
};
}
};
A pak vytvořte vazbu ListView na ViewModel.Recordings vlastnost.
<Page x:Class="Quickstart.MainPage" ... >
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<ListView ItemsSource="{x:Bind ViewModel.Recordings}"
HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>
</Page>
Ještě jsme nezadali šablonu dat pro třídu Recording, takže nejlepší, co může rámec uživatelského rozhraní udělat, je volání ToString pro každou položku v ListView. Výchozí implementace ToString je vrátit název typu.
Abychom to mohli napravit, můžeme buď přepsat ToString, aby vracelo hodnotu OneLineSummary, nebo můžeme poskytnout šablonu dat. Možnost šablony dat je obvyklejší řešení a flexibilnější. Šablonu dat zadáte pomocí vlastnosti ContentTemplate ovládacího prvku obsahu nebo vlastnosti ItemTemplate ovládacího prvku items. Tady jsou dva způsoby, jak můžeme navrhnout šablonu dat pro záznam společně s obrázkem výsledku.
<ListView ItemsSource="{x:Bind ViewModel.Recordings}"
HorizontalAlignment="Center" VerticalAlignment="Center">
<ListView.ItemTemplate>
<DataTemplate x:DataType="local:Recording">
<TextBlock Text="{x:Bind OneLineSummary}"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<ListView ItemsSource="{x:Bind ViewModel.Recordings}"
HorizontalAlignment="Center" VerticalAlignment="Center">
<ListView.ItemTemplate>
<DataTemplate x:DataType="local:Recording">
<StackPanel Orientation="Horizontal" Margin="6">
<SymbolIcon Symbol="Audio" Margin="0,0,12,0"/>
<StackPanel>
<TextBlock Text="{x:Bind ArtistName}" FontWeight="Bold"/>
<TextBlock Text="{x:Bind CompositionName}"/>
</StackPanel>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Další informace o syntaxi XAML naleznete v tématu Vytvoření uživatelského rozhraní pomocí xaml. Další informace o rozložení ovládacího prvku naleznete v tématu Definovat rozložení pomocí xaml.
Přidání zobrazení podrobností
V položkách ListView můžete zobrazit všechny podrobnosti o objektech záznamu . Ale to zabírá hodně místa. Místo toho můžete v položce zobrazit jenom dostatek dat, která se mají identifikovat, a když uživatel provede výběr, můžete zobrazit všechny podrobnosti o vybrané položce v samostatné části uživatelského rozhraní označované jako zobrazení podrobností. Toto uspořádání se také označuje jako zobrazení předlohy/podrobností nebo zobrazení seznamu/podrobností.
Existují dva způsoby, jak to udělat. Zobrazení podrobností můžete svázat s vlastností SelectedItem v komponentě ListView . Nebo můžete použít CollectionViewSource, v takovém případě propojíte zobrazovač ListView i zobrazení podrobností na CollectionViewSource (postará se o aktuálně vybranou položku). Obě techniky jsou uvedeny níže a oba poskytují stejné výsledky (znázorněné na obrázku).
Poznámka:
Zatím jsme v tomto tématu použili pouze značkovací rozšíření {x:Bind}
Pokud používáte C++/WinRT nebo rozšíření komponent Visual C++ (C++/CX), pak abyste použili rozšíření značek {Binding}, musíte přidat atribut BindableAttribute do jakékoli třídy běhového prostředí, se kterou chcete vytvořit vazbu. Pokud chcete použít {x:Bind}, tento atribut nepotřebujete.
Důležité
Pokud používáte C++/WinRT, je atribut BindableAttribute dostupný, pokud jste nainstalovali sadu Windows SDK verze 10.0.17763.0 (Windows 10, verze 1809) nebo novější. Bez tohoto atributu budete muset implementovat rozhraní ICustomPropertyProvider a ICustomProperty, abyste mohli používat rozšíření značek {Binding}.
Nejprve je tady technika SelectedItem.
// No code changes necessary for C#.
// Recording.idl
// Add this attribute:
...
[Windows.UI.Xaml.Data.Bindable]
runtimeclass Recording
...
[Windows::UI::Xaml::Data::Bindable]
public ref class Recording sealed
{
...
};
Jedinou další potřebnou změnou je změna označení.
<Page x:Class="Quickstart.MainPage" ... >
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
<ListView x:Name="recordingsListView" ItemsSource="{x:Bind ViewModel.Recordings}">
<ListView.ItemTemplate>
<DataTemplate x:DataType="local:Recording">
<StackPanel Orientation="Horizontal" Margin="6">
<SymbolIcon Symbol="Audio" Margin="0,0,12,0"/>
<StackPanel>
<TextBlock Text="{x:Bind CompositionName}"/>
</StackPanel>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<StackPanel DataContext="{Binding SelectedItem, ElementName=recordingsListView}"
Margin="0,24,0,0">
<TextBlock Text="{Binding ArtistName}"/>
<TextBlock Text="{Binding CompositionName}"/>
<TextBlock Text="{Binding ReleaseDateTime}"/>
</StackPanel>
</StackPanel>
</Grid>
</Page>
Pro CollectionViewSource nejprve přidejte CollectionViewSource jako prostředek stránky.
<Page.Resources>
<CollectionViewSource x:Name="RecordingsCollection" Source="{x:Bind ViewModel.Recordings}"/>
</Page.Resources>
Pak upravte vazby na ListView (který již nemusí být pojmenován) a při zobrazení podrobností použijte CollectionViewSource. Všimněte si, že vazbou zobrazení podrobností přímo na CollectionViewSourcevyjadřujete, že chcete vytvořit vazbu k aktuální položce ve vazbách, kde cestu nelze najít v kolekci. Vlastnost CurrentItem není nutné zadávat jako cestu pro vazbu, i když to můžete udělat, pokud existuje nějaká nejednoznačnost).
...
<ListView ItemsSource="{Binding Source={StaticResource RecordingsCollection}}">
...
<StackPanel DataContext="{Binding Source={StaticResource RecordingsCollection}}" ...>
...
A tady je stejný výsledek v každém případě.
Poznámka:
Pokud používáte C++, uživatelské rozhraní nebude vypadat přesně jako na obrázku níže: vykreslování vlastnosti ReleaseDateTime se liší. Další informace o tom najdete v následující části.
Formátování nebo převod hodnot dat pro zobrazení
Při vykreslování výše došlo k problému. Vlastnost ReleaseDateTime není jen datum, jedná se o DateTime (pokud používáte C++, pak je to kalendář). V jazyce C# se tedy zobrazuje s větší přesností, než potřebujeme. A v jazyce C++ se vykresluje jako název typu. Jedním z řešení je přidat řetězcovou vlastnost do třídy Recording, která vrací ekvivalent .this.ReleaseDateTime.ToString("d") Pojmenování této vlastnosti ReleaseDate označuje, že vrací datum, nikoli datum a čas. Pojmenování ReleaseDateAsString by dále ukazovalo, že se jedná o řetězec.
Flexibilnějším řešením je použít něco, co se označuje jako převaděč hodnot. Tady je příklad, jak vytvořit vlastní převaděč hodnot. Pokud používáte jazyk C#, přidejte následující kód do Recording.cs souboru zdrojového kódu. Pokud používáte C++/WinRT, přidejte do projektu novou položku Midl File (.idl), která je uvedená v následujícím výpisu kódu C++/WinRT, sestavte projekt, který vygeneruje StringFormatter.h a .cpppřidá tyto soubory do projektu, a pak do nich vložte výpisy kódu. Také přidejte #include "StringFormatter.h" do MainPage.h souboru.
public class StringFormatter : Windows.UI.Xaml.Data.IValueConverter
{
// This converts the value object to the string to display.
// This will work with most simple types.
public object Convert(object value, Type targetType,
object parameter, string language)
{
// Retrieve the format string and use it to format the value.
string formatString = parameter as string;
if (!string.IsNullOrEmpty(formatString))
{
return string.Format(formatString, value);
}
// If the format string is null or empty, simply
// call ToString() on the value.
return value.ToString();
}
// No need to implement converting back on a one-way binding
public object ConvertBack(object value, Type targetType,
object parameter, string language)
{
throw new NotImplementedException();
}
}
// pch.h
...
#include <winrt/Windows.Globalization.h>
// StringFormatter.idl
namespace Quickstart
{
runtimeclass StringFormatter : [default] Windows.UI.Xaml.Data.IValueConverter
{
StringFormatter();
}
}
// StringFormatter.h
#pragma once
#include "StringFormatter.g.h"
#include <sstream>
namespace winrt::Quickstart::implementation
{
struct StringFormatter : StringFormatterT<StringFormatter>
{
StringFormatter() = default;
Windows::Foundation::IInspectable Convert(Windows::Foundation::IInspectable const& value, Windows::UI::Xaml::Interop::TypeName const& targetType, Windows::Foundation::IInspectable const& parameter, hstring const& language);
Windows::Foundation::IInspectable ConvertBack(Windows::Foundation::IInspectable const& value, Windows::UI::Xaml::Interop::TypeName const& targetType, Windows::Foundation::IInspectable const& parameter, hstring const& language);
};
}
namespace winrt::Quickstart::factory_implementation
{
struct StringFormatter : StringFormatterT<StringFormatter, implementation::StringFormatter>
{
};
}
// StringFormatter.cpp
#include "pch.h"
#include "StringFormatter.h"
#include "StringFormatter.g.cpp"
namespace winrt::Quickstart::implementation
{
Windows::Foundation::IInspectable StringFormatter::Convert(Windows::Foundation::IInspectable const& value, Windows::UI::Xaml::Interop::TypeName const& /* targetType */, Windows::Foundation::IInspectable const& /* parameter */, hstring const& /* language */)
{
// Retrieve the value as a Calendar.
Windows::Globalization::Calendar valueAsCalendar{ value.as<Windows::Globalization::Calendar>() };
std::wstringstream wstringstream;
wstringstream << L"Released: ";
wstringstream << valueAsCalendar.MonthAsNumericString().c_str();
wstringstream << L"/" << valueAsCalendar.DayAsString().c_str();
wstringstream << L"/" << valueAsCalendar.YearAsString().c_str();
return winrt::box_value(hstring{ wstringstream.str().c_str() });
}
Windows::Foundation::IInspectable StringFormatter::ConvertBack(Windows::Foundation::IInspectable const& /* value */, Windows::UI::Xaml::Interop::TypeName const& /* targetType */, Windows::Foundation::IInspectable const& /* parameter */, hstring const& /* language */)
{
throw hresult_not_implemented();
}
}
...
public ref class StringFormatter sealed : Windows::UI::Xaml::Data::IValueConverter
{
public:
virtual Platform::Object^ Convert(Platform::Object^ value, TypeName targetType, Platform::Object^ parameter, Platform::String^ language)
{
// Retrieve the value as a Calendar.
Windows::Globalization::Calendar^ valueAsCalendar = dynamic_cast<Windows::Globalization::Calendar^>(value);
std::wstringstream wstringstream;
wstringstream << L"Released: ";
wstringstream << valueAsCalendar->MonthAsNumericString()->Data();
wstringstream << L"/" << valueAsCalendar->DayAsString()->Data();
wstringstream << L"/" << valueAsCalendar->YearAsString()->Data();
return ref new Platform::String(wstringstream.str().c_str());
}
// No need to implement converting back on a one-way binding
virtual Platform::Object^ ConvertBack(Platform::Object^ value, TypeName targetType, Platform::Object^ parameter, Platform::String^ language)
{
throw ref new Platform::NotImplementedException();
}
};
...
Poznámka:
Pro výše uvedený seznam StringFormatter.idlkódu C++/WinRT použijeme výchozí atribut k deklaraci IValueConverter jako výchozího rozhraní. StringFormatter má ve výpisu pouze konstruktor a žádné metody, protože pro něj není generováno žádné výchozí rozhraní. Atribut default je optimální, pokud nebudete přidávat členy instance do StringFormatter, protože k volání metod IValueConverter nebude nutné žádný QueryInterface. Alternativně můžete vyzvat výchozí IStringFormatter rozhraní, které se má vygenerovat, a to tak, že zapisujete samotnou třídu modulu runtime pomocí atributu default_interface. Tato možnost je optimální, pokud na StringFormatter přidáte členy instance, které se volají častěji než metody IValueConverter, protože pak nebude nutné použít QueryInterface k volání členů instance.
Teď můžeme přidat instanci StringFormatter jako prostředek stránky a použít ji ve vazbě TextBlock, která zobrazuje vlastnost ReleaseDateTime.
<Page.Resources>
<local:StringFormatter x:Key="StringFormatterValueConverter"/>
</Page.Resources>
...
<TextBlock Text="{Binding ReleaseDateTime,
Converter={StaticResource StringFormatterValueConverter},
ConverterParameter=Released: \{0:d\}}"/>
...
Jak je vidět výše, pro flexibilitu formátování používáme značkování k předání formátovacího řetězce do převaděče prostřednictvím parametru převaděče. V příkladech kódu uvedených v tomto tématu používá tento parametr pouze převaděč hodnot jazyka C#. Můžete ale snadno předat řetězec formátu C++jako parametr převaděče a použít ho ve vašem převaděči hodnot s funkcí formátování, jako je wprintf nebo swprintf.
Tady je výsledek.
Poznámka:
Počínaje verzí 1607 systému Windows 10 poskytuje architektura XAML integrovaný převaděč typu Boolean na Visibility. Převaděč mapuje true na hodnotu výčtu Visibility.Visible a false na Visibility.Collapsed, takže můžete vytvořit vazbu vlastnosti Visibility na Boolean bez nutnosti vytvoření převaděče. Pokud chcete použít integrovaný převaděč, minimální cílová verze sady SDK vaší aplikace musí být 14393 nebo novější. Nemůžete ho použít, když vaše aplikace cílí na starší verze Windows 10. Další informace o cílových verzích najdete v tématu „Verzově přizpůsobivý kód“.