Jegyzet
Az oldalhoz való hozzáférés engedélyezést igényel. Próbálhatod be jelentkezni vagy könyvtárat váltani.
Az oldalhoz való hozzáférés engedélyezést igényel. Megpróbálhatod a könyvtár váltását.
A WinUI-alkalmazások adatkötésével hatékonyan csatlakoztathat vezérlőket az adatforrásokhoz. Megtudhatja, hogyan köthet vezérlőt egyetlen elemhez vagy elemgyűjteményhez, hogyan jelenítheti meg a vezérlőelemek renderelését, implementálhatja a részletek nézeteit, és hogyan formázhatja az adatokat megjelenítésre. További részletekért lásd az adatkötés részletes ismertetését.
Előfeltételek
Ez a témakör feltételezi, hogy tudja, hogyan hozhat létre egy alapszintű WinUI-alkalmazást a Windows App SDK-val. Az első WinUI-alkalmazás létrehozásával kapcsolatos utasításokért lásd: WinUI-alkalmazás létrehozása.
A projekt létrehozása
Hozzon létre egy új WinUI Blank App, Packaged C# projektet. Nevezze el "Gyorsindításnak".
Kötés egyetlen elemhez
Minden kötés egy kötési célból és egy kötési forrásból áll. A cél általában egy vezérlő vagy más felhasználói felületi elem tulajdonsága, a forrás pedig egy osztálypéldány (adatmodell vagy nézetmodell) tulajdonsága. Ez a példa bemutatja, hogyan lehet egy vezérlőt egyetlen elemhez kötni. A cél a TextTextBlock tulajdonsága. A forrás egy Recording nevű egyszerű osztály egy példánya, amely hangrögzítést jelöl. Először nézzük meg az osztályt.
Adjon hozzá egy új osztályt a projekthez, és nevezze el az osztályt Recording.
namespace Quickstart
{
public class Recording
{
public string ArtistName { get; set; }
public string CompositionName { get; set; }
public DateTime ReleaseDateTime { get; set; }
public Recording()
{
ArtistName = "Wolfgang Amadeus Mozart";
CompositionName = "Andante in C for Piano";
ReleaseDateTime = new DateTime(1761, 1, 1);
}
public string OneLineSummary
{
get
{
return $"{CompositionName} by {ArtistName}, released: "
+ ReleaseDateTime.ToString("d");
}
}
}
public class RecordingViewModel
{
private Recording defaultRecording = new();
public Recording DefaultRecording { get { return defaultRecording; } }
}
}
Ezután tegye elérhetővé a kötési forrásosztályt a kódrészletet jelképező ablak osztályából. Adjon hozzá egy típustulajdonságot RecordingViewModel a MainWindow.xaml.cs.
namespace Quickstart
{
public sealed partial class MainWindow : Window
{
public MainWindow()
{
this.InitializeComponent();
}
public RecordingViewModel ViewModel{ get; } = new RecordingViewModel();
}
}
Az utolsó lépés az, hogy egy TextBlock-t kössünk a ViewModel.DefaultRecording.OneLineSummary tulajdonsághoz.
<Window x:Class="Quickstart.MainWindow" ... >
<Grid>
<TextBlock Text="{x:Bind ViewModel.DefaultRecording.OneLineSummary}"
HorizontalAlignment="Center"
VerticalAlignment="Center"/>
</Grid>
</Window>
Itt az eredmény.
Kötés egy elemgyűjteményhez
Gyakori forgatókönyv az üzleti objektumok gyűjteményéhez való kötés. A C#-ban használja az általános ObservableCollection<T> osztályt az adatkötéshez. Implementálja az INotifyCollectionChanged felületet, amely az elemek hozzáadásakor vagy eltávolításakor módosítja a kötéseket. A .NET 8 és újabb verziók ismert WinUI kiadási módbeli hibája miatt azonban előfordulhat, hogy bizonyos helyzetekben T listát<> kell használnia, különösen akkor, ha a gyűjtemény statikus, és nem változik az inicializálás után. Ha a felhasználói felületnek frissítenie kell, amikor a gyűjtemény futásidőben változik, használja a következőt ObservableCollection<T>: . Ha csak rögzített elemeket kell megjelenítenie, List<T> elegendő. Emellett ha azt szeretné, hogy a kötött vezérlők frissüljenek a gyűjtemény objektumtulajdonságainak módosításával, ezeknek az objektumoknak implementálniuk kell az INotifyPropertyChanged parancsot. További információ: Az adatkötés részletesen.
Jegyzet
A használatával List<T>előfordulhat, hogy nem kap változásértesítéseket a gyűjtemény módosításairól. Ha válaszolnia kell a változásokra, fontolja meg a használatát ObservableCollection<T>. Ebben a példában nem kell válaszolnia a gyűjtemény változásaira, ezért List<T> elegendő.
Az alábbi példa egy ListView objektumgyűjteményhez köti Recording . Először adja hozzá a gyűjteményt a nézetmodellhez. Vegye fel ezeket az új tagokat az RecordingViewModel osztályba.
public class RecordingViewModel
{
...
private List<Recording> recordings = new();
public List<Recording> Recordings{ get{ return recordings; } }
public RecordingViewModel()
{
recordings.Add(new Recording(){ ArtistName = "Johann Sebastian Bach",
CompositionName = "Mass in B minor", ReleaseDateTime = new DateTime(1748, 7, 8) });
recordings.Add(new Recording(){ ArtistName = "Ludwig van Beethoven",
CompositionName = "Third Symphony", ReleaseDateTime = new DateTime(1805, 2, 11) });
recordings.Add(new Recording(){ ArtistName = "George Frideric Handel",
CompositionName = "Serse", ReleaseDateTime = new DateTime(1737, 12, 3) });
}
}
Ezután kössön egy ListView-t a ViewModel.Recordings tulajdonsághoz.
<Window x:Class="Quickstart.MainWindow" ... >
<Grid>
<ListView ItemsSource="{x:Bind ViewModel.Recordings}"
HorizontalAlignment="Center"
VerticalAlignment="Center"/>
</Grid>
</Window>
Még nem adott meg adatsablont az Recording osztályhoz, így a felhasználói felületi keretrendszer a legjobb megoldás, ha meghívja a ToStringet a ListView minden eleméhez. Az alapértelmezett implementáció ToString a típusnevet adja vissza.
A probléma megoldásához felülbírálhatja ToString metódust, hogy visszaadja az OneLineSummary értékét, vagy megadhat egy adatsablont. Az adatsablon lehetőség egy gyakoribb és rugalmasabb megoldás. Adatsablont egy tartalomvezérlő ContentTemplate tulajdonságával vagy egy elemvezérlő ItemTemplate tulajdonságával adhat meg. Az alábbi két módon tervezhet adatsablont Recording az eredmény illusztrációjával együtt.
<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>
További információ az XAML szintaxisról: Felhasználói felület létrehozása XAML-. További információ a vezérlőelrendezésről: Elrendezések definiálása XAML-.
Részletek nézet hozzáadása
A Recording elemekben megjelenítheti a objektumok összes részletét. De ez a megközelítés sok helyet foglal el. Ehelyett elég adatot jeleníthet meg az elemben az azonosításhoz. Amikor a felhasználó kijelöl egy elemet, a kijelölt elem összes részletét megjelenítheti egy külön felhasználói felületen, a részletek nézetében. Ezt az elrendezést master/details nézetnek vagy lista/részletek nézetnek is nevezik.
Ezt az elrendezést kétféleképpen valósíthatja meg. A részletek nézetet a ListViewSelectedItem tulajdonságához kötheti. Vagy használhatja a CollectionViewSource-t is. Ebben az esetben mind a ListView-hoz, mind a részletek nézetéhez kötést hajt végre a CollectionViewSource-hoz. Ez a módszer gondoskodik a jelenleg kijelölt elemről. Mindkét technika a következő szakaszokban látható, és mindkettő ugyanazt az eredményt adja (az ábrán látható).
Jegyzet
Ebben a témakörben eddig csak a {x:Bind} jelölőbővítményt használta. A következő szakaszokban bemutatott mindkét módszerhez azonban rugalmasabb (de kevésbé teljesítő) {Binding} korrektúrakiterjesztésre van szükség.
Először is, a SelectedItem technikát. C#-alkalmazások esetében csak a korrektúra módosítása szükséges.
<Window x:Class="Quickstart.MainWindow" ... >
<Grid>
<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>
</Window>
A CollectionViewSource technikához először adjon hozzá egy CollectionViewSource a legfelső szintű Griderőforrásaként.
<Grid.Resources>
<CollectionViewSource x:Name="RecordingsCollection" Source="{x:Bind ViewModel.Recordings}"/>
</Grid.Resources>
Jegyzet
A WinUI Ablak osztályának nincs Resources tulajdonsága. A CollectionViewSource elemet hozzáadhatja a legfelső szintű Grid (vagy más szülő felhasználói felületi elem, például StackPanel) elemhez is. Ha egy Page-ban dolgozik, hozzáadhatja a CollectionViewSource-et a Page.Resources-höz.
Ezután módosítsa a kapcsolatokat a ListView-ban (amelyiknek már nincs szüksége elnevezésre) és a részletek nézetben a CollectionViewSource használatához. Ha a részletek nézetet közvetlenül a CollectionViewSourcegyűjteményhez köti, azt jelenti, hogy az aktuális elemhez szeretne kötéseket kötni, ahol az elérési út nem található a gyűjteményben. A kötés elérési útjaként nem kell megadnia a CurrentItem tulajdonságot, bár ezt kétértelműség esetén megteheti.
...
<ListView ItemsSource="{Binding Source={StaticResource RecordingsCollection}}">
...
<StackPanel DataContext="{Binding Source={StaticResource RecordingsCollection}}" ...>
...
És minden esetben ugyanaz az eredmény.
Adatértékek formázása vagy konvertálása megjelenítésre
A fenti rendereléssel kapcsolatban probléma merült fel. A ReleaseDateTime tulajdonság nem csak dátum, hanem Dátumidő is. Így a szükségesnél nagyobb pontossággal jelenik meg. Az egyik megoldás egy sztringtulajdonság hozzáadása a Recording osztályhoz, amely a ReleaseDateTime.ToString("d")értékének megfelelőjét adja vissza. A tulajdonság ReleaseDate elnevezése azt jelzi, hogy dátumot ad vissza, nem pedig dátumot és időt. Az, hogy elnevezzük ReleaseDateAsString-t, azt is jelzi, hogy egy sztringet ad vissza.
Rugalmasabb megoldás egy értékkonverter használata. Íme egy példa arra, hogyan hozhat létre saját értékkonvertert. Adja hozzá a következő kódot a Recording.cs forráskódfájlhoz.
public class StringFormatter : Microsoft.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();
}
}
Most hozzáadhat egy StringFormatter példányt erőforrásként, és használhatja azt a TextBlock kötésben, amely megjeleníti a ReleaseDateTime tulajdonságot.
<Grid.Resources>
...
<local:StringFormatter x:Key="StringFormatterValueConverter"/>
</Grid.Resources>
...
<TextBlock Text="{Binding ReleaseDateTime,
Converter={StaticResource StringFormatterValueConverter},
ConverterParameter=Released: \{0:d\}}"/>
...
Amint látható, a formázási rugalmasság érdekében a jelölő a formátumsztringet a konverter paramétere útján adja át a konverternek. A jelen témakörben bemutatott kód példájában a C# értékkonverter ezt a paramétert használja.
Itt az eredmény.
A Binding és az x:Bind közötti különbségek
Amikor a WinUI-alkalmazásokban adatkötéssel dolgozik, két elsődleges kötési mechanizmussal találkozhat: Binding és x:Bind. Bár mindkettő a felhasználói felület elemeinek adatforrásokhoz való csatlakoztatását szolgálja, különböző különbségek vannak:
-
x:Bind: Fordítási időbeli ellenőrzést kínál, jobb teljesítményt nyújt, és szigorúan típusos. Ideális olyan forgatókönyvekhez, ahol a fordítási időben ismeri az adatstruktúrát. -
Binding: Futásidejű értékelést biztosít, és rugalmasabb a dinamikus forgatókönyvekhez, például ha az adatstruktúra fordításkor nem ismert.
Az x:Bind által nem támogatott forgatókönyvek
Bár x:Bind hatékony, bizonyos esetekben nem használhatja:
-
Dinamikus adatstruktúrák: Ha az adatstruktúra fordításkor nem ismert, akkor nem használható
x:Bind. -
Elem–elem kötés:
x:Bindnem támogatja közvetlenül két felhasználói felületi elem közötti kötést. - A
DataContextx:Bindvaló kötés nem örökli automatikusan a szülőelemDataContextértékét. -
Kétirányú kötések a következővel
Mode=TwoWay: Habár támogatott, explicit implementálást igényelx:Bindminden olyan tulajdonság esetén, amelyet szeretnénk, hogy a felhasználói felület frissítsen, amikor a forrás megváltozik, függetlenül attól, hogy egyirányú vagy kétirányú kötést használunk. A kétirányú kötések fő különbsége, hogy a módosítások a felhasználói felületről a forrásra is átfolynak.
Gyakorlati példákért és a használatuk időpontjának mélyebb megértéséhez tekintse meg az alábbi témaköröket:
Kapcsolódó tartalom
Windows developer