Binding Button to its handler by convention doesn't work - c#

I have a WPF application with caliburn.micro. There is a user control MyView in a tab item of a tab control. Within that user control, there is another tab control. In one of its tabs, I added a button, and a corresponding method with the same name in the MyViewModel. But this method is not called when I click the button. Could you please tell what might cause it?
Thanks.
In the View:
<TabControl SelectedIndex="{Binding SelectedTabIndex}">
...
<TabItem x:Name="TextTab" Header="Text">
<Grid Grid.Row="1">
<Grid.RowDefinitions>
<RowDefinition Height="10*"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<ScrollViewer Grid.Row="0" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
...
</ScrollViewer>
<Button Grid.Row="1" x:Name="SaveText" Content="Save" Width="50" Height="25" />
</Grid>
</TabItem>
In the ViewModel:
public void SaveText()
{
...
}

I found a solution:
<Button Grid.Row="1" x:Name="SaveText" cal:Message.Attach="SaveText" Content="Save" Width="50" Height="25" />
Still don't know why the convention didn't work without "Attach".

Related

Hiding/Showing a UserControl WPF

I am building a WPF MVVM application.
What I have:
I have a ShellWindow which looks like this:
It is composed by 2 rows:
1: the hamburger menu (not important) with Height="*"
2: the console with Height="100"
The console is a UserControl:
<UserControl
//namespaces>
<Grid Name="LoggingGrid" Background="Black">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Margin="{StaticResource SmallLeftMargin}">
<Button
x:Name="CollapseBtn"
Width="25"
Height="25"
Click="CollapseBtn_Click"
Content="▲">
<Button.Template>
<ControlTemplate TargetType="{x:Type Button}">
<Grid>
<Ellipse Fill="White" />
<ContentPresenter
HorizontalAlignment="Center"
VerticalAlignment="Center"
Content="{TemplateBinding Content}" />
</Grid>
</ControlTemplate>
</Button.Template>
</Button>
<StackPanel Margin="5,0,0,0" Orientation="Horizontal">
<Image
Height="25"
Source="/Images/console-icon.png"
Visibility="Visible" />
<Label
Content="Console"
FontSize="16"
Foreground="White" />
</StackPanel>
</TextBlock>
<Border Grid.Row="1">
<ListView
x:Name="LoggingList"
Margin="5"
Background="Black"
BorderThickness="0"
Foreground="White"
ItemsSource="{Binding Logs, UpdateSourceTrigger=PropertyChanged}"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
ScrollViewer.VerticalScrollBarVisibility="Auto" />
</Border>
</Grid>
</UserControl>
I have omitted the non-important things.
What I want to do:
Whenever the user clicks on the button, the console should collapse and look something like this:
The arrow is also changed.
How can I implement this? What is the best approach using MVVM?
What I have tried:
I have tried using a button click event handler in the code behind - CollapseBtn_Click, just to see what will happen:
private void CollapseBtn_Click(object sender, System.Windows.RoutedEventArgs e)
{
LoggingGrid.Visibility = System.Windows.Visibility.Hidden;
}
Apparently it removes the user control and leaves a white background where it used to be.
Instead of setting the Visibility of the whole LoggingGrid to Hidden, you should set the Visibility of the LoggingList to Collapsed. (For the difference between Hidden and Collapsed, see here: Difference between Visibility.Collapsed and Visibility.Hidden).
Depending on your layout in the ShellWindow you probably have to adjust your row height configuration in the UserControl such that the collapsed LoggingGrid leads to a row with a height of zero.
Regarding MVVM the best approach would be to bind the Button to a bool property ConsoleVisible on your ViewModel such that clicking the button toggles the property between true and false. The styling of the button can be bound to the same property. For the LoggingList Visibility you could use a Binding with a BooleanToVisibilityConverter on the same property.

Checking specific radiobutton when navigate to page

In a windows 8.1 project i have a ListView that displays several items that look something like this:
I basically display agenda points, that can have 2 sub levels
if subpoint at first level has no subpoints itself it is a radiobutton, otherwise the subpoints it contains are radiobuttons.
the radiobutton points have this template.
<DataTemplate x:Key="WithSubTemplate2">
<Grid Width="280" Height="50" Margin="85,0,0,0" HorizontalAlignment="Right">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="5" />
</Grid.RowDefinitions>
<RadioButton GroupName="meetingFiles" Tag="{Binding}" Checked="RadioButton_Checked" Content="{Binding Name}" Style="{StaticResource RadioButtonStyle1}"></RadioButton>
<Ellipse Width="20" Height="20" Fill="#b3d0dd" HorizontalAlignment="Right" Margin="0,0,10,0"></Ellipse>
<TextBlock Text="{Binding AttachmentNumber}" HorizontalAlignment="Right" FontFamily="Segoe UI Regular" FontSize="16" Foreground="{StaticResource BrandBrush}" Margin="0, 14,15,0"></TextBlock>
<Grid x:Name="whiteLine" Grid.Row="1" Width="270" Height="1" Background="#80b0c6" HorizontalAlignment="Center" />
</Grid>
</DataTemplate>
When i check one of the radio buttons, i have a control that displays a pdf, and then when i want to edit that pdf it navigates to another page.
What i want is, when i go back to the previous page to have the RadioButton i checked earlier to be checked when the page opens.
Any way i can achieve this?
You can simply use:
this.NavigationCacheMode = NavigationCacheMode.Required;
That'll save current page status :).

Two AutoCompleteBox controls in two different tabs in wpf

I have used two AutoCompleteBox controls in two different tabs in a wpf window.
Control in first tab is working fine. First Control
But the control in second tab, data is binding and I could see the matched strings in the dropdown list.
I couldn't select the items from the list using mouse or arrow keys. Second Control
When I moved the second control to new window, it is working fine.
I couldn't understand what is the actual issue?
Please find below code:
Autocompletebox in first tab
<ctrls:AutoCompleteBox Grid.Column="1" x:Name="txtFirst" VerticalAlignment="Center" Margin="0,0,0,10" />
Autocompletebox in Second tab
<ctrls:AutoCompleteBox Grid.Column="1" x:Name="txtSecond" VerticalAlignment="Center" Margin="0,0,0,10" />
Xaml code for Tab control
<TabControl Grid.Row="1"
x:Name="tabCtrl"
SelectionChanged="tabCtrl_SelectionChanged">
<TabItem x:Name="tab1"
Header="First">
<ScrollViewer>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200" />
<ColumnDefinition Width="500" />
</Grid.ColumnDefinitions>
<TextBlock Text="First"
VerticalAlignment="Center"
Margin="0,0,0,10" />
<ctrls:AutoCompleteBox Grid.Column="1"
x:Name="txtFirst"
VerticalAlignment="Center"
Margin="0,0,0,10" />
</Grid>
</ScrollViewer>
</TabItem>
<TabItem x:Name="tab2"
Header="Second">
<ScrollViewer>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200" />
<ColumnDefinition Width="500" />
</Grid.ColumnDefinitions>
<TextBlock Text="Second"
VerticalAlignment="Center"
Margin="0,0,0,10" />
<ctrls:AutoCompleteBox Grid.Column="1"
x:Name="txtSecond"
VerticalAlignment="Center"
Margin="0,0,0,10" />
</Grid>
</ScrollViewer>
</TabItem>
</TabControl>
And the code behind
var data = db.tblname.Select(c => c.propertyname).ToList();
txtFirst.ItemsSource = data;
var data1 = db.tblname.Select(c => c.propertyname).ToList();
txtSecond.ItemsSource = data1;
Your C# code is fine.
You should take a look at the XAML.
(Provide XAML to us as well.)
After thorough debugging of my code, I figured out that the issue was due to SelectionChanged event of TabControl.
Whenever I select an item from the Autocompletebox control, SelectionChanged event of TabControl was getting fired, which led to chaos, as my binding logic for Autocompletebox was in SelectionChanged event.
Still I am not getting why do my Autocompletebox control triggers SelectionChanged event of TabControl without the registeration of SelectionChanged event for Autocompletebox Control.
But Below code overcame the issue
private void tabCtrl_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (e.Source is TabControl)
{
// Business logic for binding autocompletebox
}
}
Thanks everyone for their support!

Creating a button Template

I'm trying to create a template for a button that I can use over and over again on a form.
The Button, I want it to contain a Grid with two rows and a custom piece of text within the bottom row.
This is what I've got so far, but I don't think it's right because I want to set the text from within the button element.
<ControlTemplate TargetType="Control">
<Grid Width="444">
<Grid.RowDefinitions>
<RowDefinition Height="51" />
<RowDefinition Height="36" />
</Grid.RowDefinitions>
<Grid Grid.Row="0" Background="#286c97"></Grid>
<Grid Grid.Row="1" Background="#5898c0">
<TextBlock Grid.Row="1" FontFamily="Segoe UI" FontSize="12" Text="{TemplateBinding Content}" />
</Grid>
</Grid>
</ControlTemplate>
Then to call the template I was hoping I could go:
<Button Content="This is the text" />
But sadly this doesn't work. Is there some other template that I'm supposed to be using to pass the text value to it?
To make it work, there is a control called ContentPresenter. Place that inside your template wherever you want it to be. But remember, that it could be anything, a text, an image or a bunch of other controls, and your Button nor your ControlTemplate, should not care about what it is.
ControlTemplate TargetType="Control">
<Grid Width="444">
<Grid.RowDefinitions>
<RowDefinition Height="51" />
<RowDefinition Height="36" />
</Grid.RowDefinitions>
<Grid Grid.Row="0" Background="#286c97"></Grid>
<Grid Grid.Row="1" Background="#5898c0">
<ContentPresenter/>
</Grid>
</Grid>
</ControlTemplate>
The ContentPresenter, when used inside a ContentControl, like the button, automatically attaches to the Content, ContentTemplate and ContentTemplateSelector properties of the templated parent.
Now if you want to display more than just Text, or want to customize the text more, just pass a DataTemplate as your ContentTemplate directly to the specific button.
<DataTemplate x:Key="myButtonContentTemplate">
<TextBlock FontSize="18" Text="{Binding}"/>
</DataTemplate>
<Button ContentTemplate="{StaticResource myButtonContentTemplate}"/>

Is it possible to launch another view using XAML only when button is clicked?

I know that Binding in WPF is a really powerful feature, but I don't know if that is possible.
My window is composed of a really simple grid:
<Grid Height="593" Width="800" >
<Grid.RowDefinitions>
<RowDefinition Height="109*" />
<RowDefinition Height="484*" />
</Grid.RowDefinitions>
<Grid.Background>
<ImageBrush ImageSource="MenuBackground.png" />
</Grid.Background>
<Label Grid.Row="0"
HorizontalAlignment="Center" VerticalAlignment="Center"
FontSize="36" Foreground="Gray"
Margin="0,15,0,0">
Bindings Sandbox
</Label>
<Grid Grid.Row="1" Width="300" Height="200">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Button Grid.Row="0" Margin="5" FontSize="16">Slider and Progress Bar</Button>
<Button Grid.Row="1" Margin="5" FontSize="16">Button2</Button>
</Grid>
</Grid>
I want to know if it is possible to call another window (let's say defined in View1.xaml) without routing the Button.Click incode-behind?
You have a few options here.
Technically, you could make an attached property that does what you want. This would use code, but not in the code behind, so it provides a more reusable option.
Alternatively, you can use a Command instead of an event handler. This lets you bind to the command, and move the logic into your DataContext. (This, btw, is one of the "tools" that makes the MVVM pattern work correctly.) The Command could open your new View.

Categories

Resources