WPF Buttons not instantiating - c#

I'm having the weirdest problem and it's driving me insane.
I've created a WPF MVVM program and everything was working alright, however, now when I open the program and click on a button, I receive a System.NullReferenceException. I put a breakpoint where the error occurs and the button isn't instantiated, however, the form shows just fine and the buttons are clickable. In fact, none of the buttons instantiate (every button on my form gives the same error, and when I set a breakpoint after InitializeComponent(), none of the buttons show up under this - all the other components show up.
Here is sample code for the button:
MainWindow.xaml
<Button Content="A"
Command="{Binding KeyButtonClickCommand}"
Style="{StaticResource keyButtonStyle}" />
The method throwing an error is in my ViewModel, the button is bound to a command:
private void keyButton_Click(object sender)
{
Button btn = (Button)sender;
string tempKey = "";
tempKey = btn.Content.ToString();
this.Key = tempKey;
}
Breakpoint after InitializeComponent()
Breakpoint after error
Like I said, was working just fine earlier, now just went on the fritz.
What worries me most is that maybe I've done something that I shouldn't have and it might affect future projects. I'd just like to double-check whether it's that, or just a freak occurrence.
Thanks.

If I am understanding your question correctly you are getting the argument for your keyButton_Click method as null.
This is most likely because you are not passing in a CommandParameter to your command. If you want to pass the button itself into the command, try the following XAML.
<Button Content="A"
Command="{Binding KeyButtonClickCommand}"
CommandParameter="{Binding RelativeSource={RelativeSource Self}}"
Style="{StaticResource keyButtonStyle}" />
I do want to note the whole point of MVVM is to not interact with the actual UI layer directly in your ViewModel and when you pass your button to your ViewModel like this you are doing exactly that.
Edit : As noted in the comments if you want to pass "A" as argument to your command you should just set that as your CommandParameter.
<Button Content="A"
Command="{Binding KeyButtonClickCommand}"
CommandParameter="A"
Style="{StaticResource keyButtonStyle}" />

Related

Is there a way to know in code behind 'xaml.cs' if the command was fired by another control

This is my button template.
`<Button
Name="Save"
Command="{Binding Save}">
</Button>`
Now the main window also uses the Save command(key binding) when the user uses the shortcut key ctrl save.
I want to know in my template if the command was fired by another control.
Sample code:
`<Window>
<KeyBinding
Key="S"
Command="{Binding Save}"
Modifiers="Ctrl" />
<Template:ButtonSave/>
</Window>`
I it certainly possible to use CommandParameter property with the bool value in the xaml and that value would end-up as a parameter in your command's execute method.
Then you can decide what to do based on that value.
But the boolean parameter is in most cases anti-pattern and actually hides the fact that you are essentially dealing with two somewhat different methods, conceals your intent, etc...
Say you that on the CTRL+S you just want to save the data and on the button you also want to close the window, then this would be more clean approach (in my opinion):
private void ExecuteSave()
{
// Do your stuff
}
private void ExecuteSaveAndClose()
{
ExecuteSave();
RequestClose();
}
Save = new Command(ExecuteSave);
SaveAndClose = new Command(ExecuteSaveAndClose);
And in the xaml:
<Window>
<KeyBinding
Key="S" Modifiers="Ctrl"
Command="{Binding Save}" />
<Template:ButtonSave/>
</Window>
<Button Command="{Binding SaveAndClose}" />

Caliburn Micro run code on label click

I'm using WPF alongside Caliburn.Micro. I want any code to be run when a label is clicked. I tried some googling and found out about cal:Message.Attach.
XAML:
<Label x:Name="Info" Content="Info" HorizontalAlignment="Left" Margin="305,440,0,0"
VerticalAlignment="Top" FontFamily="Tahoma" FontSize="10" FontWeight="Bold" cal:Message.Attach="[Action ShowAboutWindow()]"/>
C#:
public void ShowAboutWindow()
{
MessageBox.Show("xyz"); // just to test whether ShowAboutWindow is executed whatsoever (see explanation below)
WindowManager.ShowWindow(new AboutViewModel(EventAggregator, WindowManager, SettingsManager));
}
However, ShowAboutWindow isn't run whatsoever. I added a MessageBox to make sure that it isn't the WindowManager screwing it up.
How can I achieve what I desire?
EDIT 1: What I had tried even before was adding a public void Info() method to the ViewModel, as this works for buttons. But it didn't in this case.
Try attaching to the MouseLeftButtonUp event to simulate a click event after the mouse left button is released.
cal:Message.Attach="[Event MouseLeftButtonUp] = [Action ShowAboutWindow()]"

DatePicker update value on save button hit, even if there's no change?

I have a DatePicker binding to a backing variable via a two-way binding. The variable starts as null. I don't want to show the date until a value for it has been set, so I have it set to Opacity=0 with a button on top of it which triggers the DatePicker which it's clicked.
The issue that I have is that if someone clicks the button, then accepts the current date, it does not update the binding. If possible, I would like for it to update the binding no matter whether the value has changed.
I have tried changing the binding to UpdateSourceTrigger=PropertyChanged, but to no effect.
The only way that I can see to do this would be to manually parse the visual tree, retrieve the Flyout that the button opens, then hook into its Closed event. The problem with this is that I will have problems in the case the "Cancel" button versus the "Accept" button has been pressed.
Does anyone know of a way to do this? I'm going to try to fix it the way that I have suggested until someone suggests otherwise, as it's the only way that I can see for it right now. I'll update if it works.
Edit: Some code example
My current declaration (minus some formatting) is this:
<local:DatePickerCustom Date="{Binding Value, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Opacity="{Binding IsEmpty, Converter={StaticResource BooleanNegationToOpacityConverter}}"
x:Name="DatePicker"/>
<Button Content="Select Date"
Command="{Binding ElementName=DatePicker, Path=ClickTemplateButtonCommand}"
Visibility="{Binding IsEmpty, Converter={StaticResource BooleanToVisibilityConverter}}"/>
So the way it works is that if the Value is currently empty, only the Button shows. In the case that it is not empty, then the full DatePicker shows.
The ClickTemplateButtonCommand is implemented in my DatePickerCustom class which directly inherits from DatePicker but adds:
public void ClickTemplateButton()
{
Button btn = (GetTemplateChild("FlyoutButton") as Button);
ButtonAutomationPeer peer = new ButtonAutomationPeer(btn);
IInvokeProvider provider = (peer.GetPattern(PatternInterface.Invoke) as IInvokeProvider);
provider.Invoke();
}
public RelayCommand ClickTemplateButtonCommand
{
get
{
return new RelayCommand(ClickTemplateButton);
}
}
So what I'd like to be able to do is to listen for the Flyout closed event and tell if the "Accept" button has been pressed or not.
Edit 2:
It appears that the popup used by the DatePicker is not accessible in the way I was expecting. This way may not be possible.

Is this concept of a button containing a textbox possible?

Recently I had been looking for a way to make the tabs in a TabControl editable and came across This example on telerik's website. That did exactly what I wanted but it got me thinking about a similar usage for buttons. I was wondering if it would be possible to use something like that and make a button that would show a textbox instead of the content presenter when say, you right click the button? I tried to make something like this work but so far have only ended up with a blank button.
<Button x:Name="SB" Height="222" Width="222" Click="SB_Click">
<ContentControl.ContentTemplate>
<DataTemplate>
<local:SuperButton Content="{Binding Path=x, Mode=TwoWay}"/>
</DataTemplate>
</ContentControl.ContentTemplate>
</Button>
Where x is a string variable and using the code behind from the link above (with a class name change, of course).
edit: This button will be in an itemscontrol, so I don't think naming the inner elements in xaml will work, but I do like the ease of Wolfgang's answer.
The WPF Content Model is really flexible and allows literally anything inside anything.
This is perfectly valid XAML:
<Button>
<TextBox/>
</Button>
Or even:
<Button>
<MediaElement Source="C:\Videos\WildLife.wmv"/>
</Button>
You can simply host a (e.g.) label (TextBlock) with the text AND a TextBox inside the Button and set their Visiblity properties.
That way, if you right click the button, the TextBox shows up.
<Button>
<Grid>
<TextBox Text=normal button caption" x:Name="label" />
<TextBox
x:Name="textbox"
Text="visible on right click"
MouseRightButtonDown="HandleRightClick"/>
</Grid>
</Button>
And then in your C# code create an event handler to set the Visiblity correctly.
void HandleRightClick(object sender, MouseButtonEventArgs e)
{
label.Visibility = Visibility.Collapsed;
textBlock.Visibility = Visibility.Visible;
}

OneWayToSource in Silverlight and UpdateSource issue

I'm facing some problems binding a CommandParameter to its own Command in an application built using Prism 2.2 as MVVM . Let me introduce what it's happening.
I've got a customized listbox with a property named NumPageElements, and a couple of buttons to scroll through the list who needs that property. A simplified xaml of what I need (and works) in wpf is:
<Button x:Name="PageDownButton" Command="{Binding PageDownCommand}" CommandParameter="{Binding ElementName=ItemsListBox, Path=NumPageElements}" />
<Custom:MyOwnListBox x:Name="ItemsListBox" x:NumPageElements="{Binding ElementsPerPage, Mode=OneWayToSource}" >
. . .
</Custom:MyOwnListBox>
To have the same behaviour in Silverlight I wrote this xaml:
<Button Name="PageDownButton" Command="{Binding PageDownCommand}" CommandParameter="{Binding ElementName=ItemsListBox, Path=NumPageElements}" />
<Custom:MyOwnListBox Name="ItemsListBox" NumPageElements="{Binding Path=ElementsPerPage, Mode=TwoWay, UpdateSourceTrigger=Explicit}" >
. . .
</Custom:MyOwnListBox>
PageDownButton is an IApplicationCommand, ElementsPerPage is a property exposed by the presenter.
Now, the first time I open this view the buttons made in that way look enabled but they aren't 'clickable'. If I switch to a different view and I go back to the view with those button, they finally catch the correct behavior. It looks like it doesn't initialize correctly the first time the condition of the command (infact they should be disabled until I insert an item in the listbox), as if the parameter given via the CommandParameter property isn't initiliazed correctly. But I can't understand why switching between the views make it works.
I suspected I should force the UpdateSource of the bindings (I did it for ItemsListBox.NumPageElements and for PageDownButton.CommandParameter) after the view has been loaded, but doing it in the code behind was not of any help.
What I am doing wrong?
Thanks for any reply,
Mat.

Categories