Ten problem dręczy mnie od kilku dni. Okno to podstawowy wpis adresowy, który polega na wysyłaniu zapytań do bazy danych i wyświetlaniu wyników.
Użytkownik najpierw wprowadza ulicę (Bound to Query.Street), następnie miasto (Bound to Query.City), a następnie z listy wyników (DataGrid powiązany z QueryResults) wybiera odpowiednią ulicę.
Zapytanie do bazy danych odbywa się w obiekcie PropertyChanged of Query w ViewModel i działa dobrze. Wiążę ObservableCollection<Location> QueryResults
do DataGrid ItemsSource, a gdy w QueryResults pozostał tylko jeden element, przypisuję go do Location SelectedAddress
lubię to (this
będąc ViewModelem):
this.PropertyChanged += (sender, e) =>
{
switch (e.PropertyName)
{
case "QueryResults":
// QueryResult contains only one result
if (this.QueryResults?.Count == 1)
{
// select that result
this.SelectedAddress = this.QueryResults.First();
}
break;
default:
break;
}
};
Subskrybuję to zdarzenie w konstruktorze ViewModel.
QueryResults
w ViewModel:
internal ObservableCollection<Location> _queryResults = new ObservableCollection<Location>();
public ObservableCollection<Location> QueryResults
{
get { return this._queryResults; }
set
{
this._queryResults.Clear();
if (value != null)
{
foreach (var item in value)
{
this._queryResults.Add(item);
}
}
OnPropertyChanged("QueryResults");
}
}
To jest SelectedAddress
własność:
internal Location _selectedAddress = new Location();
public Location SelectedAddress
{
get { return this._selectedAddress; }
set
{
this._selectedAddress = value;
OnPropertyChanged("SelectedAddress");
}
}
Następnie wiążę this.SelectedAddress
do SelectedItem
DataGrid, aby mógł go wizualnie zaznaczyć. Kod DataGrid:
<DataGrid Name="dgQueryResults"
MaxHeight="212.6"
RowHeaderWidth="0"
AutoGenerateColumns="False"
CanUserAddRows="False"
CanUserDeleteRows="False"
CanUserReorderColumns="False"
CanUserResizeRows="False"
IsReadOnly="True"
VerticalScrollBarVisibility="Hidden"
ItemsSource="{Binding QueryResults}"
SelectionMode="Single"
SelectionUnit="FullRow"
SelectedItem="{Binding SelectedAddress, Mode=TwoWay}"
SelectionChanged="dgQueryResults_SelectionChanged"
>
<DataGrid.Resources>
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="LightGreen"/>
<SolidColorBrush x:Key="{x:Static SystemColors.ControlBrushKey}" Color="LightGreen"/>
<Style TargetType="{x:Type DataGridCell}" BasedOn="{StaticResource {x:Type DataGridCell}}">
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="Foreground" Value="Black"/>
</Style>
</DataGrid.Resources>
<DataGrid.Columns>
<DataGridTextColumn Width="*" Binding="{Binding Street}" IsReadOnly="True">
<DataGridTextColumn.Header>
<TextBlock Text="Street"/>
</DataGridTextColumn.Header>
</DataGridTextColumn>
<DataGridTextColumn Width="*" Binding="{Binding City}" IsReadOnly="True">
<DataGridTextColumn.Header>
<TextBlock Text="City"/>
</DataGridTextColumn.Header>
</DataGridTextColumn>
<DataGridTextColumn Width="*" Binding="{Binding Municipality}" IsReadOnly="True">
<DataGridTextColumn.Header>
<TextBlock Text="Municipality"/>
</DataGridTextColumn.Header>
</DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
dgQueryResults_SelectionChanged
jest tylko po to ScrollIntoView
wybrany wiersz.
SelectedAddress
jest również powiązany z panelem, który wyświetla wybrany adres i opis (jest to samodzielna właściwość w ViewModel, która jest kopiowana do SelectedAddress
gdy się zmienia), które użytkownik może wprowadzić, aby użytkownik mógł dwukrotnie sprawdzić, czy wybrał prawidłowy adres:
<DockPanel>
<TextBlock DockPanel.Dock="Top" Text="Selected address" FontWeight="DemiBold"/>
<DockPanel DockPanel.Dock="Bottom">
<TextBlock DockPanel.Dock="Top" Text="Floor, extra description:"/>
<TextBlock DockPanel.Dock="Bottom" Text="{Binding Description}"/>
</DockPanel>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" DataContext="{Binding SelectedAddress}">
<StackPanel>
<TextBlock Text="Street" HorizontalAlignment="Left"/>
<TextBlock Text="{Binding Street}" HorizontalAlignment="Left"/>
</StackPanel>
<StackPanel>
<TextBlock Text="House number" HorizontalAlignment="Left"/>
<TextBlock Text="{Binding HouseNumber}" HorizontalAlignment="Left"/>
</StackPanel>
<StackPanel>
<TextBlock Text="City" HorizontalAlignment="Left"/>
<TextBlock Text="{Binding City}" HorizontalAlignment="Left"/>
</StackPanel>
<StackPanel>
<TextBlock Text="Municipality" HorizontalAlignment="Left"/>
<TextBlock Text="{Binding Municipality}" HorizontalAlignment="Left"/>
</StackPanel>
</StackPanel>
</DockPanel>
Problem jest tak, że istnieje tylko jeden element w DataGrid (lub po równo w QueryResults
), Chcę go wybrać automatycznie (sprawdzam, kiedy QueryResults
zmienia się i jeśli zawiera tylko jedną pozycję, przypisz ją do SelectedAddress
), tak aby DataGrid zaktualizował wybrany element. Tak się nie dzieje. SelectedAddress
właściwość w zmianach ViewModel, plik OnPropertyChanged("SelectedAddress");
jest wywoływana, jednak DataGrid nie wybiera jedynego pozostałego wiersza, ani DockPanel nie aktualizuje. Jednak gdy kliknę wiersz w DataGrid, plik SelectedAddress
jest aktualizowany, a DockPanel aktualizuje się natychmiast.
Każda pomoc będzie bardzo ceniona!
Z góry dziękuję!
Edytować: Resetowanie okien DataContext
gdy SelectedAddress
zmiany działają, ale jest to obejście, którego raczej bym nie używał.
Odpowiedzi:
0 dla odpowiedzi № 1Rozgryzłem to.
Mimo że prawidłowo podbijałem PropertyChanged
nie wskazałem, że mój ViewModel
implementuje interfejs INotifyPropertyChanged
, dlatego zmiana nie odbiła się na interfejsie użytkownika.