[英]Highlight ListView Item From Code - WPF Data Binding
我訪問過的以前的來源(但沒有找到答案):
更密切相關但過於復雜/不完全是我需要的來源。
一般信息:
如標記,此代碼在c#
中,使用WPF
,目標框架.NET Framework 4.5
。
注意:這是我第一次嘗試實現MVVM
,因此我將不勝感激有關我缺少的最佳實踐的評論(盡管這不是這個問題的主要主題)。
問題:
WPF 帶有ListView
和Button
。 Button
從ListView
中刪除項目。
ListView<String>
(View) --->RemoveStringFromList()
(ViewModel)
以上工作。 我的問題是突出顯示。
我希望能夠從 ListView 中刪除一個字符串,並在刪除后突出顯示不同的 Item 。
我最初的想法是,通過使用與ListView
的SelectedItem
屬性綁定的屬性 ( SelectedItemProperty
) - 突出顯示將是自動的。
但在實踐中, SelectedItem
屬性綁定有效——因為我可以繼續按下Button
並刪除根據SelectedItemProperty
設置器中實現的邏輯成為SelectedItem
的項目——但盡管它們是按代碼選擇的,但它們沒有突出顯示。
代碼:
主窗口.xaml
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="213.06">
<Grid>
<ListView ItemsSource="{Binding ItemsProperty}" SelectedItem="{Binding SelectedItemProperty}" HorizontalAlignment="Left" Height="214" Margin="35,74,0,0" VerticalAlignment="Top" Width="142">
<ListView.View>
<GridView>
<GridViewColumn/>
</GridView>
</ListView.View>
</ListView>
<Button Command="{Binding RemoveString}" Content="Remove From List!" HorizontalAlignment="Left" Margin="35,10,0,0" VerticalAlignment="Top" Width="142" Height="46"/>
</Grid>
</Window>
主窗口.xaml.cs
using System.Windows;
namespace WpfApplication1
{
public partial class MainWindow : Window
{
private readonly MainWindowViewModel _viewModel;
public MainWindow()
{
InitializeComponent();
_viewModel = new MainWindowViewModel();
DataContext = _viewModel;
Show();
}
}
}
MainWindowViewModel.cs
using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows.Input;
namespace WpfApplication1
{
public class MainWindowViewModel : INotifyPropertyChanged
{
private ObservableCollection<String> _list;
private String _selectedItem;
public MainWindowViewModel()
{
_list = new ObservableCollection<String> {"1", "2", "3", "4"};
RemoveString = new RemoveStringCommand(this);
}
public ObservableCollection<String> ItemsProperty
{
get { return _list; }
}
public String SelectedItemProperty
{
get { return _selectedItem; }
set
{
if (value != null)
{
_selectedItem = value;
}
else
{
if (_list.Count > 0)
{
_selectedItem = _list[0];
}
}
}
}
public ICommand RemoveString
{
get;
private set;
}
public bool CanRemoveString
{
get { return _list.Count > 0; }
}
public void RemoveStringFromList()
{
if (SelectedItemProperty != null)
{
_list.Remove(SelectedItemProperty);
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged(String propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
RemoveStringCommand.cs
using System.Windows.Input;
using WpfApplication1;
namespace WpfApplication1
{
class RemoveStringCommand : ICommand
{
private MainWindowViewModel _viewModel;
public RemoveStringCommand(MainWindowViewModel viewModel)
{
_viewModel = viewModel;
}
public event System.EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public bool CanExecute(object parameter)
{
return _viewModel.CanRemoveString;
}
public void Execute(object parameter)
{
_viewModel.RemoveStringFromList();
}
}
}
應用圖片 - 首次點擊之前
應用程序圖片 - 單擊 1 次后(注意 - 沒有突出顯示!)
應用圖片 - 2 次點擊后(仍然沒有突出顯示...)
首先刪除一個錯誤
public MainWindow()
{
InitializeComponent();
_viewModel = new MainWindowViewModel();
DataContext = _viewModel;
// Show(); remove this, it's not needed
}
我用兩個可重用的輔助類做了一個例子。
1)第一個常見的 class 實現INotifyPropertyChanged
。 在每個 ViewModel class 中重復實現 INPC 可能會有所幫助。
public class NotifyPropertyChanged : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName]string propertyName = null)
=> PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
[CallerMemberName]
此處允許不在每個OnPropertyChanged()
調用中包含屬性名稱。 編譯器會自動完成。
2) Class 便於命令使用。 (在這里抓到)
public class RelayCommand : ICommand
{
private readonly Action<object> _execute;
private readonly Func<object, bool> _canExecute;
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public RelayCommand(Action<object> execute, Func<object, bool> canExecute = null)
{
_execute = execute;
_canExecute = canExecute;
}
public bool CanExecute(object parameter) => _canExecute == null || _canExecute(parameter);
public void Execute(object parameter) => _execute(parameter);
}
3)在以下示例中,我根據您的要求更改了屬性的名稱。 不要命名諸如SomethingProperty
之類的屬性以避免與依賴屬性發生沖突,這種命名模式僅對 DP 有用。
標記:
<Grid>
<ListView ItemsSource="{Binding ItemsList}" SelectedIndex="{Binding SelectedItemIndex}" HorizontalAlignment="Left" Height="214" Margin="35,74,0,0" VerticalAlignment="Top" Width="142">
<ListView.View>
<GridView>
<GridViewColumn/>
</GridView>
</ListView.View>
</ListView>
<Button Command="{Binding RemoveItem}" Content="Remove From List!" HorizontalAlignment="Left" Margin="35,10,0,0" VerticalAlignment="Top" Width="142" Height="46"/>
</Grid>
4)視圖模型:
public class MainWindowViewModel : NotifyPropertyChanged
{
private ObservableCollection<string> _itemsList;
private int _selectedItemIndex;
private ICommand _removeItem;
public MainWindowViewModel()
{
// never interact with fields outside of the property 'set' clause
// use property name instead of back-end field
ItemsList = new ObservableCollection<string> { "1", "2", "3", "4" };
}
public ObservableCollection<string> ItemsList
{
get => _itemsList;
set
{
_itemsList = value;
OnPropertyChanged(); // Notify UI that property was changed
//other ways doing the same call
// OnPropertyChanged("ItemsList");
// OnPropertyChanged(nameof(ItemsList));
}
}
public int SelectedItemIndex
{
get => _selectedItemIndex;
set
{
_selectedItemIndex = value;
OnPropertyChanged();
}
}
// command will be initialized in "lazy" mode, at a first call.
public ICommand RemoveItem => _removeItem ?? (_removeItem = new RelayCommand(parameter =>
{
ItemsList.RemoveAt(SelectedItemIndex);
},
// SelectedItemIndex -1 means nothing is selected
parameter => SelectedItemIndex >=0 && ItemsList.Count > 0));
}
作為獎勵,您可以以編程方式更改ListView
的SelectedIndex
,只需將任何值設置為SelectedItemIndex
。
編輯:
抱歉,我忘記在刪除后保留選擇。 修改命令:
public ICommand RemoveItem => _removeItem ?? (_removeItem = new RelayCommand(parameter =>
{
int index = SelectedItemIndex;
ItemsList.RemoveAt(index);
if (ItemsList.Count > 0)
SelectedItemIndex = (index == ItemsList.Count) ? index - 1 : index;
}, parameter => SelectedItemIndex >= 0 && ItemsList.Count > 0));
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.