C#:
class ViewModelsWindow2 : INotifyPropertyChanged
{
private List<BookBase> _listBase;
private ObservableCollection<Tab> _tabs;
public List<BookBase> ListBase {...} // It's for work and serialization to file.
public ObservableCollection<Tab> Tabs {...} // It's for binding to WPF.
public ViewModelsWindow2()
{
ListBase = new List<BookBase>()
{
new BookBase() { Author="Mark Twain", Name="The Adventures of Tom Sawyer"},
new BookBase() { Author="Mark Twain", Name="Adventures of Huckleberry Finn"}
};
var newTab = new Tab()
{
Header = "New",
BookBase = ListBase,
AddBook = new Command(o => { MessageBox.Show("!"); ListBase.Add(new BookBase() { Author = "", Name = "" }); })
};
Tabs = new ObservableCollection<Tab>();
Tabs.Add(newTab);
}
}
Вспомогательные классы:
public class Tab
{
public string Header { get; set; }
public List<BookBase> BookBase { get; set; }
public Command AddBook { get; set; }
public Tab()
{
Header = null;
BookBase = new List<BookBase>();
AddBook = null;
}
}
public class BookBase
{
public string Author { get; set; }
public string Name { get; set; }
public BookBase()
{
Author = null;
Name = null;
}
}
XAML:
<Window
x:Class="WpfApp1.Views.Window2"
...
xmlns:local="clr-namespace:WpfApp1.Views"
...
xmlns:vm="clr-namespace:WpfApp1.ViewModels"
...
mc:Ignorable="d">
<Window.DataContext>
<vm:ViewModelsWindow2 />
</Window.DataContext>
<Grid>
<TabControl Grid.Column="0" ItemsSource="{Binding Tabs}">
<TabControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Header}" />
</DataTemplate>
</TabControl.ItemTemplate>
<TabControl.ContentTemplate>
<DataTemplate>
<Grid Margin="5">
<Grid.RowDefinitions>
<RowDefinition Height="25" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid Grid.Row="0">
<Button Command="{Binding AddBook}" Content="Continue" />
</Grid>
<DataGrid Grid.Row="1" AutoGenerateColumns="False" CanUserAddRows="False" ItemsSource="{Binding BookBase}">
<DataGrid.Columns>
<DataGridTextColumn MinWidth="70" Binding="Binding Author}" Header="Author" />
<DataGridTextColumn MinWidth="100" Binding="{Binding Name}" Header="Name" />
</DataGrid.Columns>
</DataGrid>
</Grid>
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
</Grid>
</Window>
Вообщем не получается заставить эту программу нормально работать, решил обратиться к сообществу.
Суть в том, что не работает кнопка добавления строк. Также не влияет добавляю я к ObservableCollection
или к List
. Кнопка не работает при обоих вариантах.
Восросы:
AddBook
находилась в основном класе, а не в классе Tab
, а вызывальсь из XAML с того же места, что и сейчас. Не вижу смысла плодить комманду, если она делает одну и ту же функцию. Скажу проще, возможно изменить XAML, что бы перенисти комману в основной класс?Также не влияет добавляю я к ObservableCollection или к List . Кнопка не работает при обоих вариантах.
Основная ваша проблема в том, что вы привязываетесь к List<T>
, которому зачем то пытаетесь реализовать не тот интерфейс. List<T>
- что это, коллекция или свойство? А INotifyPropertyChanged
- за что отвечает, за коллекцию или за свойство?
Вердикт таков: Хотите мучать мозг - реализовывайте INotifyCollectionChanged
, не хотите - переделывайте все на уже реализующие данный интерфейс коллекции (ObservableCollection
или BindingList
). В данном случае вы данные добавляете, но интерфейс не знает о том, что коллекция обновилась.
P.S. Проверил весь ваш код изменил все List<T>
на ObservableCollection<T>
и о чудо, данные появляются!.
Хорошо, давайте теперь поговорим о коде:
ICommand
интерфейса, а не класса, который ее реализует.INotifyPropertyChanged
лучше вынести в отдельный класс (дабы не дублировать его по сотни раз). P.S. Я его вынесу, но он вам не нужен, по этому закомментирую его наследование.Исходя из этого мы получаем такой код:
public class Tab
{
public string Header { get; set; }
public ObservableCollection<BookBase> BookBase { get; set; }
public ICommand AddBook { get; set; }
public Tab(string header, ObservableCollection<BookBase> bookBase, ICommand addBook = null)
{
Header = header;
BookBase = bookBase;
AddBook = addBook;
}
}
public class BookBase
{
public string Author { get; set; }
public string Name { get; set; }
public BookBase(string author, string name)
{
Author = author;
Name = name;
}
}
public class ViewBase : INotifyPropertyChanged
{
internal void RaisePropertyChanged(string property)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(property));
}
public event PropertyChangedEventHandler PropertyChanged;
}
public class ViewModelsWindow2 /*: ViewBase*/
{
public ObservableCollection<BookBase> ListBase { get; set; }
public ObservableCollection<Tab> Tabs { get; set; }
private ICommand AddCommand { get; }
public ViewModelsWindow2()
{
AddCommand = new RelayCommand(Add);
ListBase = new ObservableCollection<BookBase>()
{
new BookBase("Mark Twain", "The Adventures of Tom Sawyer"),
new BookBase("Mark Twain", "Adventures of Huckleberry Finn")
};
Tabs = new ObservableCollection<Tab> { new Tab("New", ListBase, AddCommand) };
}
private void Add()
{
MessageBox.Show("!");
ListBase.Add(new BookBase("", ""));
}
}
Теперь что касается команды в главном классе:
В паттерне MVVM каждый VM должен отвечать за что то одно, у вас идет отдельно реализация VM вкладок и все, что касается именно вкладок должно быть внутри VM. Вы можете инициализировать команду в другом месте и передавать на нее ссылку в нужный VM (как собственно сделал я в коде выше), но не изменять пути путем XAML кода, это не правильно!
Оборудование для ресторана: новинки профессиональной кухонной техники
Частный дом престарелых в Киеве: комфорт, забота и профессиональный уход
Возникла задача отправлять email напрямую из программыПо мимо просто текста прикреплять файл лога к письму
Как выгрузить данные из databasebak в базу данных? Иcпользую ASP
Хотелось бы сократить время "вникания" в новый проект на 500+ классовЕсть ли какая то возможность в Unity, или просто в проекте Visual Studio, наглядно...