【问题标题】:Binding SelectedItem on DataGrid doesn't work在 DataGrid 上绑定 SelectedItem 不起作用
【发布时间】: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 线程和当前线程。

标签: wpf mvvm datagrid


【解决方案1】:

我想通了。

尽管我正确地引发了PropertyChanged 事件,但我并没有指出我的ViewModel 实现了接口INotifyPropertyChanged,所以这就是为什么更改没有反映在UI 上。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-10-12
    • 2012-02-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多