I have ContentPage named MainPage.xaml with MainPageViewModel set.
MainPage has following content view
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:myViews= ...>
//this view has a button with 'Handle_Click'
<myViews.View1 ... />
<BoxView x:Name="boxView" .../>
</ContentPage>
View1 has View1.xaml.cs and has Handle_Click event as bellow
void Handle_Click(System.Object sender, System.EventArgs e)
{
// How to access 'boxView' in this file so that I can animate.
// I can only access 'boxView' in respective MainPage.xaml.cs
// if I cannot access it over here , then how to let MainPage.xaml.cs know to animate
}
I am doing animation in code behind because I believe animation is part of UI and hence needs to be done in code behind and not in VM. Also I cannot access boxview in VM by name to animate.
Please correct me in my approach.
As #Jason mentioned, since boxView belongs to MainPage it's better to handle it animation in MainPage's code-behind, for that you need to expose a public event handler of View1, subscribe to it in MainPage code-behind, and invoke it from view1 code-behind:
MainPage.xaml
<myViews.View1 x:Name="view1" />
MainPage.xaml.cs
protected override void OnAppearing()
{
base.OnAppearing();
view1.Clicked += View1_Clicked;
}
protected override void OnDisappearing()
{
base.OnDisappearing();
view1.Clicked -= View1_Clicked;
}
void View1_Clicked(object sender, System.EventArgs e)
{
// animate boxview
}
View1.xaml.cs
public event EventHandler Clicked;
void Button_Clicked(object sender, EventArgs e)
{
...
//checking null before invoking
Clicked?.Invoke(sender, e);
}
Related
In WinUI 3 I want to change the view to a SecondaryView after a button click. The view change works flawlessly if I just add it to my code. But as soon as it happens in a Button Click function the app crashes. I am using the Template Studio for WinUI template to do this. The relative code is as follows:
MainPage.xaml:
<Grid x:Name="ContentArea">
<TextBlock Text="Main Page"/>
<Button Content="Press" Click="Button_Clicked"/>
</Grid>
MainPage.xaml.cs
private readonly INavigationService _navigationService;
public MainPage()
{
ViewModel = App.GetService<MainViewModel>();
InitializeComponent();
_navigationService.NavigateTo(typeof(SecondaryViewModel).FullName); // WORKS
}
private void Button_Clicked(object sender, RoutedEventArgs e)
{
_navigationService.NavigateTo(typeof(SecondaryViewModel).FullName); // DOESN'T WORK
}
The exception I get is
#if DEBUG && !DISABLE_XAML_GENERATED_BREAK_ON_UNHANDLED_EXCEPTION
UnhandledException += (sender, e) =>
{
if (global::System.Diagnostics.Debugger.IsAttached) global::System.Diagnostics.Debugger.Break();
};
#endif
This is all right from the template, barely changing anything. I tried it in my own code first before trying the template and got the same error. Is there any way to change the view on a button click?
You need to initialize the _navigationService.
public sealed partial class MainPage : Page
{
private readonly INavigationService _navigationService;
public MainViewModel ViewModel
{
get;
}
// Constructor
public MainPage()
{
ViewModel = App.GetService<MainViewModel>();
InitializeComponent();
_navigationService = App.GetService<INavigationService>(); // This line is missing.
_navigationService.NavigateTo(typeof(SecondaryViewModel).FullName);
}
private void Button_Click(object sender, Microsoft.UI.Xaml.RoutedEventArgs e)
{
_navigationService.NavigateTo(typeof(SecondaryViewModel).FullName);
}
}
I'm new to the xaramin. forms and Im designing a quiz game. I want to make the button to be disabled after the user clicks it to prevent the user from choosing it again. I tried to use Isenable but it's not working.
if I miss putting some code, please point it out.
XAML CODE
<StackLayout>
<StackLayout>
<Button x:Name="C11" Text="$1" WidthRequest="50" HeightRequest="100" Clicked="C11_Clicked" />
<Button x:Name="C12" Text="$1" WidthRequest="50" HeightRequest="100" Clicked="C12_Clicked"/>
</StackLayout>
</StackLayout>
C# code
private void C11_Clicked(object sender, EventArgs e)
{
C11.IsEnabled = false;
Navigation.PushModalAsync(new C11());
}
updated part
private void continue_Clicked(object sender, EventArgs e)
{
MainPage m = new MainPage();
m.C11btn.IsEnabled = false;
Preferences.Set("ButtonEnableFlag", false);
Navigation.PushModalAsync(new MainPage());
}
protected override void OnAppearing()
{
base.OnAppearing();
var enableValue = Preferences.Get("ButtonEnableFlag", true);
MainPage m = new MainPage();
m.C11btn.IsEnabled = enableValue;
}
may i ask how to permanently disabled the button?
If you want to make the button disabled permanently, you need to save a custom status flag in device. Next time entering to this view, the button will be disabled by this custom status flag programmatically.
For example, we can use Xamarin.Essentials: Preferences to sace the custom status flag and override OnAppearing method as follows:
public partial class PageThird : ContentPage
{
public PageThird()
{
InitializeComponent();
}
private void Button_Clicked(object sender, EventArgs e)
{
MyButton.IsEnabled = false;
Preferences.Set("ButtonEnableFlag", false);
}
protected override void OnAppearing()
{
base.OnAppearing();
var enableValue = Preferences.Get("ButtonEnableFlag", true);
MyButton.IsEnabled = enableValue;
}
}
Here is the Xaml code of this page:
<ContentPage.Content>
<StackLayout Padding="20">
<Label Text="Welcome to PagePersonal!"
VerticalOptions="CenterAndExpand"
HorizontalOptions="CenterAndExpand" />
<Button x:Name="MyButton" Text="Disable" Clicked="Button_Clicked"/>
</StackLayout>
</ContentPage.Content>
Now the button will be disabled permanently.
If you want to disable the button in another page, you only need to set the custom status flag in another page. Later when you back to needed page, the button will be disabled.
The another page code:
public partial class PageSecond : ContentPage
{
public PageSecond()
{
InitializeComponent();
}
private async void Button_Clicked(object sender, EventArgs e)
{
await Navigation.PushModalAsync(new PageThird());
}
private void Disable_Clicked(object sender, EventArgs e)
{
Preferences.Set("ButtonEnableFlag", false);
}
private void Enable_Clicked(object sender, EventArgs e)
{
Preferences.Set("ButtonEnableFlag", true);
}
}
Then it will work, no code need to change in the needed page.
I have a visible grid that has to collapse when I click outside of it. I solved it for half.
MainPage.xaml code:
<StackPanel Width="400" VerticalAlignment="Center">
<Button x:Name="btnOne" Content="Button One" HorizontalAlignment="Center" VerticalAlignment="Top" Margin="30"/>
<Button x:Name="btnShowGrid" Content="Show Grid" Click="btnShowGrid_Click" HorizontalAlignment="Center" VerticalAlignment="Top" Margin="30"/>
<Grid x:Name="ControlGrid" PointerEntered="ControlGrid_PointerEntered" PointerExited="ControlGrid_PointerExited" HorizontalAlignment="Center" Visibility="Visible" Background="LightGreen" Height="300" VerticalAlignment="Top" Width="300" Margin="30"/>
</StackPanel>
MainPage.xaml.cs code:
bool PointerInGrid = false;
public MainPage()
{
this.InitializeComponent();
}
protected override void OnPointerPressed(PointerRoutedEventArgs e)
{
base.OnPointerPressed(e);
if (!PointerInGrid)
{
ControlGrid.Visibility = Visibility.Collapsed;
}
}
private void btnShowGrid_Click(object sender, RoutedEventArgs e)
{
ControlGrid.Visibility = Visibility.Visible;
}
private void ControlGrid_PointerEntered(object sender, PointerRoutedEventArgs e)
{
PointerInGrid = true;
}
private void ControlGrid_PointerExited(object sender, PointerRoutedEventArgs e)
{
PointerInGrid = false;
}
If I click into the Grid this remains visible, if I click out the grid goes to collapsed, so far everything is fine but, if I click the btnOne the grid remains visible.
So is possible detect a global click to collapse the grid?
As always thanks in advance.
Code that works in windows form:
const int WM_PARENTNOTIFY = 0x0210;
const int WM_LBUTTONDOWN = 0x0201;
public Form1()
{
InitializeComponent();
}
protected override void WndProc(ref Message m)
{
if (!DesignMode)
{
if (m.Msg == WM_PARENTNOTIFY)
{
if (m.WParam.ToInt32() == WM_LBUTTONDOWN)
{
MessageBox.Show("Clicked!");
}
}
}
base.WndProc(ref m);
}
The PointerPressed event is swallowed by the button so it cannot reach the underlying parent, where the event handler OnPointerPressed is executed.
There is a technique to pass the event down to the parent, please refer to this answer.
You can do it like this, in the page's constructor
public MainPage()
{
this.InitializeComponent();
//...other code
//then add this line
this.btnOne.AddHandler(UIElement.PointerPressedEvent,
new PointerEventHandler((s, e) => { e.Handled = false; }), true);
}
A second thought: Maybe you can just handle btnOne’s PointerPressed event, and in the handler set its event argument’s Handled property as false. Don’t need to use AddHandler, I mean. Give it a try.
As far as I known, the UWP is sandboxed, we can't use WndProc method to receive Window event Messages.
Specific Windows Runtime controls may have class-based handling for the PointerPressed input event. If so, the control probably has an override for the method OnPointerPressed. Typically the event is marked handled by the class handler, and the PointerPressed event is not raised for handling by any user code handlers on that control. For example, ButtonBase has class handling that handles PointerPressed and instead fires Click.
For more info, please refer PointerPressed.
When we click the Button, the OnPointerPressed event will not be fired.
If you want to your Button can fire OnPointerPressed event, you can create a class that inherited the Button class. In the class, you can override the OnPointerPresse event.
For example:
class MyButton: Button
{
protected override void OnPointerPressed(PointerRoutedEventArgs e)
{
}
}
By the way, if we override OnPointerPressed event in class that inherited the Button class, the Click event will not be fired.
Is there a way to highlight all text in textbox purely through XAML, or does it have to be done in the Xaml.cs
Thanks!
This is what you are going to do:
First, add DoubleClickBehavior.cs class to your Project.
class DoubleClickBehavior : Behavior<TextBox>
{
protected override void OnAttached()
{
AssociatedObject.MouseDoubleClick += AssociatedObjectMouseDoubleClick;
base.OnAttached();
}
protected override void OnDetaching()
{
AssociatedObject.MouseDoubleClick -= AssociatedObjectMouseDoubleClick;
base.OnDetaching();
}
private void AssociatedObjectMouseDoubleClick(object sender, RoutedEventArgs routedEventArgs)
{
AssociatedObject.SelectAll();
}
}
Then in .xaml, add this behavior to your TextBox:
<TextBox>
<i:Interaction.Behaviors>
<local:DoubleClickBehavior/>
</i:Interaction.Behaviors>
</TextBox>
You need to add two namepsaces to your .xaml to use your behavior. (The name of my project was WpfApplication1, so you will probably need to change that):
xmlns:local ="clr-namespace:WpfApplication1"
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
That's it. Also you need System.Windows.Interactivity.dll to use the Behavior class.
You can download it from the Nuget Package Manager.
With a TextBox, you can add the PreviewMouseDoubleClick event.
<TextBox DockPanel.Dock="Top" Name="MyTextBox" AcceptsReturn="True" PreviewMouseDoubleClick="TextBoxSelectAll"/>
Then you set the TextBox.SelectedText Property of the TextBox to the text in the TextBox.
private void TextBoxSelectAll(object sender, MouseButtonEventArgs e) {
// Set the event as handled
e.Handled = true;
// Select the Text
(sender as TextBox).SelectAll();
}
I have created resource dictionary and code behind file for it.
In XAML I have defined command binding and added Executed handler:
<Button Grid.Row="2" Width="100" >
<CommandBinding Command="Search" Executed="CommandBinding_Executed" />
</Button>
Here is code behind:
partial class StyleResources : ResourceDictionary {
public StyleResources() {
InitializeComponent();
}
private void CommandBinding_Executed(object sender, ExecutedRoutedEventArgs e) {
//this is never executed
}
}
I don't know why is command not executing when button is clicked, and also, why is button enabled when I didn't set CanExecute to true. I have also tried to set it to true, but CanExecute event didn't fire as well.
Here is how I am using the resource dictionary:
public partial class MyWindow : Window {
public MyWindow() {
InitializeComponent();
Uri uri = new Uri("/WPFLibs;component/Resources/StyleResources.xaml", UriKind.Relative);
ResourceDictionary Dict = Application.LoadComponent(uri) as ResourceDictionary;
this.Style = Dict["WindowTemplate"] as Style;
}
}
This is not how you bind commands to buttons. It should look something like this:
<Grid>
<Grid.CommandBindings>
<CommandBinding Command="Search"
Executed="Search_Executed"
CanExecute="Search_CanExecute" />
</Grid.CommandBindings>
...
<Button Grid.Row="2" Width="100" Command="Search" />
...
</Grid>
And in codebehind:
private void Search_Executed(object sender, ExecutedRoutedEventArgs e) {
// do something
}
private void Search_CanExecute(object sender, CanExecuteRoutedEventArgs e) {
e.CanExecute = ...; // set to true or false
}