MainWindow.xaml
<Window
x:Class="Prüfstand_Gallerie.MainWindow"
xmlns=http://schemas.microsoft.com/winfx/2006/xaml/presentation
xmlns:x=http://schemas.microsoft.com/winfx/2006/xaml
xmlns:local="using:Prüfstand_Gallerie"
xmlns:d=http://schemas.microsoft.com/expression/blend/2008
xmlns:mc=http://schemas.openxmlformats.org/markup-compatibility/2006 xmlns:interactivity="using:Microsoft.Xaml.Interactivity" xmlns:core="using:Microsoft.Xaml.Interactions.Core"
mc:Ignorable="d">
<StackPanel VerticalAlignment="Center" HorizontalAlignment="Center">
<TextBlock Text="{x:Bind ViewModel.FirstName}"></TextBlock>
<Button Content="Change Name" Command="{x:Bind ViewModel.ChangeNameCommand}"></Button>
</StackPanel>
</Window>
MainWindow.xaml.cs
namespace Prüfstand_Gallerie
{
public sealed partial class MainWindow : Window
{
public MainWindow()
{
this.InitializeComponent();
}
public MainWindowViewModel ViewModel { get; } = new();
}
}
MainWindowViewModel.cs
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Prüfstand_Gallerie.ViewModels
{
public partial class MainWindowViewModel : ObservableObject
{
[ObservableProperty]
public string firstName = "Jack";
[RelayCommand]
public void ChangeName()
{
FirstName = "Tjark";
}
[RelayCommand]
private void SelectItem(object param)
{
}
}
}
I'm trying to implement the mvvm pattern with winUi3, but the property FirstName is not updating when the button is clicked, though the command is fired and the value changes as I can see while debugging. It does not change in the ui. Where is the problem?
x:Bind is OneTime by default. You need to explicitly set it to OneWay.
<TextBlock Text="{x:Bind ViewModel.FirstName, Mode=OneWay}" />
Related
What I want is to get the CommandParameter data when I click the button in the dynamically created data source.
First I create data for item source, then I bind it with binding, then I try to capture this click event with command.
Mainwindow.xaml
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:local="clr-namespace:lestplay"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800" Loaded="Window_Loaded">
<Window.Resources>
<Style TargetType="ItemsControl" x:Key="den2">
<Setter Property="SnapsToDevicePixels" Value="true" />
<Setter Property="UseLayoutRounding" Value="True" />
<Setter Property="ItemTemplate">
<Setter.Value>
<DataTemplate>
<StackPanel>
<Button x:Name="lestplaybutton" Command="{Binding DisplayMessageCommand}" CommandParameter="{Binding Id}" Width="100" Height="50" Content="Furkan" />
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Grid>
<ItemsControl x:Name="le2" Style="{DynamicResource den2}">
</ItemsControl>
</Grid>
</Window>
here is the view i use to bind Icommand
MessageViewModel.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
namespace lestplay
{
public class MessageViewModel
{
public List<Person> Persons { get; set; }
public MessageCommand DisplayMessageCommand { get; set; }
public MessageViewModel()
{
DisplayMessageCommand = new MessageCommand(DisplayMessage);
}
public void DisplayMessage(string messagetext)
{
MessageBox.Show(messagetext);
}
}
}
Person.cs
The class that will hold the data I want
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace lestplay
{
public class Person
{
public string Id { get; set; }
public string Name { get; set; }
public Person(string id, string name)
{
this.Id = id;
this.Name = name;
}
}
}
MessageCommand.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
namespace lestplay
{
public class MessageCommand : ICommand
{
public event EventHandler? CanExecuteChanged;
public Action<string> _execute;
public MessageCommand(Action<string> execute)
{
_execute = execute;
}
public bool CanExecute(object? parameter)
{
return true;
}
public void Execute(object? parameter)
{
_execute.Invoke(parameter as string);
}
}
}
MainWindow.xaml.cs
namespace lestplay
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
List<Person> prn = new List<Person>();
prn.Add(new Person() { Name = "furkan", Id = "ui-148782" });
le2.ItemsSource = prn;
DataContext = new MessageViewModel();
}
}
}
When adding ViewModels to an ObservableCollection, which is shown on the MainWindow as an ItemsControl with the ObservableCollection as the ItemsSource. The initial values of the View are displayed as null. I know this because on debugging and changing the value of the TextBox I see that the Name field is set to null, but when I press the button to add new ViewModels it is setting the Name field but then not displaying the name. This app has been condensed for ease of debugging. So it seems that while the ObservableCollection is communicating to the view it is not receiving the proper values somehow.
MainWindow
<Window x:Class="LifeCalculator.Views.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:prism="http://prismlibrary.com/"
prism:ViewModelLocator.AutoWireViewModel="True"
xmlns:myControl="clr-namespace:LifeCalculator.Views" xmlns:views="clr-namespace:LifeFinanceCalculator.Views"
Title="{Binding Title}" Height="350" Width="525">
<Grid>
<Button Margin="47,24,373,269" Content="Add ViewModels" Command="{Binding AddCommandItem}"/>
<ScrollViewer Margin="28,75,37,72">
<ItemsControl ItemsSource="{Binding ListExampleItems}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<views:exampleView/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
</Grid>
MainWindowViewModel
using Prism.Mvvm;
using System.Collections.ObjectModel;
using LifeFinanceCalculator.ViewModels;
using System.Windows.Input;
using Prism.Commands;
namespace LifeCalculator.ViewModels
{
public class MainWindowViewModel : BindableBase
{
private ObservableCollection<exampleViewModel> _listExampleItems;
public ObservableCollection<exampleViewModel> ListExampleItems
{
get => _listExampleItems;
set
{
SetProperty(ref _listExampleItems, value);
}
}
public ICommand AddCommandItem { get; set; }
public MainWindowViewModel()
{
_listExampleItems = new ObservableCollection<exampleViewModel>();
AddCommandItem = new DelegateCommand(ListItem);
}
private void ListItem()
{
_listExampleItems.Add(new exampleViewModel() { Name = "Chris" });
_listExampleItems.Add(new exampleViewModel() { Name = "Olivia" });
}
}
}
exampleView
<UserControl x:Class="LifeFinanceCalculator.Views.exampleView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:prism="http://prismlibrary.com/"
prism:ViewModelLocator.AutoWireViewModel="True">
<Grid>
<TextBox Text="{Binding Name}" FontSize="22"/>
</Grid>
</UserControl>
exampleViewModel
using Prism.Mvvm;
namespace LifeFinanceCalculator.ViewModels
{
public class exampleViewModel : BindableBase
{
private string _name;
public string Name
{
get => _name;
set
{
SetProperty(ref _name, value);
}
}
public exampleViewModel()
{
}
}
}
The ViewModelLocator used by Prism was the issue. The ViewModelLocator re-intializes the View with a new ViewModel. To solve the issue :
prism:ViewModelLocator.AutoWireViewModel = "False"
I have two WPF windows and i want to set the context to a ViewModel but if I write:
this.DataContext = new myViewModel()
in my second windows cs it doesn't work here is my code. i have tried to place a binding in the XAML and to connect the context but when i try to debug it all i get the error code this breakpoint will not get run.
BrowseDialog.xaml
<Window x:Class="TextalkApi.BrowseDialog"
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:local="clr-namespace:TextalkApi"
mc:Ignorable="d"
Title="BrowseDialog" Height="248.361" Width="427.459">
<Grid>
<Button Content="Browse" HorizontalAlignment="Left" Margin="267,11,0,0" VerticalAlignment="Top" Width="75"/>
<TextBox x:Name="FileDialog" HorizontalAlignment="Left" Height="23" Margin="10,10,0,0" TextWrapping="Wrap" Text="{Binding webUrl}" VerticalAlignment="Top" Width="244"/>
<Button Content="Save" HorizontalAlignment="Left" Margin="267,166,0,0" VerticalAlignment="Top" Width="75" Command="{Binding SaveCommand}" />
<TextBox HorizontalAlignment="Left" Height="23" Margin="10,38,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120"/>
<Label Content="{Binding errorMessage}" HorizontalAlignment="Left" Margin="10,167,0,0" VerticalAlignment="Top" RenderTransformOrigin="-5.611,10.822" Width="207" Height="19"/>
</Grid>
</Window>
BrowseViewModel
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Input;
using System.Threading;
using System.Threading.Tasks;
using System.Configuration;
using System.Collections.Specialized;
using System.IO;
namespace Data
{
public class BrowseViewModel : BaseViewModel
{
#region public variables
public string webUrl { get; set; }
public string errorMessage { get; set; }
#endregion
#region Public Commands
public ICommand SaveCommand { get; set; }
#endregion
#region Constructor
public BrowseViewModel()
{
this.SaveCommand = new RelayCommand(SaveFilePath);
}
#endregion
#region Private methods
private void SaveFilePath()
{
if (File.Exists(webUrl))
{
ConfigurationManager.AppSettings.Add("WebUrl", webUrl);
}
else
{
errorMessage = "Filen existerar ej";
}
}
#endregion
}
}
BrowseDialog.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.IO;
using Data;
namespace TextalkApi
{
/// <summary>
/// Interaction logic for BrowseDialog.xaml
/// </summary>
public partial class BrowseDialog : Window
{
public BrowseDialog()
{
InitializeComponent();
this.DataContext = new BrowseViewModel();
}
}
}
BaseViewModel
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
using PropertyChanged;
namespace Data
{
[AddINotifyPropertyChangedInterface]
public class BaseViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
}
}
Your XAML looks correct and I highly suspect it is the ViewModel causing it not to work. Something like this should work.
Please note that this will depend a lot on how the BaseViewModel has been implemented. If possible can you share this so I can update my answer to be correct? The below is how you should implement the properties in your ViewModel which is the DataContext of the View.
#region Properties
private string _webUrl;
public string WebUrl
{
get => _webUrl;
set
{
//This will change based on how you have implemented your BaseViewModel!
//The method name might be different, or have different parameters!
this.SetProperty(ref _webUrl, value, nameof(WebUrl));
//Call the save file path validation method...
SaveFilePath();
}
}
private string _errorMessage;
public string ErrorMessage
{
get => _errorMessage;
private set
{
//This will change based on how you have implemented your BaseViewModel!
//This method should call NotifyPropertyChange to notify the UI to update...
this.SetProperty(ref _errorMessage, value, nameof(ErrorMessage));
}
}
#endregion
In your ViewModelBase you can add a generic SetProperty method that can then handle raising the property changed event for you. Something like this:
public class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void SetProperty<T>(ref T storage, T value, string propertyName)
{
storage = value;
RaisePropertyChangedEvent(propertyName);
}
protected void RaisePropertyChangedEvent(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
and because of the changes in the ViewModel you will also need to update the bindings in your XAML.
<Grid>
<Button Content="Browse" HorizontalAlignment="Left" Margin="267,11,0,0" VerticalAlignment="Top" Width="75"/>
<TextBox x:Name="FileDialog" HorizontalAlignment="Left" Height="23" Margin="10,10,0,0" TextWrapping="Wrap" Text="{Binding WebUrl}" VerticalAlignment="Top" Width="244"/>
<Button Content="Save" HorizontalAlignment="Left" Margin="267,166,0,0" VerticalAlignment="Top" Width="75" Command="{Binding SaveCommand}" />
<TextBox HorizontalAlignment="Left" Height="23" Margin="10,38,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120"/>
<Label Content="{Binding ErrorMessage}" HorizontalAlignment="Left" Margin="10,155,0,0" VerticalAlignment="Top" RenderTransformOrigin="-5.611,10.822" Width="207" Height="46"/>
</Grid>
I make a simple weather app. And now i want to change it.
I want to implement a command to a button, and when is pressed, a TextBlock will update with weather info but i can't acces property of TextBlock.
Here is the Command class from Models:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
namespace RemakeWindowsWeather.Models
{
public class Command : ICommand
{
public event EventHandler CanExecuteChanged;
Func<object, bool> canExecuteMethod;
Action<object> executeMethod;
public Command(Func<object, bool> canExecuteMethod, Action<object> executeMethod)
{
this.canExecuteMethod = canExecuteMethod;
this.executeMethod = executeMethod;
}
public bool CanExecute(object parameter)
{
return canExecuteMethod(parameter);
}
public void Execute(object parameter)
{
executeMethod(parameter);
}
}
}
Here is the class from ViewModels where i want to change the property of TextBlock:
using RemakeWindowsWeather.Models;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace RemakeWindowsWeather.ViewModels
{
public class CommandViewModel
{
Command ShowWeather { get; set; }
public CommandViewModel()
{
ShowWeather = new Command(canExecuteMethod, executeMethod);
}
private bool canExecuteMethod(object parameter)
{
return true;
}
private async void executeMethod(object parameter)
{
var pos = await LocationManager.GetLocation();
var lat = pos.Coordinate.Latitude;
var lon = pos.Coordinate.Longitude;
var weather = await WeatherProxyMap.GetWeather(lon, lat);
//HERE.. not working
WeatherCondition.Text = weather.main.temp + " " + weather.name;
}
}
}
Here is the XAML:
<Page
x:Class="RemakeWindowsWeather.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:RemakeWindowsWeather"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
x:Name="MyPage">
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<StackPanel>
<Button Height="30"
Width="120"
Click="Button_Click"
Content="Get Weather"/>
<TextBlock Name="WeatherCondition"
Margin="0,20,0,20"/>
<TextBox Name="CitySearch"
PlaceholderText="Search for weather.."
Margin="0,20,0,20"/>
<Button Width="120"
Height="30"
Click="Button_Click_1"
Content="Get Weather"/>
<TextBlock Name="CityNameTxtBlock"/>
</StackPanel>
</Grid>
You need to bind your command from the viewmodel in xaml, instead using event handlers in the view.
<Button Width="120"
Height="30"
Command="{Binding ShowWeather}"
Content="Get Weather"/>
Also the command should be public and you need a text property
public Command ShowWeather { get; set; }
public string WeatherText { get; set; }
Then you need to bind the text from the viewmodel in the view.
<TextBlock Name="WeatherCondition" Margin="0,20,0,20" Text="{Binding WeatherText}"/>
also you would need to implement INotifyPropertyChanged in the viewmodel and call it when you modify the text.
WeatherText= weather.main.temp + " " + weather.name;
this.RaisePropertyChanged("WeatherText");
This pretty much basic MVVM which you can read about from here.
I am writing an application for Windows Phone 8.1, and I wanted to use a flyout on listView item. Because I am doing my best to write nice app, I am trying to use MVVM pattern and resource dictionaries with templates insead of all xaml in one page.
However, I can't bind my MenuFlyoutItem Command - it seems like it doesn't see the datacontext of the page, or it has some other dataContext. Here is some code:
1) My template in a separate resource dictionary:
<Grid Margin="0, 0, 0, 10">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="4*" />
</Grid.ColumnDefinitions>
<Grid.Resources>
<converters:BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
<converters:EmptyDateConverter x:Key="EmptyDateConverter" />
</Grid.Resources>
<i:Interaction.Behaviors>
<icore:EventTriggerBehavior EventName="Holding">
<converters:OpenMenuFlyoutAction />
</icore:EventTriggerBehavior>
</i:Interaction.Behaviors>
<FlyoutBase.AttachedFlyout>
<MenuFlyout>
<MenuFlyoutItem x:Uid="AddToCalendarMenuItem" Command="{Binding AddToCalendar}" />
</MenuFlyout>
</FlyoutBase.AttachedFlyout>
<Image Grid.Column="0" Source="{Binding ThumbnailUri}"/>
<StackPanel Grid.Column="1" Orientation="Vertical" Margin="10,0,0,0">
<TextBlock Text="{Binding Title}" Style="{StaticResource ListItemTitle}"/>
<StackPanel Orientation="Horizontal" VerticalAlignment="Bottom">
<TextBlock x:Uid="DvdReleaseDate" />
<TextBlock Text="{Binding DvdRelease, Converter={StaticResource EmptyDateConverter}}" />
</StackPanel>
</StackPanel>
</Grid>
2) And here is the list view:
<ListView Grid.Row="1" x:Name="SearchListView"
ItemsSource="{Binding SearchList}"
ItemTemplate="{StaticResource SearchListTemplate}" SelectionChanged="NavigateToMovieDetails" />
My ViewModel is a static kind of singleton in the app.xaml.cs
I've tried to create a new instance of the VM in xaml, but it didn't work - maybe I was doing smth wrong.
I would really appreciate Your help! Thanks in advance.
Best regards,
Roman
If you stick with that <ItemTemplate> you will have to have a Command per every Model in your ViewModel, which is not ideal.
To set a single Command and have a CommandParameter see this SO Tutorial I made it is too much code to type here:
Implement a ViewModel Single Command with CommandParamater
#Chubosaurus Software following your approach I came up with this.
Here is a ListView bound to a list of todo items placed inside a DataTemplate which contains a TextBlock having a MenuFlyout to show edit, delete context menu kind of thing.
The key to bind the commands in the view model to the MenuFlyoutItem is to give the ListView a name and do element binding using the ElementName property in the Command to point to the ListView's name. To access the commands in our view model we've to go through the ListView's DataContext and bind it to a command on it because the DataContext of the MenuFlyoutItem is an item in the ItemsSource
The MainPage.xaml
<Page
x:Class="UWA.MenuFlyout.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:UWA.MenuFlyout"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="using:UWA.MenuFlyout.ViewModels"
xmlns:interactivity="using:Microsoft.Xaml.Interactivity"
xmlns:core="using:Microsoft.Xaml.Interactions.Core"
xmlns:common="using:UWA.MenuFlyout.Core"
mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid Margin="24,24">
<ListView x:Name="Todos" ItemsSource="{Binding Todos}">
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Action}">
<FlyoutBase.AttachedFlyout>
<MenuFlyout>
<MenuFlyoutItem Text="edit"
Command="{Binding ElementName=Todos, Path=DataContext.EditTodo}"
CommandParameter="{Binding}"/>
<MenuFlyoutItem Text="delete"
Command="{Binding ElementName=Todos, Path=DataContext.DeleteTodo}"
CommandParameter="{Binding}"/>
</MenuFlyout>
</FlyoutBase.AttachedFlyout>
<interactivity:Interaction.Behaviors>
<core:EventTriggerBehavior EventName="Holding">
<common:OpenMenuFlyoutAction/>
</core:EventTriggerBehavior>
<core:EventTriggerBehavior EventName="RightTapped">
<common:OpenMenuFlyoutAction/>
</core:EventTriggerBehavior>
</interactivity:Interaction.Behaviors>
</TextBlock>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
</Page>
The MainPage.xaml.cs is where the DataContext of the MainPage is set.
namespace UWA.MenuFlyout
{
using UWA.MenuFlyout.ViewModels;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;
/// <summary>
/// An empty page that can be used on its own or navigated to within a Frame.
/// </summary>
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
this.NavigationCacheMode = NavigationCacheMode.Required;
this.DataContext = new MainViewModel();
}
/// <summary>
/// Invoked when this page is about to be displayed in a Frame.
/// </summary>
/// <param name="e">Event data that describes how this page was reached.
/// This parameter is typically used to configure the page.</param>
protected override void OnNavigatedTo(NavigationEventArgs e)
{
// TODO: Prepare page for display here.
// TODO: If your application contains multiple pages, ensure that you are
// handling the hardware Back button by registering for the
// Windows.Phone.UI.Input.HardwareButtons.BackPressed event.
// If you are using the NavigationHelper provided by some templates,
// this event is handled for you.
}
}
}
The MainViewModel.cs containing the Todos which is an ObservableCollection type and the EditTodo and DeleteTodo commands.
namespace UWA.MenuFlyout.ViewModels
{
using System.Collections.ObjectModel;
using System.Windows.Input;
using UWA.MenuFlyout.Core;
using UWA.MenuFlyout.Models;
public class MainViewModel : BaseViewModel
{
private ICommand editTodo;
private ICommand deleteTodo;
public MainViewModel()
{
this.Todos = new ObservableCollection<TodoModel>
{
new TodoModel { Id = 1, Action = "Buy Milk", IsDone = true },
new TodoModel { Id = 2, Action = "Buy Groceries", IsDone = false }
};
}
public ObservableCollection<TodoModel> Todos { get; set; }
public ICommand EditTodo
{
get
{
if (this.editTodo == null)
{
this.editTodo = new RelayCommand(this.OnEditTodo);
}
return this.editTodo;
}
}
public ICommand DeleteTodo
{
get
{
if (this.deleteTodo == null)
{
this.deleteTodo = new RelayCommand(this.OnDeleteTodo);
}
return this.deleteTodo;
}
}
public void OnEditTodo(object parameter)
{
// perform edit here
var todo = parameter as TodoModel;
}
public void OnDeleteTodo(object parameter)
{
// perform delete here
var todo = parameter as TodoModel;
}
}
}
The Model
namespace UWA.MenuFlyout.Models
{
public class TodoModel
{
public int Id { get; set; }
public string Action { get; set; }
public bool IsDone { get; set; }
}
}
The BaseViewModel which implements the INotifyPropertyChanged.
namespace UWA.MenuFlyout.Core
{
using System.ComponentModel;
using System.Runtime.CompilerServices;
public class BaseViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public virtual void OnPropertyChanged([CallerMemberName] string propertyName = "")
{
if (this.PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
}
A simple ICommand implementation.
namespace UWA.MenuFlyout.Core
{
using System;
using System.Windows.Input;
public class RelayCommand : ICommand
{
private Action<object> action;
public RelayCommand(Action<object> action)
{
this.action = action;
}
public event EventHandler CanExecuteChanged;
public bool CanExecute(object parameter)
{
return true;
}
public void Execute(object parameter)
{
this.action(parameter);
}
}
}
The OpenMenuFlyoutAction which implements DependencyObject and IAction to open the MenuFlyout by using the Execute method on the IAction interface.
namespace UWA.MenuFlyout.Core
{
using Microsoft.Xaml.Interactivity;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls.Primitives;
public class OpenMenuFlyoutAction : DependencyObject, IAction
{
public object Execute(object sender, object parameter)
{
var frameworkElement = sender as FrameworkElement;
var flyoutBase = FlyoutBase.GetAttachedFlyout(frameworkElement);
flyoutBase.ShowAt(frameworkElement);
return null;
}
}
}