#c# #wpf #mvvm
#c# #wpf #mvvm
Вопрос:
Я новичок в C # и WPF и получил задание запрограммировать сигнал тревоги. Теперь у меня проблема в том, что я должен сохранять установленное время в текстовый файл при закрытии mainwindow.
Время сохраняется в ObservableCollection типа Reminder, класса, который я написал сам, и сохраняет время и имя будильника в виде строки.
public override string ToString()
{
return ReminderName " " ReminderTime.ToString("HH:mm");
}
Моя функция сохранения выглядит следующим образом:
...
public RelayCommand<object> SaveAllTimes { get; set; }
...
public MainWindowModel()
{
...
SaveAllTimes = new RelayCommand<object>(SaveReminders, CanSaveReminders);
...
}
private void SaveReminders(object sender)
{
StreamWriter writer = new StreamWriter("time.txt");
foreach (Reminder time in Reminders)
{
writer.WriteLine(time.ToString());
}
}
Теперь, как я могу привязать представление к этой функции, чтобы оно выполнялось, когда пользователь закрывает его?
Мое представление выглядит так:
<Window x:Class="Wecker1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Wecker1"
Height="350"
Width="310" >
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="3*" />
<RowDefinition Height="1*" />
</Grid.RowDefinitions>
<ListBox Name="Liste" ItemsSource="{Binding Reminders}" Margin="10" Grid.Row="0">
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox Content="{Binding}" IsChecked="{Binding Active}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<Grid Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="1*"/>
</Grid.ColumnDefinitions>
<Button Command="{Binding SaveTime}" Content="Add Reminder" Margin="10" Grid.Column="1"/>
<Button Margin="10" Content="Stop" Command="{Binding DeleteTime}"
CommandParameter="{Binding ElementName=Liste,Path=SelectedItem}" />
</Grid>
</Grid>
</Window>
Ответ №1:
вот мой подход, использующий чистый MVVM, не зависящий от какого-либо другого поставщика
xaml
<Window x:Class="CSharpWPF.ViewModel"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:l="clr-namespace:CSharpWPF"
l:MyEventHandler.ClosingCommand="{Binding SaveAllTimes}">
</Window>
Класс MyEventHandler
namespace CSharpWPF
{
public class MyEventHandler
{
public static ICommand GetClosingCommand(DependencyObject obj)
{
return (ICommand)obj.GetValue(ClosingCommandProperty);
}
public static void SetClosingCommand(DependencyObject obj, ICommand value)
{
obj.SetValue(ClosingCommandProperty, value);
}
// Using a DependencyProperty as the backing store for ClosingCommand. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ClosingCommandProperty =
DependencyProperty.RegisterAttached("ClosingCommand", typeof(ICommand), typeof(MyEventHandler), new PropertyMetadata(OnClosingCommandChanged));
private static void OnClosingCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
Window window = d as Window;
window.Closing = (s, ee) => GetClosingCommand(d).Execute(ee);
}
}
}
итак, вся идея состоит в том, чтобы направлять события в привязанные команды через Attached Properties
, вы можете создавать больше обработчиков по мере необходимости
Ответ №2:
Где-то в вашем коде вы создаете свой View и ViewModel. С моей точки зрения (и эта часть, безусловно, основана на мнении), вы должны реализовать там свой код при выходе, потому что сохранение данных происходит в конце процесса, а не в конце представления. Когда ваш MainWindow был запущен, вы можете вызвать метод viewmodel для сохранения всех соответствующих данных.
Если вы хотите иметь его при закрытии представления вместо завершения программы, вы можете пойти двумя путями: темная сторона, написав кодовый обработчик OnClose для окна. Никому не говорите, что я так сказал. Это не стиль WPF. Или правильный путь путем реализации поведения закрытия для вашего окна. Это слишком широко для одного поста, вам следует посмотреть WPF, View и Behavior, вы найдете множество руководств для разных поведений.
Ответ №3:
Вы можете использовать интерактивность для привязки Closing
события к вашему Command
, как показано ниже
<Window xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Closing">
<i:InvokeCommandAction Command="{Binding SaveAllTimes }"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Window>