就像标题所说,我尝试通知属性更改,方法 RaisePropertyChanged 被直接调用,但PropertyChanged始终为null。
这里是缩短的课程:
public class BluetoothManager : INotifyPropertyChanged {
private string selectedBluetoothResult;
private List<string> foundDevices = new List<string>(5);
public List<DeviceInformation> penDevices = new List<DeviceInformation>();
private GattCharacteristic TxCharacteristic;
public string SelectedBluetoothResult {
get {
return selectedBluetoothResult;
}
set {
selectedBluetoothResult = value;
RaisePropertyChanged();
}
}
public List<string> FoundDevices {
get
{
return foundDevices;
}
set
{
foundDevices = value;
RaisePropertyChanged();
}
}
public BluetoothManager() {
StartScanWatcher();
}
public void StartScanWatcher() {
Debug.WriteLine("Starting device watcher...");
String query = "";
//query for Bluetooth LE devices
query += "System.Devices.DevObjectType:=5 AND System.Devices.Aep.ProtocolId:=\"{BB7BB05E-5972-42B5-94FC-76EAA7084D49}\"";
//query for devices with controllers' name
query += " AND (System.ItemNameDisplay:=\"" + DeviceName + "\" )";
var deviceWatcher = DeviceInformation.CreateWatcher(query); //, requestedProperties, DeviceInformationKind.AssociationEndpoint);
deviceWatcher.Added += DeviceWatcher_OnAdded;
deviceWatcher.EnumerationCompleted += DeviceWatcher_OnEnumComplete;
deviceWatcher.Removed += DeviceWatcher_Removed;
deviceWatcher.Stopped += DeviceWatcher_Stopped;
deviceWatcher.Updated += DeviceWatcher_Updated;
deviceWatcher.Start();
Debug.WriteLine(" StartScanWatcher end");
}
private void DeviceWatcher_OnAdded(DeviceWatcher sender, DeviceInformation deviceInfo) {
Debug.WriteLine(" DeviceWatcher_OnAdded Start");
lock (foundDevices) {
if (foundDevices.Contains(deviceInfo.Id)) {
return;
}
foundDevices.Add(deviceInfo.Id);
RaisePropertyChanged("FoundDevices");
}
Debug.WriteLine($"[{deviceInfo.Name}] DeviceWatcher_OnAdded...");
if (SelectedBluetoothResult == null)
{
SelectedBluetoothResult = deviceInfo.Id;
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged([CallerMemberName] string propertyName = null)
{
Debug.WriteLine("<<<<<<<<<<<<< BluetoothManager, PropertyChanging: " + propertyName);
if (PropertyChanged == null) {
Debug.WriteLine("============ BluetoothManager, PropertyChanged == null, " + propertyName);
return;
}
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
Debug.WriteLine(">>>>>>>>>>>>> BluetoothManager, PropertyChanged: " + propertyName);
}
}
}
这里是XAML文件中的Binding:
<ListView ItemsSource="{Binding BluetoothManager.FoundDevices}" SelectedItem="{Binding BluetoothManager.SelectedBluetoothResult}">
<ListView.Resources>
<DataTemplate x:Key="BluetoothDeviceTemplate">
<TextBlock Text="{Binding Path=Sap}"/>
</DataTemplate>
</ListView.Resources>
</ListView>
绑定似乎正常。
请注意,PropertyChanged始终为null的类不是XAML文件的DataContext。这是否意味着我必须以不同的方式使用PropertyChange通知?
提前致谢。
修改 完整的MainWindowViewModel:
public class MainWindowViewModel : INotifyPropertyChanged {
private ObservableCollection<BookGame> _booksToDisplay = new ObservableCollection<BookGame>();
private ObservableCollection<BookGame> _games = new ObservableCollection<BookGame>();
private string _url;
private int[] _newBooksMID;
private int[] _oldBooksMID;
private Dictionary<int, int> _newBooksVersionNumbers;
private Dictionary<int, int> _oldBooksVersionNumbers;
private Dictionary<int, int> _allVersionNumbers;
private List<BookGame> _booksToAdd;
private long _downloadSpeed;
private bool _isDownloading = true;
private bool _toggleLastSearchKeyWasReturn = false;
string _volumeLabel = "";
FileInfo[] _filesTxt = { };
FileInfo[] _filesAll = { };
private string _folderPath = "";
private string _driveName = null;
List<BookGame> _allGames;
List<BookGame> _allBooks;
List<MP3> _allMP3;
long lengthAllBooks = 0;
long lengthAllGames = 0;
int _percentDownloaded = 100;
private long _amountBytesToDownload;
private long _amountBytesDownloaded;
private long _amountMBytesToDownload;
private long _amountMBytesDownloaded;
private int _downloadTime;
//private bool _isDownloadAborted;
ServerCommi serverComm;
public BluetoothManager BluetoothManager { get; set; }
public MainWindowViewModel() {
DownloadTime = 0;
AmountBytesToDownload = 0;
AmountBytesDownloaded = 0;
DriveInfo drive = null;
foreach (DriveInfo driveInfo in DriveInfo.GetDrives()) {
if (driveInfo.IsReady && driveInfo.VolumeLabel == _volumeLabel) {
drive = driveInfo;
_driveName = drive.Name;
_folderPath = _driveName + _folderPath;
}
}
DirectoryInfo di = new DirectoryInfo(_folderPath);
if (di.Exists)
{
_filesTxt = di.GetFiles("*.txt");
FilesAll = di.GetFiles("*.*");
foreach (FileInfo file in _filesTxt)
{
try
{
Convert.ToInt32(file.Name.Split('_')[0]);
AddBookGameToList(file);
}
catch (Exception e)
{
}
}
}
SearchResults = new ObservableCollection<ResultItem>();
MenuCommand = new RelayCommand(o => {
Debug.WriteLine("Menu Command " + o);
SwitchBooks(o);
});
SearchReturnKeyCommand = new RelayCommand(o => {
Debug.WriteLine("00000000000000000000000000000000 SearchReturnKeyCommand " + o);
SearchActivated();
});
BrowserCommand = new RelayCommand(o => {
Debug.WriteLine("Browser Command main" + o);
CallBrowser("");
});
DeleteCommand = new RelayCommand(o => {
Debug.WriteLine("Delete Command main" + o);
});
ToggleDownloadsCommand = new RelayCommand(o => {
Debug.WriteLine(" |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| ");
Debug.WriteLine(" |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| ");
Debug.WriteLine("ToggleDownloadsCommand Command main" + o);
ToggleDownloads();
});
_viewModelMusic = new ViewModelMusic(_driveName);
AllGames = Games.ToList<BookGame>();
AllBooks = BooksToDisplay.ToList<BookGame>();
AllMP3 = _viewModelMusic.Mp3s.ToList<MP3>();
long lengthAllMP3 = 0;
foreach (MP3 mp3 in AllMP3) {
lengthAllMP3 += mp3.LengthValue;
}
_viewModelBooks = new ViewModelBooks(BooksToDisplay);
_viewModelGames = new ViewModelGames(Games);
_viewModelFiles = new ViewModelFiles(FilesAll);
_viewModelLumi = new ViewModelLumi(drive, lengthAllBooks, lengthAllGames, lengthAllMP3);
_viewModelOverview = new ViewModelOverview(AllBooks, AllGames, AllMP3);
_screens[0] = _viewModelOverview;
_screens[1] = _viewModelBooks;
_screens[2] = _viewModelGames;
_screens[3] = _viewModelMusic;
_screens[4] = _viewModelFiles;
_screens[5] = _viewModelVideos;
_screens[6] = _viewModelAdults;
_screens[7] = _viewModelLumi;
SearchText = "";
SelectedItem = _viewModelBooks;
Debug.WriteLine("CALLING ServerCommi! Ring, ring!");
serverComm = new ServerCommi(this);
//serverComm.DownloadBooksAsync();
BluetoothManager = new BluetoothManager();
}
private void ToggleDownloads() {
IsDownloading = !IsDownloading;
serverComm.ToggleDownloads(IsDownloading);
_viewModelBooks.ToggleDownloads(IsDownloading);
}
internal void DownloadStateChange(int mid, int newState) {
_viewModelBooks.DownloadStateChange(mid, newState);
}
// params bool[] isDownload : varargs
// returns the mid
public int AddBookGameToList(FileInfo file, bool isDownload = false) {
BookGame bg = new BookGame(file);
if (isDownload) {
bg.DownloadState = 2;
if (bg.Mid == serverComm.DownloadingMID) {
bg.DownloadState = 1;
}
}
if (bg.Group.StartsWith("B")) {
bg.Group = "Bücher";
}
switch (bg.Group) {
case "Bücher":
if (isDownload) {
BooksToDisplay.Insert(0, bg);
} else {
BooksToDisplay.Add(bg);
}
lengthAllBooks += bg.LengthValue;
break;
case "Spiele":
Games.Add(bg);
lengthAllGames += bg.LengthValue;
break;
default:
Debug.WriteLine("Default: " + bg.Title);
break;
}
return bg.Mid;
}
private void CallBrowser(string url) {
Debug.WriteLine("Url: " + Url);
try {
System.Diagnostics.Process.Start(Url);
} catch (System.ComponentModel.Win32Exception noBrowser) {
if (noBrowser.ErrorCode == -2147467259)
MessageBox.Show(noBrowser.Message);
} catch (System.Exception other) {
MessageBox.Show(other.Message);
}
}
string _searchText;
public string SearchText {
get {
return _searchText;
}
set {
Debug.WriteLine("SearchText Value= " + value);
if (!_toggleLastSearchKeyWasReturn) {
_searchText = value;
SearchResults.Clear();
List<ResultItem> _allBooksRI = new List<ResultItem>();
List<ResultItem> _allBooksHelperList = _allBooks.ToList<ResultItem>();
List<ResultItem> _allGamesHelperList = _allGames.ToList<ResultItem>();
List<ResultItem> _allMP3HelperList = _allMP3.ToList<ResultItem>();
if (SelectedItem != null && SelectedItem.Equals(_viewModelGames)) {
AddAllResultItemsIf(SearchResults, _allGamesHelperList, _searchText);
AddAllResultItemsIf(SearchResults, _allBooksHelperList, _searchText);
AddAllResultItemsIf(SearchResults, _allMP3HelperList, _searchText);
Debug.WriteLine("===================================== Games - " + SearchResults);
Debug.WriteLine("SelectedItem - " + SelectedItem);
} else if (SelectedItem != null && SelectedItem.Equals(_viewModelMusic)) {
AddAllResultItemsIf(SearchResults, _allMP3HelperList, _searchText);
AddAllResultItemsIf(SearchResults, _allGamesHelperList, _searchText);
AddAllResultItemsIf(SearchResults, _allBooksHelperList, _searchText);
Debug.WriteLine("====================================== Music " + SearchResults);
Debug.WriteLine("SelectedItem - " + SelectedItem);
} else {
AddAllResultItemsIf(SearchResults, _allBooksHelperList, _searchText);
AddAllResultItemsIf(SearchResults, _allGamesHelperList, _searchText);
AddAllResultItemsIf(SearchResults, _allMP3HelperList, _searchText);
Debug.WriteLine("====================================== Books " + SearchResults);
}
if (SearchResults.Count == 0) {
SearchResults.Add(new ErrorResultItem("Error", "Nichts passendes gefunden."));
}
} else {
_toggleLastSearchKeyWasReturn = false;
}
}
}
private ObservableCollection<ResultItem> AddAllResultItemsIf(ObservableCollection<ResultItem> searchResults, List<ResultItem> toAdd, string searchText) {
foreach (ResultItem item in toAdd) {
if (item.Title.ToLower().Contains(_searchText.ToLower())) {
searchResults.Add(item);
}
}
return searchResults;
}
public ObservableCollection<ResultItem> SearchResults {
get; set;
}
ResultItem _selectedResult;
public ResultItem SelectedResult {
get {
return _selectedResult;
}
set {
_selectedResult = value;
SearchItemSelected(value);
}
}
private void SearchItemSelected(ResultItem value) {
switch (value.Group) {
case "Bücher":
SelectedItem = _viewModelBooks;
break;
case "Spiele":
SelectedItem = _viewModelGames;
break;
case "Musik":
SelectedItem = _viewModelMusic;
break;
default:
Debug.WriteLine("Search Item Selected, jumped to default: " + value);
break;
}
Unmark(Marked);
Mark(value);
}
ResultItem _marked;
internal void Mark(ResultItem value) {
Marked = value;
value.Marked = true;
}
internal void Unmark(ResultItem value) {
Marked = null;
if (value != null) {
value.Marked = false;
}
}
public ResultItem Marked {
get => _marked;
set => _marked = value;
}
private bool _isSearchResult;
public bool IsSearchResult {
get {
return _isSearchResult;
}
set {
_isSearchResult = value;
Debug.WriteLine("IsSearchResult= " + value);
RaisePropertyChanged();
}
}
private void SearchActivated() {
_toggleLastSearchKeyWasReturn = true;
SelectedItem = _viewModelOverview;
IsSearchResult = true;
}
private object _selectedItem;
public object SelectedItem {
get {
return _selectedItem;
}
set {
_selectedItem = value;
Debug.WriteLine("SELECTED_ITEM SETTER: " + value);
Unmark(Marked);
IsSearchResult = false;
if (SearchText != null) {
SearchText = SearchText;
}
RaisePropertyChanged();
}
}
ViewModelOverview _viewModelOverview;
ViewModelBooks _viewModelBooks;
ViewModelGames _viewModelGames;
ViewModelMusic _viewModelMusic;
ViewModelFiles _viewModelFiles;
ViewModelVideos _viewModelVideos = new ViewModelVideos();
ViewModelAdults _viewModelAdults = new ViewModelAdults();
ViewModelLumi _viewModelLumi;
object[] _screens = new object[8];
public object[] Screens {
get {
return _screens;
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged([CallerMemberName] string propertyName = null) {
if (PropertyChanged == null)
return;
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
public ICommand MenuCommand {
get; set;
}
public ICommand SearchReturnKeyCommand {
get; set;
}
public ICommand BrowserCommand {
get; set;
}
public ICommand ToggleDownloadsCommand {
get; set;
}
public RelayCommand DeleteCommand {
get;
private set;
}
public List<BookGame> AllGames {
get => _allGames;
set => _allGames = value;
}
public List<BookGame> AllBooks {
get => _allBooks;
set => _allBooks = value;
}
public List<MP3> AllMP3 {
get => _allMP3;
set => _allMP3 = value;
}
public ViewModelBooks ViewModelBooks {
get => _viewModelBooks;
set => _viewModelBooks = value;
}
public ObservableCollection<BookGame> BooksToDisplay {
get => _booksToDisplay;
set => _booksToDisplay = value;
}
public ObservableCollection<BookGame> Games {
get => _games;
set => _games = value;
}
public string Url {
get {
return _url;
}
set {
_url = value;
RaisePropertyChanged();
}
}
public int[] NewBooksMID {
get => _newBooksMID;
set => _newBooksMID = value;
}
public int[] OldBooksMID {
get => _oldBooksMID;
set => _oldBooksMID = value;
}
public Dictionary<int, int> NewBooksVersionNumbers {
get => _newBooksVersionNumbers;
set => _newBooksVersionNumbers = value;
}
public Dictionary<int, int> OldBooksVersionNumbers {
get => _oldBooksVersionNumbers;
set => _oldBooksVersionNumbers = value;
}
public Dictionary<int, int> AllVersionNumbers {
get => _allVersionNumbers;
set => _allVersionNumbers = value;
}
public int[] OldBooksMID1 {
get => _oldBooksMID;
set => _oldBooksMID = value;
}
public List<BookGame> BooksToAdd {
get => _booksToAdd;
set => _booksToAdd = value;
}
public FileInfo[] FilesAll {
get => _filesAll;
set => _filesAll = value;
}
public string FolderPath {
get => _folderPath;
set => _folderPath = value;
}
public int PercentDownloaded {
get {
return _percentDownloaded;
}
set {
_percentDownloaded = value;
RaisePropertyChanged();
}
}
public long DownloadSpeed {
get {
return _downloadSpeed;
}
set {
_downloadSpeed = value;
RaisePropertyChanged();
}
}
public long AmountBytesToDownload {
get {
return _amountBytesToDownload;
}
set {
_amountBytesToDownload = value;
Debug.WriteLine("Property Changed: " + "AmountBytesToDownload");
AmountMBytesToDownload = value / 1024 / 1024;
}
}
public long AmountBytesDownloaded {
get {
return _amountBytesDownloaded;
}
set {
_amountBytesDownloaded = value;
AmountMBytesDownloaded = value / 1024 / 1024;
}
}
public int DownloadTime {
get {
return _downloadTime;
}
set {
_downloadTime = value;
RaisePropertyChanged();
}
}
/*
public bool IsDownloadAborted {
get {
return _isDownloadAborted;
}
set {
_isDownloadAborted = value;
RaisePropertyChanged();
}
}
*/
public long AmountMBytesDownloaded {
get {
return _amountMBytesDownloaded;
}
set {
_amountMBytesDownloaded = value;
RaisePropertyChanged();
}
}
public long AmountMBytesToDownload {
get {
return _amountMBytesToDownload;
}
set {
_amountMBytesToDownload = value;
RaisePropertyChanged();
}
}
public bool IsDownloading {
get {
return _isDownloading;
}
set {
_isDownloading = value;
RaisePropertyChanged();
}
}
internal void SwitchBooks(object o) {
Debug.WriteLine("SwitchBooksEx " + o);
if (o.ToString().Equals("Tessloff.ViewModelBooks")) {
((ViewModelBooks)_screens[0]).SwitchView();
Debug.WriteLine("SwitchBooksIn " + o);
}
}
}
public class CommandViewModel {
private MainWindowViewModel _viewmodel;
public CommandViewModel(MainWindowViewModel viewmodel) {
_viewmodel = viewmodel;
Debug.WriteLine("LALALALALA");
MenuCommand = new RelayCommand(o => {
Debug.WriteLine("CommandViewModel " + o);
_viewmodel.SwitchBooks(o);
});
DeleteCommand = new RelayCommand(o => {
Debug.WriteLine("Delte Command CVM" + o);
});
}
public ICommand MenuCommand {
get; set;
}
public ICommand DeleteCommand {
get; set;
}
public string Title {
get;
private set;
}
}
public class RelayCommand : ICommand {
#region Fields
readonly Action<object> _execute;
readonly Predicate<object> _canExecute;
#endregion // Fields
#region Constructors
public RelayCommand(Action<object> execute)
: this(execute, null) {
}
public RelayCommand(Action<object> execute, Predicate<object> canExecute) {
if (execute == null)
throw new ArgumentNullException("execute");
_execute = execute;
_canExecute = canExecute;
}
#endregion // Constructors
#region ICommand Members
[DebuggerStepThrough]
public bool CanExecute(object parameter) {
return _canExecute == null ? true : _canExecute(parameter);
}
public event EventHandler CanExecuteChanged {
add {
CommandManager.RequerySuggested += value;
}
remove {
CommandManager.RequerySuggested -= value;
}
}
public void Execute(object parameter) {
_execute(parameter);
}
#endregion // ICommand Members
}
public class ViewModelAdults {
public ViewModelAdults() {
Title = "Erwachsene";
ImgUrl = "/Resources/Erwachsene.png";
}
public string Title {
get; set;
}
public string ImgUrl {
get;
private set;
}
}
编辑tl; dr: 为什么MainWindowViewModel的所有“直接”属性都更新(如MainWindowViewModel.IsSearchResult),但两个“间接”属性没有(MainWindowViewModel.BluetoothManager.SelectedBluetoothResul t)。
答案 0 :(得分:0)
List.add()不会触发PropertyChange。您需要在添加项目后使用ObservableCollection或自己引发PropertyChange。