【问题标题】:ListView SelectedItem not highlighted when set in ViewModel在 ViewModel 中设置时 ListView SelectedItem 未突出显示
【发布时间】:2014-11-11 07:32:43
【问题描述】:

我有一个ListView 和一个ItemSource 数据绑定和一个SelectedItem 数据绑定。

每次按下“下一个”或“上一个”按钮时,ListView 都会填充一个新的ItemSource

SelectedItem 相应更新,ItemSource 中的项目具有Selected 状态,因此用户来回导航时可以记住它。

在调试时,一切似乎都运行良好。 VM 按预期更新控件,当我使用下一个和上一个按钮导航时,我还可以看到 ListView 具有正确的选定值。

问题是,无论 ListView 有正确的SelectedItemListView 都不会将SelectedItem 可视化为突出显示。

XAML:

<ListView 
    x:Name="_matchingTvShowsFromOnlineDatabaseListView" 
    Grid.Row="0" 
    Grid.Column="0"
    Grid.RowSpan="3"
    ItemsSource="{Binding AvailableMatchingTvShows}"
    SelectedItem="{Binding AcceptedMatchingTvShow, Mode=TwoWay}">
    <ListView.ItemTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding Name}"/>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

ViewModel 中负责重新填充ItemSourceSelectedItem 的行为:

private void UpdateForCurrentVisibleTvShow()
{
    var selectedTvShow = FoundTvShows[CurrentTvShow];

    // Update the available matches
    var availableMatchingTvShows = new ObservableCollection<IWebApiTvShow>();
    if (AvailableTvShowMatches[selectedTvShow] != null)
    {
        foreach (var webApiTvShow in AvailableTvShowMatches[selectedTvShow])
        {
            availableMatchingTvShows.Add(webApiTvShow);
        }
    }
    AvailableMatchingTvShows = availableMatchingTvShows;

    // Update the selected item
    AcceptedMatchingTvShow = availableMatchingTvShows.FirstOrDefault(webApiTvShow => webApiTvShow.Accepted);

    // Update the progress text
    CurrentTvShowInfoText = string.Format(
        "TV Show: {0} ({1} of {2} TV Shows)",
        FoundTvShows[CurrentTvShow],
        CurrentTvShow + 1,
        FoundTvShows.Count);

    // Update the AcceptedMatchingTvShow selection in the listview
    OnPropertyChanged("AcceptedMatchingTvShow");
}

AcceptedMatchingTvShow的实现:

public IWebApiTvShow AcceptedMatchingTvShow
{
    get
    {
        IWebApiTvShow acceptedTvShow = null;
        if (FoundTvShows.Count > 0)
        {
            var tvShowName = FoundTvShows[CurrentTvShow];
            acceptedTvShow = AvailableTvShowMatches[tvShowName].FirstOrDefault(webApiTvShow => webApiTvShow.Accepted);
        }
        return acceptedTvShow;
    }
    set
    {
        if (value != null)
        {
            var tvShowName = FoundTvShows[CurrentTvShow];
            var currentlyAcceptedTvShow =
                AvailableTvShowMatches[tvShowName].FirstOrDefault(webApiTvShow => webApiTvShow.Accepted);
            if (currentlyAcceptedTvShow != null)
            {
                currentlyAcceptedTvShow.Accepted = false;
            }
            value.Accepted = true;
        }
        OnPropertyChanged();
    }
}

我希望有人能指出我正确的方向。为了清楚起见,ListView 具有正确的项目,并且 SelectedItem 设置了正确的项目。

【问题讨论】:

  • this.UpdateLayout(); 后面的代码中试试,你可以在SelectionChanged event 上调用它。您不会以这种方式更改VM 中的任何内容,因此只有View 会受到影响。 HTH
  • 你在哪里设置AcceptedMatchingTvShow
  • @Sinatr 我也用那部分代码更新了问题。它没有需要更新的支持字段,它只需要再次读取属性并评估哪个电视节目是Selected one
  • 你的 OnPropertyChanged();不应该取更改的属性的名称吗?
  • @sexta13,那个OnPropertyChanged方法可能在输入参数上声明了CallerMemberNameAttribute,所以它可以自动访问名称而无需传递它。

标签: c# wpf listview highlighting selecteditem


【解决方案1】:

嗯,经过大量调试和挖掘,我找到了问题的“解决方案”。我真的很想了解这是否是 WPF 意味着控件的行为方式,或者这是否是 ListViews 数据绑定部分中的错误。如果有人能告诉我,我对正确答案非常好奇(也许我以错误的方式解决了这个问题,有人可以解释我应该如何做到这一点)。

无论如何,当我创建对象的副本时,问题似乎得到了解决:

    public IWebApiTvShow AcceptedMatchingTvShow
    {
        get
        {
            IWebApiTvShow acceptedTvShow = null;
            if (FoundTvShows.Count > CurrentTvShow)
            {
                var tvShowName = FoundTvShows[CurrentTvShow];
                acceptedTvShow = AvailableTvShowMatches[tvShowName].FirstOrDefault(webApiTvShow => webApiTvShow.Accepted);
            }

            if (acceptedTvShow != null)
            {
                // I MUST create a new instance of the original object for the ListView to update the selected item (why??)
                return new WebApiTvShow(acceptedTvShow);
            }
            return null;
        }
        set
        {
            if (value != null)
            {
                var tvShowName = FoundTvShows[CurrentTvShow];
                var availableTvShowMatch = AvailableTvShowMatches[tvShowName];
                var currentlyAcceptedTvShow = availableTvShowMatch.FirstOrDefault(webApiTvShow => webApiTvShow.Accepted);
                if (currentlyAcceptedTvShow != null)
                {
                    currentlyAcceptedTvShow.Accepted = false;
                }
                value.Accepted = true;
            }

            OnPropertyChanged();
        }
    }

注意对复制构造函数的调用:

return new WebApiTvShow(acceptedTvShow);

它有效,但对我来说似乎真的很荒谬,并且闻起来像 ListView 中的错误。是吗?

我试图在一个更简单的例子here 中解释同样的问题,如果有人可以确认这个错误或者可以解释我应该如何实现它,我将非常感谢你的见解。

【讨论】:

    【解决方案2】:

    游戏有点晚了,但我一直在用类似的设置跳过箍来解决这个问题。使用 Viewmodel 中的绑定属性或使用绑定 SelectedIndex 的类似属性在 ListView 中设置 SelectedItem 是行不通的。直到我尝试异步执行:

    Task.Factory.StartNew(() =>
       {
           BoundSelectedIndex = index;
       });
    

    似乎有效 - 更高级的贡献者可能会回答为什么...

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-08-10
      • 2014-05-02
      • 1970-01-01
      • 2016-03-27
      • 1970-01-01
      • 2015-07-11
      • 2011-01-18
      • 1970-01-01
      相关资源
      最近更新 更多