#c# #wpf #xaml
#c# #wpf ( ВП ) #xaml #wpf
Вопрос:
Я уже некоторое время пытаюсь перенести свой проект в MVVM.
Есть DataTable, который я получаю из базы данных:
Основной процесс.cs:
public static DataTable CustomersInLiinos = new DataTable();
public static void MergedTable()
{
var t1 = ConnectAndRetriveDatatatableS(); // t1
var t2 = ConnectAndRetriveDatatatableF(); // t2
CustomersInLiinos = t1.Copy();
CustomersInLiinos.Merge(t2);
}
ViewModel.cs — Просмотр модели.cs:
private async Task ExecuteLoadMainTableDataAsync(object commandParameter)
{
if (MainProcess.CheckForVPNInterface())
{
if (MainProcess.CustomersInLiinos != null)
{
this.HasProgress = true;
IEnumerable<Item> resultItems = await LoadMainTableDataAsync();
this.Items = new ObservableCollection<Item>(resultItems);
EnableItemsFiltering();
this.HasProgress = false;
}
}
else
{
throw new VpnInterfaceException("Please, check your VPN connection!");
}
}
Внутри ViewModel.cs у меня также есть это:
public Task<DataView> LoadMainTableDataAsync()
{
return Task.Run(() =>
{
MainProcess.MergedTable();
return MainProcess.CustomersInLiinos.DefaultView;
});
}
В настоящее время у меня возникает ошибка, указывающая на await LoadMainTableDataAsync();
:
Описание кода серьезности Ошибка состояния подавления строки файла проекта CS0266 Не удается неявно преобразовать тип ‘System.Data.DataView’ в ‘System.Коллекции.Общий.IEnumerable<Liinos_inspector_FilterTest.Item>’. Существует явное преобразование (вам не хватает приведения?)
Я понимаю, что есть ошибка в LoadMainTableDataAsync
? Я загружаю данные в DataView и вместо этого должен загружать в IEnumerable?
Было бы проще использовать это:
public class JoinedFandS
{
public string YRNRO { get; set; }
public string HAKUNIMI { get; set; }
public string NIMIA { get; set; }
public string NIMIB { get; set; }
}
public static IEnumerable<JoinedFandS> GetMyJoinedResult()
{
var t1 = ConnectAndRetriveDatatatableS(); // t1
var t2 = ConnectAndRetriveDatatatableF(); // t2
var firstTable = ...
var secondTable = ...
var results = firstTable.Concat(secondTable);
return results;
}
Редактировать:
<Window x:Class="Liinos_inspector_FilterTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:Liinos_inspector_FilterTest="clr-namespace:Liinos_inspector_FilterTest"
mc:Ignorable="d"
Title="Liinos database inspector" Height="672" Width="1000" Icon="Images/logo_icon-small.jpg" Background="White" MinWidth="1000">
<Window.DataContext>
<ViewModel />
</Window.DataContext>
Описание кода серьезности Состояние подавления строки файла проекта
Ошибка XLS0414 Тип ‘ViewModel’ не найден. Убедитесь, что вы являетесь
не пропущена ссылка на сборку и что все сборки, на которые даны ссылки
были построены. Liinos инспектор фильтрует MainWindow.xaml 11
и
Описание кода серьезности Ошибка состояния подавления строки файла проекта XDG0008 ViewModel не поддерживается в проекте Windows Presentation Foundation (WPF). Инспектор Liinos фильтрует MainWindow.xaml 11
Что я должен использовать вместо ViewModel?
Комментарии:
1. Мы могли бы сделать и с вашим xaml. Является ли MainProcess какой-то статической глобальной переменной? (Этого следует избегать). Вам не нужно возвращать DefaultView в
LoadMainTableDataAsync
. Все, что вам нужно, это вернуть DataTable или, что еще лучше, создать модель и использовать ее вместо этого.2. Это следующий вопрос. Я думаю, вы должны были задать правильный вопрос с надлежащим контекстом раньше. Для правильного ответа на этот вопрос также не хватает большого контекста. Вы должны были добавить контекст вашего предыдущего вопроса. Устранение этой ошибки приведет к нарушению решения вашего предыдущего вопроса.
3. Эй, большое вам спасибо за то, что вы начали раздачу наград за этот вопрос, чтобы почтить мой ответ дополнительными очками репутации. Я действительно ценю ваш жест. Большое вам спасибо. Это очень, очень любезно с вашей стороны.
4. @BionicCode Было много вопросов, я не знал, какой из них выбрать. Большое вам спасибо за вашего пациента и помощь! Теперь я снова немного поумнел, но еще многому нужно научиться. Я занимаюсь программированием в свободное время помимо своей обычной работы. Однако я надеюсь, что однажды я достигну такого уровня, чтобы действительно давать советы другим =))
Ответ №1:
Это несоответствие типов данных. Вы не можете нажать DataView
в коллекцию. Также более практично хранить DataTable
вместо DataView
. Дешевле получить представление из таблицы, чем получать таблицу из представления (на случай, если вам понадобится поработать с DataTable
позже).
Для исправления этой ошибки также необходимо исправить фильтрацию.
DataGrid
может обрабатывать DataTable
напрямую.
Обратите внимание, что вы должны await
возвращать значение LoadMainTableDataAsync
. В противном случае этот метод вернул бы результат преждевременно (поскольку результат вычисляется в фоновом потоке). Я уверен, что эта часть вашего кода даже не компилируется. Возможно, это просто пример кода.
В этом примере также настраивается фильтрация на основе новой структуры данных. Для фильтрации DataTable.DataView
вы должны использовать DataView.RowFilter
свойство (см. справку в разделе Синтаксис выражения). Вам необходимо настроить фактическую логику фильтра в соответствии с вашими требованиями:
ViewModel.cs
class ViewModel : INotifyPropertyChanged
{
public ICommand LoadMainTableDataCommand => new RelayCommand(async param => ExecuteLoadMainTableDataAsync());
private DataTable mainDataTable;
public DataTable MainDataTable
{
get => this.mainDataTable;
set
{
this.mainDataTable = value;
OnPropertyChanged();
// Set the DataTable filter expression
EnableRowFiltering();
}
}
// Binding source for the first name TextBox
private string firstNameSearchKey;
public string FirstNameSearchKey
{
get => this.firstNameSearchKey;
set
{
this.firstNameSearchKey = value;
OnPropertyChanged();
// Refresh the DataTable filter expression
EnableRowFiltering();
}
}
// Binding source for the last name TextBox
private string lastNameSearchKey;
public string LastNameSearchKey
{
get => this.lastNameSearchKey;
set
{
this.lastNameSearchKey = value;
OnPropertyChanged();
// Refresh the DataTable filter expression
EnableRowFiltering();
}
}
private bool hasProgress;
public bool HasProgress
{
get => this.hasProgress;
set
{
this.hasProgress = value;
OnPropertyChanged();
}
}
public void EnableRowFiltering()
{
// The filter assumes a column 'FirstName' and a column 'LastName' in the DataView.
// The filter expression mimics string.StartsWith.
this.MainDataTable.DefaultView.RowFilter =
$"FirstName LIKE '{this.FirstNameSearchKey}*' "
$"OR LastName LIKE '{this.LastNameSearchKey}*'";
}
private async Task ExecuteLoadMainTableDataAsync()
{
if (MainProcess.CheckForVPNInterface())
{
if (MainProcess.Customers != null)
{
this.HasProgress = true;
this.MainDataTable = await LoadMainTableDataAsync();
this.HasProgress = false;
}
}
else
{
throw new VpnInterfaceException("Please, check your VPN connection!");
}
}
public async Task<DataTable> LoadMainTableDataAsync()
{
return await Task.Run(() =>
{
MainProcess.MergedTable();
return MainProcess.CustomersInLiinos;
});
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
=> this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
MainWindow.xaml
<Window>
<Window.DataContext>
<ViewModel />
</Window.DataContext>
<Window.Resources>
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
</Window.Resources>
<StackPanel>
<ProgressBar IsIndeterminate="True"
Visibility="{Binding HasProgress, Converter={StaticResource BooleanToVisibilityConverter}}" />
<Button Command="{Binding LoadMainTableDataCommand}"
Content="Load Data" />
<TextBox Text="{Binding FirstNameSearchKey}" />
<TextBox Text="{Binding LastNameSearchKey}" />
<DataGrid ItemsSource="{Binding MainDataTable}" />
<StackPanel>
</Window>
Комментарии:
1. Еще раз спасибо! Я думаю, что я довольно близок к чему-то, что, надеюсь, сработает, и я смогу продолжить свое обучение. В настоящее время у меня осталось две ошибки,
this.MainDataTable.DataView.RowFilter
говорящиеDataTable' does not contain a definition for 'DataView' and no accessible extension method 'DataView' accepting a first argument of type 'DataTable' could be found
, иnew RelayCommand(ExecuteLoadMainTableDataAsync)
я предполагаю, что для этого мне нужен новый класс. Я создал его, но, вероятно, сделал что-то не так.2. Добро пожаловать. Я использовал неправильное (несуществующее) свойство. Вместо этого должно быть
DefaultView
. Я обновил пример. ДляRelayCommand
вы можете скопировать эту реализацию из Microsoft и использоватьnew RealyCommand(async param => await ExecuteLoadMainTableDataAsync())
. Или , в качестве альтернативы , добавьте перегрузку конструктора , которая принимаетFunc<object, Task>
.3. Похоже, это тоже можно удалить
object commandParameter
? Теперь ошибок нет. Я постараюсь проверить.4. Можете проверить, находится ли модель представления, которая определяет команду, в
DataContext
вашем представлении? Как вы устанавливаете DataContext?5. Я обновил свой ответ. Я думаю, проблема в том, что
MainDataTable
свойство меняется, но поскольку автоматическое свойство не вызывалоINotifyPropertyChanged.PropertyChanged
событие,DataGrid
привязка никогда не обновляется. Теперь я превратил свойство в свойство с уведомлением об изменении. Теперь все должно работать. В ходе этого вопроса было переработано так много вещей, что некоторые ошибки возникли из-за того, что я забыл настроить определенный код. Я прошу прощения за это. Дайте мне знать, если все еще есть какие-либо проблемы, но их не должно быть.