Ok, so I'm trying to figure out how to set a status bars label text to show information about the current control that a mouse is hovering over. I have seen this numerous times on many programs so I know it can be done and I'm sure there are explanations out there that could help me but I can't seem to find the right words to search for the answer unfortunately...
The closest thing I could find was in the link below. I tried to utilize this but it gave me an error when I tried to set the text property.
Anyone have some information or a link to help me by chance?
Thanks,
Ryan
Display text in a label when hovering over a control without using events
My XAML Code:
<StatusBar>
<StatusBar.ItemsPanel>
<ItemsPanelTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="75" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
</Grid>
</ItemsPanelTemplate>
</StatusBar.ItemsPanel>
<StatusBarItem Grid.Column="0">
<Label Content="New Lead Inquiry" />
</StatusBarItem>
<Separator Grid.Column="1" Style="{StaticResource StylingStatusBarSeparator}" />
<StatusBarItem Grid.Column="2">
<Label x:Name="infoStatusBar" Content="Label for text about the currently hovered item" />
</StatusBarItem>
<Separator Grid.Column="3" Style="{StaticResource StylingStatusBarSeparator}" />
<StatusBarItem Grid.Column="4">
<Label Content="Not Saved" />
</StatusBarItem>
</StatusBar>
Here's a solution that doesn't require you to modify each child control or use any frameworks.
This isn't really related to MVVM, since it's pure UI stuff. There's nothing here that would involve a viewmodel.
Handle Window.PreviewMouseMove:
MainWindow.xaml
<Window
...
PreviewMouseMove="Window_PreviewMouseMove"
>
MainWindow.xaml.cs
Define a dependency property of type Object, and in the preview mousemove handler, give it the nearest parent tooltip of the control the mouse is over:
private void Window_PreviewMouseMove(object sender, MouseEventArgs e)
{
var element = Mouse.DirectlyOver as FrameworkElement;
HoverToolTip = GetTooltip(element);
}
#region HoverToolTip Property
public object HoverToolTip
{
get { return (object)GetValue(HoverToolTipProperty); }
set { SetValue(HoverToolTipProperty, value); }
}
public static readonly DependencyProperty HoverToolTipProperty =
DependencyProperty.Register(nameof(HoverToolTip), typeof(object), typeof(MainWindow),
new PropertyMetadata(null));
#endregion HoverToolTip Property
protected static Object GetTooltip(FrameworkElement obj)
{
if (obj == null)
{
return null;
}
else if (obj.ToolTip != null)
{
return obj.ToolTip;
}
else
{
return GetTooltip(VisualTreeHelper.GetParent(obj) as FrameworkElement);
}
}
And bind that to whatever in the XAML.
<Label
x:Name="StatusBar"
Content="{Binding HoverToolTip, RelativeSource={RelativeSource AncestorType=Window}}"
Grid.Row="2"
/>
That Label is just the quickie I put in my test XAML. This binding is the important part there:
{Binding HoverToolTip, RelativeSource={RelativeSource AncestorType=Window}}
You can wire the MouseEnter and MouseLeave commands on your controls to set a HelpText property in your viewmodel, and then bind the status bar label to HelpText so that when it is set to something new, the new value appears in the status bar.
This answer uses the MVVM Light toolkit, but should be adaptable for any MVVM setup:
In XAML:
<Window x:Class="MvvmLightPlayground.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:ignore="http://www.galasoft.ch/ignore"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
mc:Ignorable="d ignore"
Height="300"
Width="600"
Title="MVVM Light Application">
<Window.DataContext>
<Binding Path="Main" Source="{StaticResource Locator}" />
</Window.DataContext>
<StackPanel>
<Label Content="This is Label1" x:Name="Label1">
<!-- Triggers like this are easy to wire up using blend. If you do it manually, add the i: definition to your window tag as shown above -->
<i:Interaction.Triggers>
<i:EventTrigger SourceName="Label1" EventName="MouseEnter">
<i:InvokeCommandAction Command="{Binding MouseEnter}" CommandParameter="This is Label1. Look how neat it is!" />
</i:EventTrigger>
<i:EventTrigger SourceName="Label1" EventName="MouseLeave">
<i:InvokeCommandAction Command="{Binding MouseLeave}" CommandParameter="This is Label1. Look how neat it is!" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Label>
<Label Content="This is Label2" x:Name="Label2">
<i:Interaction.Triggers>
<i:EventTrigger SourceName="Label2" EventName="MouseEnter">
<i:InvokeCommandAction Command="{Binding MouseEnter}" CommandParameter="This is Label2. It's a different label." />
</i:EventTrigger>
<i:EventTrigger SourceName="Label2" EventName="MouseLeave">
<i:InvokeCommandAction Command="{Binding MouseLeave}" CommandParameter="This is Label2. It's a different label." />
</i:EventTrigger>
</i:Interaction.Triggers>
</Label>
<StatusBar>
<StatusBar.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</StatusBar.ItemsPanel>
<StatusBarItem>
<Label Content="{Binding HelpText, Mode=OneWay}" /> <!-- Bind to your HelpText property in the VM -->
</StatusBarItem>
</StatusBar>
</StackPanel>
</Window>
In your viewmodel:
First, add properties for your HelpText and your ICommands:
private string _helpText = "Testing";
public string HelpText
{
get
{
return _helpText;
}
set
{
Set(() => HelpText, ref _helpText, value);
}
}
private ICommand _mouseEnter;
public ICommand MouseEnter
{
get
{
return _mouseEnter;
}
set
{
Set(() => MouseEnter, ref _mouseEnter, value);
}
}
private ICommand _mouseLeave;
public ICommand MouseLeave
{
get
{
return _mouseLeave;
}
set
{
Set(() => MouseLeave, ref _mouseLeave, value);
}
}
Then initialize your ICommands in your viewmodel constructor to point at methods in the viewmodel:
public MainViewModel()
{
MouseEnter = new RelayCommand<string>(SetHelpText);
MouseLeave = new RelayCommand<string>(ClearHelpText);
}
Then create your helper methods to set the HelpText property:
public void SetHelpText(string helpText)
{
HelpText = helpText;
}
public void ClearHelpText(string textToClear)
{
// check to see whether it has already been set to something else by another MouseEnter event...
if (HelpText == textToClear)
{
HelpText = "";
}
}
This is the running sample shown with the mouse hovered over Label2:
Related
For school i have to make a WPF ui in c# the domain code is already made by the teacher.
i have to handle click events on a rectangle, i chose to wrap the rectangle around a button.
here is a part of my xaml where i make the rectangle
<Window x:Class="View.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:local="clr-namespace:ViewModel;assembly=ViewModel"
xmlns:controls="clr-namespace:View.Controls"
mc:Ignorable="d"
x:Name="Picross"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="3*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<controls:PiCrossControl x:Name="picrossControl" Margin="0,0,10.2,-0.2" Grid="{Binding Grid}" RowConstraints="{Binding RowConstraints}" ColumnConstraints="{Binding ColumnConstraints}">
<controls:PiCrossControl.SquareTemplate x:Uid="rect">
<DataTemplate>
<Button Command="{Binding Path=DataContext.OnClick, ElementName=Picross}">
<Rectangle IsHitTestVisible="False" Width="40" Height="40" Stroke="Black" Grid.Column="0" StrokeThickness="2">
<Rectangle.Fill>
<Binding Path="Contents.Value">
<Binding.Converter>
<local:SquareConverter Empty="White" Filled="#123456" Unknown="Gray"/>
</Binding.Converter>
</Binding>
</Rectangle.Fill>
</Rectangle>
</Button>
</DataTemplate>
</controls:PiCrossControl.SquareTemplate>
<controls:PiCrossControl.RowConstraintsTemplate>
<DataTemplate>
<ItemsControl ItemsSource="{Binding Values}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Width="40" Height="40" Text="{Binding Value}" TextAlignment="Center" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</DataTemplate>
</controls:PiCrossControl.RowConstraintsTemplate>
<controls:PiCrossControl.ColumnConstraintsTemplate>
<DataTemplate>
<ItemsControl ItemsSource="{Binding Values}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Width="40" Height="40" Text="{Binding Value}" TextAlignment="Center" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</DataTemplate>
</controls:PiCrossControl.ColumnConstraintsTemplate>
</controls:PiCrossControl>
<Button Grid.Column="1" Width="150" Height="20" Command="{Binding CheckSolution}">
<TextBlock Text="check solution"/>
</Button>
</Grid>
the binding OnClick does not register for some reason.
here is my datacontext of the xaml
public class GameModel
{
private IPlayablePuzzle PlayablePuzzle;
public GameModel()
{
var puzzle = Puzzle.FromRowStrings("xxxxx", "x...x", "x...x", "x...x", "xxxxx");
var facade = new PiCrossFacade();
this.PlayablePuzzle = facade.CreatePlayablePuzzle(puzzle);
//Console.WriteLine(string.Join("\n", PlayablePuzzle.RowConstraints.Items.Select(x=>x.ToString())));
//var vmGrid = this.PlayablePuzzle.Grid.Map(square => new SquareViewModel(square)).Copy();
this.CheckSolution = new CheckSolution(PlayablePuzzle);
this.OnClick = new OnClick();
}
public IGrid<IPlayablePuzzleSquare> Grid => PlayablePuzzle.Grid;
public IEnumerable<IPlayablePuzzleConstraints> RowConstraints => this.PlayablePuzzle.RowConstraints;
public IEnumerable<IPlayablePuzzleConstraints> ColumnConstraints => this.PlayablePuzzle.ColumnConstraints;
public string Test => "Test";
#region Commands
public ICommand CheckSolution { get; }
public ICommand OnClick { get; }
#endregion
}
as you can see i have 2 ICommands checksolution is also bound to a button in my xaml and that button does work (it is not wrapped around a rectangle it is just a button wrapped around a textblock) the ICommand OnClick is the one bound to my rectangle button.
here is my OnClick code
public class OnClick : ICommand
{
public event EventHandler CanExecuteChanged;
public bool CanExecute(object parameter)
{
return true;
}
public void Execute(object parameter)
{
Console.WriteLine(parameter);
}
}
update:
i set the name of window to picross and updated my binding on the button and now get the following error:
System.Windows.Data Error: 4 : Cannot find source for binding with reference 'ElementName=Picross'. BindingExpression:Path=DataContext.OnClick; DataItem=null; target element is 'Button' (Name=''); target property is 'Command' (type 'ICommand')
This happens because the command is being bound from within a DataTemplate. You will need to "walk back" to the parent to find the data context.
Something like this:
Command="{Binding Path=DataContext.OnClick, ElementName=MainWindowName}"
In this example I am assuming you set the GameModel as the DataContext of a Window named "MainWindowName".
So you can add your name to your Window like this:
x:Name="MainWindowName"
The you can assign your data context in your window constructor like this:
public MainWindow()
{
InitializeComponent();
DataContext = new GameModel();
}
This binding can be expressed in other ways.
Another way this can be done is using Reference like this:
Command="{Binding Path=DataContext.OnClick, Source={x:Reference picrossControl}}"
I have added the template based on this link
I have an Add button - when I click on it through Command I add it to a collection.
<ItemsControl ItemsSource="{Binding Collection}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid DataContext="{StaticResource VieWModel}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="15*"/>
<ColumnDefinition Width="40*"/>
</Grid.ColumnDefinitions>
<Label Content="GH" Grid.Row="0" Grid.Column="0" VerticalContentAlignment="Center"></Label>
<tk:RadComboBox Grid.Row="0" Grid.Column="0" Margin="10" IsFilteringEnabled="True" Width="150" DisplayMemberPath="D" IsEditable="True" ItemsSource="{Binding GK}" SelectedItem="{Binding SK, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<i:InvokeCommandAction Command="{Binding SelectionChangedCommand}" CommandParameter="{Binding}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</tk:RadComboBox>
<Label Content="HB" Grid.Row="0" Grid.Column="1" VerticalContentAlignment="Center"></Label>
<tk:RadComboBox Grid.Row="0" Grid.Column="1" Margin="10" IsFilteringEnabled="True" Name="cb" Width="350" IsEditable="True" DisplayMemberPath="D" ItemsSource="{Binding VR}" SelectedItem="{Binding VR1,Mode=TwoWay}">
</tk:RadComboBox>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
ViewModel sample code:
// Property for selected Item in combox1
Public ValBase SK{get;set;}
//Property off combobox1 binding
Public ValBase GK{get;set;}
// Property ofor selected Item in combox2
Public ValBase VR1{get; set;}
//Property ofr combobox2 binding
Public ValBase VR{get;set;}
Public void AddButton(object obj)
{
var item =new collectionbase();
Collection.Add(item)
}
Whenever I click the Add Button this itemplate will be added.
MyRequirement :
When I Click Add Button for the first time ,template should get added
When I click Add Button for the second time Previous generated controls Must have contain the values,only then controls should be added to a collection and then new controls should be created
And I dont know how to save those values dynamically created in a collection
I am running out of Ideas how to achieve this can anyone help . MVVM pattern
I guess you are having Collection in MainViewModel and Command for add Model.
private Model _lastAdded;
public Model LastAdded
{
get{return _lastAdded;}
set{_lastAdded = value;}
}
private void AddCommand(object obj)
{
if(_lastAdded != null && _lastAdded.SelectedValue != null)
{
var newItem = new Model();
Collection.Add(newItem);
_lastAdded = newItem;
}
else
{
//Show message
}
}
Using Selector Class.I have used CurrentInstance To Bind the Collection its working fine now
I am having an scenario where I show a window to the user and ask them to choose anything by left click on it. See attached pix
So in this Window I have corresponding WindowViewModel following a Prism 6.1.0 framework. I want to bind this click event to the Grid instead of Binding with the each TextBlock each. Is it possible?
if yes, I tried this. In the grid Control my code is this.
<Grid x:Name="Locals1">
<Grid.InputBindings>
<MouseBinding MouseAction="LeftClick"
Gesture="LeftClick" Command="{Binding MouseCommand,
Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
CommandParameter="{Binding ElementName=Locals1,
Path=SelectedItem, Mode=TwoWay}"
/>
</Grid.InputBindings>
<TextBlock Focusable="True" text="textblock1" />
<TextBlock Focusable="True" text="textblock2" />
<TextBlock Focusable="True" text="textblock3" />
<TextBlock Focusable="True" text="textblock4" />
</Grid>
And in the WindowViewModel I have a code like this.
public WindowViewModel(IEventAggregator eventAggregator)
{
MouseCommand = new DelegateCommand<string>(OnConnection);
}
private void OnConnection(string obj)
{
...
}
But I don't get the TextBlock.Text value in that OnConnection method. Is it really so tough? What I know about WPF and MVVM that we can handle the child click event in the parent control itself. This will reduce duplicate codes.
I know I am doing something definitely wrong. But I don't know what exactly. How can I pass this value from WindowViewModel to the MainWindowViewModel?
I can achieve the same functionality using a binding each in all the textblocks but that will not serve the purpose of Prism. basically all the text Block click events functionality is same only the value of the textblock will be different.
thanks
Honestly, i don't like my answer, but:
You use Grid, not DataGrid and similar, so what is SelectedItem in you context?!
I cant invent how to use pretty binding in this case, so i changed command
public DelegateCommand<Object> MouseCommand { get; set; }
public WindowViewModel(IEventAggregator eventAggregator)
{
MouseCommand = new DelegateCommand<object>(OnConnection);
}
and
private void OnConnection(object obj)
{
var text = GetTextFromClickOnGrid(obj);
}
private string GetTextFromClickOnGrid(object obj)
{
var grid = obj as Grid;
if (grid != null)
{
var mousePos = Mouse.GetPosition(grid);
var itemUnderMouse = VisualTreeHelper.HitTest(grid, mousePos);
var textBlock = itemUnderMouse.VisualHit as TextBlock;
if (textBlock != null)
{
return textBlock.Text;
}
}
var textBlockUnderMouse = Mouse.DirectlyOver as TextBlock;
if (textBlockUnderMouse != null)
{
return textBlockUnderMouse.Text;
}
return string.Empty;
}
and xaml
<Grid Grid.Row="1" x:Name="Locals1">
<Grid.InputBindings>
<MouseBinding MouseAction="LeftClick"
Gesture="LeftClick"
Command="{Binding MouseCommand,
Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged}"
CommandParameter="{Binding ElementName=Locals1}"
/>
</Grid.InputBindings>
<TextBlock Focusable="True" Text="textblock1" Height="30" Width="100" Margin="115,45,302,84" />
<TextBlock Focusable="True" Text="textblock2" Height="30" Width="100" Margin="115,10,302,119"/>
<TextBlock Focusable="True" Text="textblock3" Height="30" Width="100" Margin="10,45,407,84"/>
<TextBlock Focusable="True" Text="textblock4" Height="30" Width="100" Margin="10,10,407,119"/>
</Grid>
i think you looking this:
<i:Interaction.Triggers>
<i:EventTrigger EventName="LeftClick">
<command:EventToCommand
Command="{Binding Main.MouseCommand ,
Mode=OneWay,
Source={StaticResource Locator}}" />
</i:EventTrigger>
</i:Interaction.Triggers>
binding what you want. Any event to almost any command.
ViewModelLocator:
public class ViewModelLocator
{
static ViewModelLocator()
{
ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
SimpleIoc.Default.Register<MainViewModel>();
}
/// <summary>
/// Gets the Main property.
/// </summary>
public MainViewModel Main
{
get
{
return ServiceLocator.Current.GetInstance<MainViewModel>();
}
}
}
I have read articles about how commanding works different inside of a listview so I tried that code but when I click nothing happens. I am using Template10. Most of the example I find are for WPF which has incompatible pieces. Just need the bare minimum to get the button click to call the method below. The relevant parts of my code are :
<ListView x:Name="lvMain"
ItemsSource="{Binding LeadSpeakerItems}"
SelectedItem="{Binding Lsi}">
<ListView.ItemTemplate>
...
<Button Content="Details"
Command="{Binding ElementName=Root, Path=RunCommand}"
Grid.Column="1" />
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
And the code:
public ICommand RunCommand { get; private set; }
public MainPageViewModel()
{
if (Windows.ApplicationModel.DesignMode.DesignModeEnabled)
{
LeadSpeakerItems.Add(new LeadSpeakerItem {
VelocifyLeadTitle = "The is the lead title that says somrthing about something and her a number 234-456-3454",
VelocifyFirstName = "BobbiMinajobi",
VelocifyLastName = "Luciferdissikusliskus",
VelocifyLoanAmount = 254000.00,
VelocifyHomeValue = 278000.00
});
}
RunCommand = new DelegateCommand<object>(OnRunCommand, CanRunCommand);
}
private void OnRunCommand(object obj)
{
// use the SelectedCustomer object here...
}
private bool CanRunCommand(object obj)
{
return true;
}
EDIT 1:
How would I get that particular item when the button or the listview item is selected? I am trying to get this piece of code run when that happens. I am missing something.
set
{
Set(ref selectedItem, value);
}
Supposing Root is your page or another control with your viewmodel as DataContext, you should alter your XAML to:
<Button Content="Details"
Command="{Binding ElementName=Root, Path=DataContext.RunCommand}"
Grid.Column="1" />
as RunCommand itself is not known to your Root object, but DataContext (your vm) is.
<Button Content="Details"
Command="{Binding RunCommand}"
Grid.Column="1" />
or
<ListView
x:Name="lvMain"
DataContext={Binding}>
....
</ListView>
<Button
DataContext="{Binding ElementName=lvMain, Path=DataContext}"
Content="Details"
Command="{Binding RunCommand}"
Grid.Column="1" />
try use Template10.Mvvm.DelegateCommand
for example
in viewmodel
public ICommand ItemSelected
{
get
{
return new Template10.Mvvm.DelegateCommand<string>((s) =>
{
NavigationService.Navigate(typeof(DetailPage), s);
});
}
}
add to your page
<page
xmlns:Behaviors="using:Template10.Behaviors"
xmlns:Core="using:Microsoft.Xaml.Interactions.Core"
xmlns:Interactivity="using:Microsoft.Xaml.Interactivity"
xmlns:vm="using:....ViewModel"
....>
<Page.DataContext>
<vm:ViewModel />
</Page.DataContext>
in your listview
<ListView x:Name="listView" ... ItemsSource="{x:Bind ViewModel.ListItem}" >
<Interactivity:Interaction.Behaviors>
<Core:EventTriggerBehavior EventName="Tapped">
<Core:InvokeCommandAction Command="{x:Bind ViewModel.ItemSelected}" CommandParameter="{Binding ElementName=listView,Path=SelectedItem}"/>
</Core:EventTriggerBehavior>
</Interactivity:Interaction.Behaviors>
</ListView>
I am trying to send to a view model the current item of a FlipView control, using MVVM Light.
The XAML code representing the FlipView control is the following:
<FlipView x:Name="mainFlipView" Margin="0,10,0,10" ItemsSource="{Binding AlbumItems, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
<FlipView.ItemTemplate>
<DataTemplate>
<Grid Margin="5">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock Text="{Binding Caption}"
FontSize="23"
HorizontalAlignment="Center"
TextAlignment="Center"
TextWrapping="Wrap"
Margin="10"/>
<ScrollViewer Grid.Row="1" ZoomMode="Enabled">
<uc:ImageViewer FilePath="{Binding ImagePath}" />
</ScrollViewer>
<TextBlock Text="{Binding NrOfVotes}" FontSize="20"
Grid.Row="2" HorizontalAlignment="Center"
Margin="10" />
</Grid>
</DataTemplate>
</FlipView.ItemTemplate>
</FlipView>
...
The XAML code of the item containing the relay command is:
<Page.BottomAppBar>
<CommandBar>
<AppBarButton x:Name="appBarButtonDelete" Label="Delete" Icon="Delete"
Command="{Binding DeleteItemCommand}"
CommandParameter="{Binding ElementName=mainFlipView, Path=SelectedItem}"/>
</CommandBar>
</Page.BottomAppBar>
In the ViewModel, the RelayCommand is declared and used as follows:
public class ResultsPageViewModel : ViewModelBase
{
public RelayCommand<MyModel> DeleteItemCommand { get; private set; }
public ResultsPageViewModel()
{
this.DeleteItemCommand = new RelayCommand<MyModel>(post => DeleteItem(post));
}
public void DeleteItem(MyModel p)
{
//P is always null here...
}
}
The problem is that in the DeleteItem function I always get the parameter as null. I have tried declaring the RelayCommand as RelayCommand<object> but the problem persists.
I also tried the "workaround" method of declaring a MyModel bindable property and binding it to the FlipView. It works, but I would like to know what am I doing wrong in this situation.
Thank you in advance!
Try a different strategy: take the parameter directly from ViewModel, after a proper binding.
XAML
<FlipView x:Name="mainFlipView"
Margin="0,10,0,10"
ItemsSource="{Binding AlbumItems, Mode=TwoWay }"
SelectedItem="{Binding AlbumSelectedItem, Mode=TwoWay}">
ViewModel
private MyModel albumSelectedItem;
public MyModel AlbumSelectedItem
{
get
{
return albumSelectedItem;
}
set
{
if (value != null && albumSelectedItem != value)
{
albumSelectedItem = value;
RaisePropertyChanged(() => AlbumSelectedItem);
}
}
}
public void DeleteItem(MyModel p)
{
//P is always null here...
var pp = AlbumSelectedItem;
}
Obviously, CommandParameter is useless. ;-)