【发布时间】:2017-12-11 13:44:57
【问题描述】:
过去几天这个问题一直困扰着我。该窗口是一个基本地址条目,通过查询数据库并显示结果。
用户首先输入街道(绑定到 Query.Street),然后输入城市(绑定到 Query.City),然后从结果列表(DataGrid 绑定到 QueryResults)中选择合适的街道。
查询数据库是在 ViewModel 中的 Query 对象的 PropertyChanged 中完成的,它工作得很好。我将ObservableCollection<Location> QueryResults 绑定到DataGrid ItemsSource,当QueryResults 中只剩下一个项目时,我将它分配给Location SelectedAddress,就像这样(this 是ViewModel):
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;
}
};
我在 ViewModel 构造函数中订阅了这个事件。
ViewModel 中的QueryResults:
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");
}
}
这是SelectedAddress 属性:
internal Location _selectedAddress = new Location();
public Location SelectedAddress
{
get { return this._selectedAddress; }
set
{
this._selectedAddress = value;
OnPropertyChanged("SelectedAddress");
}
}
然后我将this.SelectedAddress 绑定到DataGrid 的SelectedItem,以便它可以直观地选择它。数据网格代码:
<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 只存在于ScrollIntoView 所选行。
SelectedAddress 还绑定到一个面板,该面板显示选定的地址和用户可以输入的描述(这是 ViewModel 中的独立属性,当它更改时被复制到 SelectedAddress),以便用户可以仔细检查他们是否选择了正确的地址:
<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>
问题是当 DataGrid 中只剩下一个项目时(或者同样在 QueryResults 中),我想自动选择它(我在 QueryResults 更改和如果它只包含一项,则将其分配给SelectedAddress),以便 DataGrid 将更新其选定的项。这不会发生。 ViewModel 中的SelectedAddress 属性发生变化,OnPropertyChanged("SelectedAddress"); 被调用,但是 DataGrid 不会选择剩下的唯一行,DockPanel 也不会更新。但是,当我单击 DataGrid 中的一行时,SelectedAddress 会更新,并且 DockPanel 会立即更新。
任何帮助将不胜感激!
提前致谢!
编辑:当SelectedAddress 更改时重置窗口DataContext 有效,但我不想使用它的解决方法。
【问题讨论】:
-
你
Clear和 re-Add你的可观察集合的方式让我担心。这意味着清除后,SelectedItem将与可用项目不同步。有时,Binding会在几次尝试后无法产生正确结果时决定禁用更新。 -
好的,我会检查并报告。我将对其进行重写,以便它不会将新的
ObservableCollection分配给QueryResults,但会在其中添加/删除项目。 -
@grek40 仍然不起作用:/
-
您能否检查一下,集合和属性更改是否发生在 UI 线程上(类似于
Thread.CurrentThread == Dispatcher.Thread)? -
是的,集合更改和
SelectedAddress更改都发生在 UI 线程上。我在 PropertyChange 事件和 setter 中比较了Windows 线程和当前线程。