Modify HamburgerButtonVisibility property from different views - c#

I'm using the fantastic Template10 for my Universal App and MVVM..
What I'm trying to do is to hide and show the hamburger button declared in the Shell.xaml file from a different view. The ideal solution would be something like.. If I don't say nothing, then show the hamburger button, otherwise, hide the hamburger button..
Let's suppose I have the MainPage and when I click an item in the list I navigate to the DetailsPage, in the constructor I send a message or set a property that infor the ShellView to hide the Hamburger button.
What's the best practice for doing that?
Messenger can be a possibilty imho but I'm not sure that is the best solution..

If you are using Template10 then in the Shell.xaml.cs you should have this:
public static Shell Instance { get; set; }
public static HamburgerMenu HamburgerMenu { get { return Instance.MyHamburgerMenu; } }
public Shell()
{
Instance = this;
this.InitializeComponent();
}
Which will allow you to access the shell instance from anywhere from you app, and with code:
var h = Shell.HamburgerMenu;
h.HamburgerButtonVisibility = MyVisibilityParam;
you can acces the visibility of the HamburgerButton, MyVisibilityparam here can be Visibility.Collapsed or Visibility.Visible

I think Messenger will fit well in here, fire it from other Views to update the button.

Related

How to edit Hamburger Menu items list at runtime?

I'm using Template 10 in my UWP application. However I need to Enable/Disable the hamburger buttons according to my conditions.
I'm setting IsFullScreen property to true initially because I want to show the hamburger menu after user logs in the application.
Because the Shell page is loaded initially then at runtime if I create a new instance of it then the application is running on full screen and I'm unable to see the Menu.
Thanks for the help in advance.
Accessing Shell page instance
You will first need to be able to access the Shell page instance. You can do this in two ways. If you know, there will always be a single instance, you can add a static property pointing to it like this:
public static Shell Instance { get; private set; }
And set the instance in the constructor:
public Shell()
{
//InitializeComponent(), etc....
Instance = this;
}
Now from anywhere, you can use Shell.Instance to access it. If you could theoretically have multiple windows, you can access the instance of current Shell using Windows.Current.Content. If you used the Template 10 Hamburger template, you would do:
var dialog = (ModalDialog)Window.Current.Content;
var shell = (Shell)dialog.Content;
Disabling/enabling
The items in HamburgerMenu control are of type HamburgerButtonInfo and have an IsEnabled property which you can use for enabling/disabling. If you add a x:Name="Menu" to the HamburgerMenu control, you can then write a enabling method like this:
public void SetMenuEnabled(bool enable)
{
foreach (var primaryButton in Menu.PrimaryButtons)
{
primaryButton.IsEnabled = false;
}
foreach (var secondaryButton in Menu.SecondaryButtons)
{
secondaryButton.IsEnabled = false;
}
}
You can put this method in the Shell page and call it via Shell.Instance.SetMenuEnabled(false) to disable and Shell.Instance.SetMenuEnabled(true) to enable all buttons.

Using data from a ViewModel in a ModalDialog even though it lives in the Shell

I'm writing a UWP and using Template 10.
I've created a ModalDialog that should show the user some data that was just calculated in a ViewModel.
Here's where I'm lost:
#1, the ModalDialog needs data from my ViewModel. #2, the ModalDialog needs to call 1+ method(s) on the ViewModel depending on which button the user clicks.
My Shell.xaml.cs:
public sealed partial class Shell : Page
{
public static Shell Instance { get; set; }
public static HamburgerMenu HamburgerMenu => Instance.MyHamburgerMenu;
public Shell()
{
Instance = this;
InitializeComponent();
if (App.MobileService.CurrentUser == null)
LoginModal.IsModal = true;
}
public Shell(INavigationService navigationService) : this()
{
SetNavigationService(navigationService);
}
public void SetNavigationService(INavigationService navigationService)
{
MyHamburgerMenu.NavigationService = navigationService;
}
#region Login
private void LoginLoggedIn(object sender, EventArgs e)
{
MyHamburgerMenu.NavigationService.Navigate(typeof(Views.MainPage));
LoginModal.IsModal = false;
}
#endregion
}
}
Shell.xaml
<Controls:ModalDialog x:Name="ScoreModal" Grid.RowSpan="3"
CanBackButtonDismiss="False"
DisableBackButtonWhenModal="True">
<Controls:ModalDialog.ModalContent>
<myControls:QuizScorePart
HorizontalAlignment="Stretch" VerticalAlignment="Stretch"/>
</Controls:ModalDialog.ModalContent>
</Controls:ModalDialog>
What I've tried:
I tried just putting the control for the ModalDialog in the View that uses the ViewwModel I wish to speak to, but that doesn't work; that view lives inside the shell, meaning everything underneath the ModalDialog is NOT disabled. It HAS to be in the Shell, from what I know.
I tried setting up a method in the Shell.xaml.cs file that sets IsModal for my dialog to true/false; this works, but it doesn't solve my problem of interacting with my ViewModel.
I'm lost. Thanks anyone for the help.
reference the Search example, there are delegates to handle in the actual part, look at the codebehind for the LoginPart....
What I specified below in comments is how I do it with a LoginPage, not a usercontrol. Which has a LoginPageViewModel which in-turn has a the SettingsService instance referenced.
Edit
Think of it this way...ScoreModal isn't anything other than another view control. QuizScorePart is your View, I assume that QuizScorePartViewModal exists. From there it becomes a message passing exercise between viewmodels. At least that is what I see after the last comment. You need to know what the user clicked on button wise. Assuming that the above is true, then QuizViewModel would react to that message it was listening for. Shell is merely a holding location for a complete screen cover for the it only reacts to IsModal. If that is an issue consider a Service to hold the button selection, similar to how SettingsService works. Nothing says that QuizScorePart couldn't have its datacontext set to that of the QuizViewModel, but it might be a testing issue at that point.

Xamarin XAML ListView - How to select programmatically

I am developing a windows mobile application with Xamarin, but don't seem to be able to programmatically set the selected ListView item.
I have tried the following ListViews methods and still nothing
SelectedItem
ScrollTo()
Focus()
I have also googled it and can't seem anything to say how to do this.
How do I do this?
This works fine in my sample app:
public partial class ItemsPage : ContentPage
{
public ItemsPage()
{
InitializeComponent();
Vm = new ItemsViewModel();
BindingContext = Vm;
}
protected override void OnAppearing()
{
ListviewItems.SelectedItem = Vm.Items[1];
}
public ItemsViewModel Vm { get; private set; }
In my sample app, ItemsViewModel.Items is a List<string>.
The second item in the list is set selected after this line of code runs in OnAppearing.
setting the SelectedItem property is the "correct" way to do it. What specifically is not happening that you think you happen when it is set?
I used a method but it may not be the most effective one. You can set your change to the list which was created by your model type and then you should reload the list view.
subjects[i].something=false;//set something
yourListView.ItemSource=null;
yourListView.ItemSource=subjects;
if you want to scroll to the specific location,
I am using
listChat.SetSelection(currentIndex);
in one of my chat application and it works fine.
if you are looking for the solution to scroll to desired position, even I have searched for the solution on internet, nothing helped. finally this one was my work around to make it work.

WPF call method parent from usercontrol

I want to call a method from user control in WPF
I´ve a Window with a list and I have a method that get this list.
private ObservableCollection<int> _lst;
public MainWindow()
{
InitializeComponent();
getList();
}
public void getList()
{
_lst = List<int>();
}
In this page I use a usercontrol:
UserControlAAA userControl = new UserControlAAA ();
gridDatos.Children.Add(userControl);
I want to do something like this inside of usercontrol:
Window win = Window.GetWindow(this);
win.getList();
but I can´t call win.getList();
I want to call the method getList from my usercontrol, but I don´t know how to do it.
You'll need to cast the Window object to the specific window type you're using - which in your case is MainWindow:
MainWindow win = (MainWindow)Window.GetWindow(this);
win.getList();
However, it's not wise to have such coupling between the user control and the window it's hosted in, since that means you will only be able to use it in a window of type MainWindow. It would be better to expose a dependency property in the user control and bind the list to that property - this way the user control will have the data it requires and it will also be reusable in any type of window.
Solution from #Adi Lester is working but it break WPF coding ruler. Proper way of doing this is using event like in the linked answer below
https://stackoverflow.com/a/19384953/3099317

How can I access a control in WPF from another class or window

I want to access my controls like button or textbox in mainWindow in WPF, but I can't do this.
In Windows Form application it's so easy, you can set modifier of that control to True and you can reach that control from an instance of that mainWindow, but in WPF I can't declare a public control. How can I do this?
To access controls in another WPF forms, you have to declare that control as public. The default declaration for controls in WPF is public, but you can specify it with this code:
<TextBox x:Name="textBox1" x:FieldModifier="public" />
And after that you can search in all active windows in the application to find windows that have control like this:
foreach (Window window in Application.Current.Windows)
{
if (window.GetType() == typeof(Window1))
{
(window as Window1).textBox1.Text = "I changed it from another window";
}
}
Unfortunately, the basics of WPF are data bindings. Doing it any other way is 'going against the grain', is bad practice, and is generally orders of magnitude more complex to code and to understand.
To your issue at hand, if you have data to share between views (and even if it's only one view), create a view model class which contains properties to represent the data, and bind to the properties from your view(s).
In your code, only manage your view model class, and don't touch the actual view with its visual controls and visual composition.
I found that in WPF, you have to cast Window as a MainWindow.
Looks complicated but it's very easy! However, maybe not best practices.
Supposing we have a Label1, a Button1 in the MainWindow, and you have a class that deals with anything related to the User Interface called UI.
We can have the following:
MainWindow Class:
namespace WpfApplication1
{
public partial class MainWindow : Window
{
UI ui = null;
//Here, "null" prevents an automatic instantiation of the class,
//which may raise a Stack Overflow Exception or not.
//If you're creating controls such as TextBoxes, Labels, Buttons...
public MainWindow()
{
InitializeComponent(); //This starts all controls created with the XAML Designer.
ui = new UI(); //Now we can safely create an instantiation of our UI class.
ui.Start();
}
}
}
UI Class:
namespace WpfApplication1
{
public class UI
{
MainWindow Form = Application.Current.Windows[0] as MainWindow;
//Bear in mind the array! Ensure it's the correct Window you're trying to catch.
public void Start()
{
Form.Label1.Content = "Yay! You made it!";
Form.Top = 0;
Form.Button1.Width = 50;
//Et voilá! You have now access to the MainWindow and all it's controls
//from a separate class/file!
CreateLabel(text, count); //Creating a control to be added to "Form".
}
private void CreateLabel(string Text, int Count)
{
Label aLabel = new Label();
aLabel.Name = Text.Replace(" ", "") + "Label";
aLabel.Content = Text + ": ";
aLabel.HorizontalAlignment = HorizontalAlignment.Right;
aLabel.VerticalAlignment = VerticalAlignment.Center;
aLabel.Margin = new Thickness(0);
aLabel.FontFamily = Form.DIN;
aLabel.FontSize = 29.333;
Grid.SetRow(aLabel, Count);
Grid.SetColumn(aLabel, 0);
Form.MainGrid.Children.Add(aLabel); //Haha! We're adding it to a Grid in "Form"!
}
}
}
var targetWindow = Application.Current.Windows.Cast<Window>().FirstOrDefault(window => window is principal) as principal;
targetWindow .BssAcesso.Background = Brushes.Transparent;
just call any control of it from your current window:
targetWindow.ABUTTON.Background = Brushes.Transparent;
How can I access one window's control (richtextbox) from another window in wpf?
I was also struggling with this when I started WPF. However, I found a nice way around it similar to the good old fashioned win forms approach (coding VB.NET, sorry). Adding on what was said earlier:
To directly change properties of objects from a module or a different class for an active window:
Public Class Whatever
Public Sub ChangeObjProperties()
' Here the window is indexed in case of multiple instances of the same
' window could possibly be open at any given time.. otherwise just use 0
Dim w As MainWindow = Application.Current.Windows(0)
w.Button1.Content = "Anything"
End Sub
End Class
You obviously have to instantiate Whatever before ChangeObjProperties() can be called in your code.
Also there is no need to worry about naming in XAML regarding object accessibility.
Just declare your control like this to make it public:
<TextBox x:Name="textBox1" x:FieldModifier="public" />
You can then access it from another control.
The default declaration of controls is non public, internal and not public!
Access of the controls from within the same assembly is hence allowed. If you want to access a control on a wpf form from another assembly you have to use the modifier attribute x:FieldModifier="public" or use the method proposed by Jean.
This may be a slightly different answer, but let's think about why we need to pass data between forms.
obviously, the reason is 'visualization'.
use Delegate or Event.
There is no need to declare an element as Public just to make it visible.
only need to be able to transform elements within a window using a delegate , on a limited basis.
To access any control in another window is so simple. Lets say to access from a Login window to MainWindow. Here is the steps:
MainWindow MW = new MainWindow(); //declare the mainwindow
MW.Label1.Content = "Hello world"; //specify what control
MW.ShowDialog(); //check what happen to that control
Good programming

Categories