Silverlight: Show the same controls on every page - c#

I'm building a SL4 app. I have two controls, a top search bar and a bottom favorites bar, that I'd like to be present on every page. I'm not sure what the best way to do this is.
My current approach uses a nav frame as the root visual:
App.xaml.cs:
this.RootVisual = new NavFrame();
NevFrame.xaml:
<Grid x:Name="LayoutRoot" Background="White">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<my:TopSearchBar x:Name="topSearchBar" Grid.Row="0"/>
<navigation:Frame x:Name="navigationFrame" Source="/HomePage.xaml" Grid.Row="1"/>
<my:BottomFavoritesBar x:Name="bottomFavoritesBar" Grid.Row="2"/>
</Grid>
Then, I'd change pages within the Frame, leaving the persistent elements in place. Is this the correct approach, or is there some other preferred pattern?
However, if I do this, I'm not sure how to let the TopSearchBar and BottomFavoritesBar user controls do navigation. (In general, I'm not sure how to do navigation directly from a UserControl.)
When TopSearchBar was a member of each page, I'd have this code on each page's code-behind:
topSearchBar.ParentPage = this;
TopSearchBar could then use this reference to do navigation:
ParentPage.NavigationService.Navigate(new Uri("/SearchPage.xaml?q=" + searchBox.Text, UriKind.Relative));
Is there a better way to do this? It feels somewhat awkward. If navigation requires a reference to a page, how can I pass that reference from NavFrame?

The appropriate approach is to add a dependency property to both the TopSearchBar and BottomFavoritesBar called "Navigator" (or whatever you prefer) that has the type INavigate.
Your xaml would look like this:-
<Grid x:Name="LayoutRoot" Background="White">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<my:TopSearchBar x:Name="topSearchBar" Grid.Row="0" Navigator="{Binding ElementName=navigationFrame}"/>
<navigation:Frame x:Name="navigationFrame" Source="/HomePage.xaml" Grid.Row="1"/>
<my:BottomFavoritesBar x:Name="bottomFavoritesBar" Grid.Row="2" Navigator="{Binding ElementName=navigationFrame}" />
</Grid>
Now in your two Bar user controls navigation is simply:-
Navigator.Navigate(new Uri("/SearchPage.xaml?q=" + searchBox.Text, UriKind.Relative));
Edit
To create the dependency properties add this to your TopSearchBar class:-
public INavigate Navigator
{
get { return GetValue(NavigatorProperty) as INavigate; }
set { SetValue(NavigatorProperty, value); }
}
public static readonly DependencyProperty NavigatorProperty =
DependencyProperty.Register(
"Navigator",
typeof(INavigate),
typeof(TopSearchBar),
new PropertyMetadata(null));
Duplicate this in your BottomFavoritesBar class but change the reference to TopSearchBar.

I suggest looking in to Prism CAL Pattern
This way you can create regions for your containers and the region(s) you want changed from page to page... it's simple, you just swap the new one to replace the old one while the others remain in place. It's a much more streamlined approach in my opinion.
http://development-guides.silverbaylabs.org/Video/Silverlight-Prism

Related

WPF Databinding vs Programmatically generating controls

My underlying data structure consists of a hierarchy of objects that are built upon a common abstract class:
public abstract class model {
public string name {get;};
public string type {get;};
}
public class A:model {
public int val1 {get; set;};
}
public class B:model {
public int val2 {get; set;};
}
public class C:B {
public Dictionary<string, int> extra_props;
}
My goal is to create a UI that upon object selection, is able to dynamically preview but also be able to modify the object's underlying properties.
I'm an absolute noob regarding WPF, so I have no idea what its full capabilities are. For now regarding the single value properties, I have found my way to use Databinding to bind the properties to the UI elements. It works like a charm for showing and also modifying the values.
<GroupBox x:Name="InfoBox" Header="Object Information">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="41*"/>
<ColumnDefinition Width="200*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="20"/>
<RowDefinition Height="20"/>
<RowDefinition Height="20"/>
<RowDefinition Height="50*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<DockPanel Grid.Row="0" Grid.ColumnSpan="2" >
<TextBlock>Name:</TextBlock>
<TextBlock Text="{Binding name}" HorizontalAlignment="Right"></TextBlock>
</DockPanel>
<DockPanel Grid.Row="1" Grid.ColumnSpan="2" >
<TextBlock>Type:</TextBlock>
<TextBlock Text="{Binding type}" HorizontalAlignment="Right"></TextBlock>
</DockPanel>
<DockPanel Grid.Row="2" Grid.ColumnSpan="2" >
<TextBlock>Material Name:</TextBlock>
<TextBlock Text="{Binding val1}" HorizontalAlignment="Right"></TextBlock>
</DockPanel>
</Grid>
</GroupBox>
Problem 1:
When an object of type B is bound, property val1 doesn't exist and I'm getting some BindingErrors in the debug output. These cause no problem during execution at all, but I have found no way of catching them and returning a default value or something.
The only way that I have thought of for solving this issue is to add all the desired properties in the abstract class so that they all exist on all derived classes with some null values or something, but this doesn't feel right at all.
Problem 2:
For more complex classes like C, I want to dynamically generate the UI based on a set/list of properties of the class. For now I have absolutely no idea how to do it with databinding, except for adding them all one by one in the XML and working around the issues of problem 1.
The most viable solution that I thought of is to programmatically generate a Control and add it to the main window with textboxes and inputs for the class properties that I need, and again programmatically hopefully be able to bind the object to the control so that the values are read/set appropriately. Obviously this method would resolve problem 1 as well.
I'm not even sure if this solution is possible or not, but in any case I need recommendations and advice on mainly if there is a way to resolve my issues with data-binding or if I should go with with programmatically updating the UI (if possible).
Well for a noob you're doing well so far :) There's actually a very simple solution to both of these problems: DataTemplates. You can read all about them on the microsoft site.
In your case you want to declare a separate template for each type you're trying to display:
<DataTemplate DataType="{x:Type local:A}">
<TextBlock Text="This object is type A">
</DataTemplate>
<DataTemplate DataType="{x:Type local:B}">
<TextBlock Text="This object is type B">
</DataTemplate>
...and so on. This is typically done in the Resources block of whatever window/user control that this code appears on, although it can also be declared in the App.xaml resources block etc.
DataTemplates are used by any WPF control that is able to bind to data in some way. Take Button, for example....the overall look of the button including the border and how it behaves to mouse-over etc is dictated by its ControlTemplate (which you can also override yourself of course). But at some point in the XAML it has to render the actual data that you've assigned to its "Content" property, and if you were to look at the ControlTemplate for Button you'd find something like this buried inside it:
<ContentPresenter />
This effectively says "ok, this is where my actual data should be rendered, but instead of declaring it specifically here I want you to refer to the object's corresponding DataTemplate instead". In this way you can create a top-level button style using a single ControlTemplate, but you can then specify multiple DataTemplates for each of the types of things that you'll render inside it.
Lots of controls use DataTemplate, including things like ListBox etc where each element in the list can be given a different graphical representation based on its type. Going back to your own specific problem, if you just want to render the data itself without any bells and whistles etc around it then just use a ContentControl:
<ContentControl Content="{Binding MyModel}" />
So MyModel should be a property of type model that's in your view model layer (or whatever else you've set the DataContext to). Assigning that property to be an instance of type A, B or C will cause the ContentControl to be populated with an instance of whatever you've declared in its DataTemplate.

C# WPF How to navigate to an existing page from the MainWindow?

I have a task which has to implement the MVVM pattern.
I have a MainWindow with a button, successfully tied it up to a working and tested command.
My goal is to navigate to an existing Page on button click, but the problem is:
-NullReferenceException()
Corresponding MainWindow.xaml part
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Frame x:Name="MainFrame" NavigationUIVisibility="Hidden" Content="{Binding MainFrame}" ></Frame>
ETC
Corresponding ViewModels clickCommand:
private void ExecuteMethod(object parameter)
{
View.Home homePage = new View.Home();
mainFrame.Content = homePage;
MainFrame.Navigate(homePage);
}
Page to be loaded is an existing page with several controls in it, yet I fail to even navigate to there, since
mainFrame.Content = homePage;
throws a NullReferenceException(object reference not set to an instance of an object)
What am I missing?

C# wpf web control

is any way to open a web browser(visible?) in specific browser and do action like clic button, search etc. i try
WebBrowser web = new WebBrowser();
web.Navigate(new Uri("https://www.google.com/"));
but i didnt see it. I too know i can do something like that
System.Diagnostics.Process.Start("chrome.exe","http://www.google.com");
but how then make action there control it? Or the only way is open browse in wpf and show it on some king of window.
The best place to actually start learning how to utilize the different Class Controls at our disposal from the .NET environment is reading their documentation!
WebBrowserClass
They show a relative simple example of how to achieve what you want, with the creation of the webbrowser in XAML. In this XAML, they define a TextBox so you can introduce your absolute path, but also a button to perform the search when you click on it.
<Grid x:Name="MainGrid">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<TextBox x:Name="addressTextBox" Width="200" />
<Button Click="Button_Click">Go</Button>
</StackPanel>
<WebBrowser Grid.Row="1" x:Name="myWebBrowser" />
</Grid>
I changed the XAML part a bit, so you don't have your WebBrowser with limited Height and instead have it occupied most of the screen real estate.
PS. In all honesty i cannot pinpoint why your code-behind implementation on the WebBrowser is not working though.

Overlay layer without interactivity in Xamarin.Forms

Recently Xamarin.Forms changed its behavior for controls with Clear and Default background. The changes are described in this PR: https://github.com/xamarin/Xamarin.Forms/pull/935
This change was quite a breaking change in two of my apps. The default XAML behavior in UWP and WPF is that when Background is clear (x:Null), the visual is click-through, but If it has some children, you can still interact with them. This is very important especially for mapping apps where you often need map control and then layout some control above it. If I set the layer to InputTransparent user cannot interact with any controls in the layer in any way, if I don't set it, then I cannot interact with the map itself.
The problem is that I don't see any easy workaround to this, because I cannot layout the controls without a layout parent. If I want to lay them out in a grid, I need a Grid above them. and that will block the map. Same with any other layout.
I want to achieve something like the following:
<CustomMapControl />
<Grid x:Name="ControlsGrid">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Button Grid.Row="1" Text="Zoom in" />
</Grid>
<AboluteLayout x:Name="PlaceMenuContainer" />
This code now will not allow me to interact with the map, because the Grid occludes it. If I add InputTransparent="True" to the Grid, I cannot interact with the button anymore, as the touch interactions are no longer dispatched to them (see VisualInputRenderer, line 52 - 64). Also note that I can have multiple layers above the map, like the PlaceMenuContainer which is a container for context menu items which are displayed above the map when the user taps a certain location on the map. This means I cannot easily use a single layout container for all controls...
Do you see any way around this?
I got a confirmation from E. Z. Hart from the Microsoft Xamarin Team that this issue is currently looked at, and that several developers have run into this problem. Either a workaround of a new approach will be implemented soon, any updates will be posted on the related bug in Bugzilla :-).
Did you try something like
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<CustomMapControl Grid.RowSpan="2"/>
<Button Grid.Row="1" Text="Click me" />
</Grid>

Control like debug Object list in WPF

I want to create a WPF control which looks like control which appears while we debug .NET code. I.e. control like the window which shows all the property/value and have top and bottom arrow, clicking on which list scrolls up/down. (I am looking for control which have Scroll bar in this style).
To be more specific, I want to make a control like a Panel in which I can display controls/text and which have sroll button in middle like it appears in debug window as shown in Image link.
Link is having sample of control I am trying to make.
http://www.use.com/supersize.pl?set=11a2085f136b99d6869c
Any help will be appreciated.
It sounds like you want to use the WPF Visualizer that comes with Visual Studio. You can access it in debug mode once execution has hit a break point. It displays every property and value for every item in the visual tree. You can find out more from the How to: Use the WPF Tree Visualizer page on MSDN.
The control you wanted probably like this
<Grid x:Name="LayoutRoot">
<Grid.RowDefinitions>
<RowDefinition Height="25"/>
<RowDefinition Height="*"/>
<RowDefinition Height="25"/>
</Grid.RowDefinitions>
<RepeatButton>Up</RepeatButton>
<ScrollViewer Grid.Row="1" x:Name="sv" VerticalScrollBarVisibility="Hidden">
<Rectangle Height="700" Fill="Black"/>
</ScrollViewer>
<RepeatButton Grid.Row="2">Down</RepeatButton>
</Grid>
also you should control scrollview in codebehind via click eventhandler of RepeatButton.

Categories