I have been fixating on this from some time:
I am developing a windows phone app:
I have a XAML Page as a template and three UserControls:
One of which has map-layout, one generalInfo-layout, Summary+Pic layout.
I want to create 3 buttons at the top and change the active UserControl respectively.
I dont want to you use a PivotPage.
HELP? Advice? Code?
One very primitive approach would be to subscribe to the Click event of all 3 buttons and basically just change the Visibility property of your UserControls in the event handlers appropriately.
Of course there are other approaches you might want to consider - like using the MVVM pattern or using TabControl and TabItem from the sdk if available for WP7 or using event triggers - but this can be a good starting point.
Your MainPage should look something like this:
<UserControl x:Class="SilverlightApplication10.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:silverlightApplication10="clr-namespace:SilverlightApplication10"
mc:Ignorable="d"
d:DesignHeight="300"
d:DesignWidth="400">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="30" />
<RowDefinition />
</Grid.RowDefinitions>
<StackPanel x:Name="LayoutRoot"
Orientation="Horizontal"
Background="White">
<Button Height="30"
Content="content1"
Click="Button_Click" />
<Button Height="30"
Content="content2"
Click="Button_Click_1" />
<Button Height="30"
Content="content3"
Click="Button_Click_2" />
</StackPanel>
<Grid Grid.Row="1">
<silverlightApplication10:SilverlightControl1 x:Name="ctrl1"
Visibility="Collapsed" />
<silverlightApplication10:SilverlightControl2 x:Name="ctrl2"
Visibility="Collapsed" />
<silverlightApplication10:SilverlightControl3 x:Name="ctrl3"
Visibility="Collapsed" />
</Grid>
</Grid>
</UserControl>
And then your event handlers should take care of setting the Visibility property of all these UserControls:
private void Button_Click(object sender, RoutedEventArgs e)
{
ctrl1.Visibility = Visibility.Visible;
ctrl2.Visibility = Visibility.Collapsed;
ctrl3.Visibility = Visibility.Collapsed;
}
private void Button_Click_1(object sender, RoutedEventArgs e)
{
ctrl2.Visibility = Visibility.Visible;
ctrl1.Visibility = Visibility.Collapsed;
ctrl3.Visibility = Visibility.Collapsed;
}
private void Button_Click_2(object sender, RoutedEventArgs e)
{
ctrl3.Visibility = Visibility.Visible;
ctrl1.Visibility = Visibility.Collapsed;
ctrl2.Visibility = Visibility.Collapsed;
}
Related
Sorry about the headline but it was the best I could come up with. Let me explain my problem: I have a WPF application that has a Menu looking much like your standard top menu that only takes up 5% of the screen. Click a menu item and the view below changes. The menu control is home-brewed because of reasons: Dynamic changes to menu-items, weird UI that doesn't fit existing controls, etc.
The menu changing view part is done using a ContentControl that binds to a "CurrentMenuView" property. When a menu item is clicked, this happens (pseudo-code):
private async void Button_Pressed(...)
{
await MakeSomeVisualMenuChanges();
CurrentMenuView = new CarsView();
await MakeSomOtherStuff();
}
The problem is that some views take some time to load, which makes the other steps happen slow also. I'd like to start loading the "CarsView" but at the same time (not after) continue with the other changes. So the user can see stuff happening.
I can solve this by using Task.Run() but that seems wrong as it puts stuff in a different context.
What is the correct / better way of dealing with this?
EDIT:
Thanks for all answers, as I expected this is not easy to explain. Let me try with a simple example:
MainWindows.xaml:
<Window x:Class="WpfApp32.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid ShowGridLines="True">
<Grid.RowDefinitions>
<RowDefinition Height="30" />
<RowDefinition Height="300" />
<RowDefinition Height="30" />
</Grid.RowDefinitions>
<Button Grid.Row="0" Width="50" Content="Click" Click="Button_Click" />
<ContentControl Grid.Row="1" Width="200" Height="200" Content="{Binding PageContent, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" />
<TextBlock Grid.Row="2" Text="Bottom" Width="300" x:Name="BottomText" />
</Grid>
</Window>
Code-Behind:
using System.Windows;
using System.ComponentModel;
namespace WpfApp32
{
public partial class MainWindow : Window, INotifyPropertyChanged
{
public MainWindow()
{
InitializeComponent();
DataContext = this;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
BottomText.Text = "AndNowforSomethingCompletelyDifferent";
PageContent = new UserControl1();
}
private object pageContent;
public object PageContent
{
get => pageContent;
set
{
pageContent = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(PageContent)));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
}
UserControl1.xaml:
<UserControl x:Class="WpfApp32.UserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
Loaded="UserControl_Loaded"
d:DesignHeight="450" d:DesignWidth="800">
<Grid>
<TextBlock x:Name="CtrlTextBlock" Width="100"/>
</Grid>
</UserControl>
UserControl1.cs:
using System.Windows;
using System.Windows.Controls;
namespace WpfApp32
{
public partial class UserControl1 : UserControl
{
public UserControl1()
{
InitializeComponent();
}
private void Init()
{
System.Threading.Thread.Sleep(2000);
CtrlTextBlock.Text = "Loaded";
}
private void UserControl_Loaded(object sender, RoutedEventArgs e)
{
Init();
}
}
}
So this is stripped from async etc and just showing the issue. When the button is pressed, the UserControl1 is loaded but it takes 2 seconds to load. Until then, the text in the "BottomText" element remains unset.
As I said before, I can solve this by doing something like this in the button click:
private void Button_Click(object sender, RoutedEventArgs e)
{
BottomText.Text = "AndNowforSomethingCompletelyDifferent";
System.Threading.Tasks.Task.Run(() => Application.Current.Dispatcher.Invoke(() => PageContent = new UserControl1()));
}
But not sure that is the way to go. So the basic issue here, is that a ContentControl is bound to a property and setting that property might take some time. While that is loading I don't want execution in the MainWindow to be halted (I want the BottomText element to display "AndNowforSomethingCompletelyDifferent" immediately).
Here's an example that simulates 3 seconds of loading... It's not an extremely complex UI and binding to complex DataTemplates, especially nested, can slow things a bit but normally the drag comes from pulling the data.
The trick is having a clever UI that keeps things moving but also lets the user know it's waiting on something else to continue. The infamous loading bar for example... Not that I would use that exact process but that's the right idea.
Note and disclaimer: I almost despise code behind unless it's in a custom control of some type; never in the view. I always prefer MVVM and using a ViewModel for binding; but not to build or control the UI only for the data the UI uses. All that said because this example is none of that. I simply made the controls on the view and put the code behind for answering this question, with example, as simple as possible.
The View
<Window x:Class="Question_Answer_WPF_App.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow"
Height="500"
Width="800">
<Window.Resources>
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="30" />
<RowDefinition />
</Grid.RowDefinitions>
<ToggleButton x:Name="menuButton"
Content="Menu"
Click="MenuButton_Click" />
<!--I do not recommend binding in the view like this... Make a custom control that does this properly.-->
<Grid x:Name="menu"
Visibility="{Binding IsChecked, Converter={StaticResource BooleanToVisibilityConverter}, ElementName=menuButton}"
VerticalAlignment="Top"
Grid.Row="1"
Background="Wheat">
<StackPanel x:Name="menuItems">
<TextBlock Text="simulated...." />
<TextBlock Text="simulated...." />
<TextBlock Text="simulated...." />
<TextBlock Text="simulated...." />
<TextBlock Text="simulated...." />
<TextBlock Text="simulated...." />
<TextBlock Text="simulated...." />
<TextBlock Text="simulated...." />
<TextBlock Text="simulated...." />
<TextBlock Text="simulated...." />
</StackPanel>
<StackPanel Name="menuLoading">
<TextBlock Text="Loading..."
FontSize="21" />
<ProgressBar IsIndeterminate="True"
Height="3" />
</StackPanel>
</Grid>
</Grid>
</Window>
Code Behind the View
using System.Threading.Tasks;
using System.Windows;
namespace Question_Answer_WPF_App
{
public partial class MainWindow : Window
{
public MainWindow() => InitializeComponent();
private Task SimulateLoadingResourcesAsnyc() => Task.Delay(3000);
private async void MenuButton_Click(object sender, RoutedEventArgs e)
{
menuItems.Visibility = Visibility.Collapsed;
menuLoading.Visibility = Visibility.Visible;
await SimulateLoadingResourcesAsnyc();
menuItems.Visibility = Visibility.Visible;
menuLoading.Visibility = Visibility.Collapsed;
}
}
}
I want to customize my listbox or listview to behave like the control on the following picture:
It's similar to FlipView but I've never worked with FlipView before and just saw some pictures.
I have found a good solution for me. It might helps somebody. I've changed it a little bit and It works perfectly for me.
http://www.codeproject.com/Articles/741026/WPF-FlipView
Try something like this
<UserControl x:Class="WpfApplication1.UserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
>
<UserControl.Resources>
<DataTemplate x:Key="Test">
<Grid >
<Border Background="Red"
Loaded="RedBorder_OnLoaded" >
<!--content for this card goes here-->
<TextBlock Text="{Binding}"></TextBlock>
</Border>
<Border Background="Green"
Loaded="GreenBorder_OnLoaded"
Visibility="Collapsed" >
<!--content for this card goes here-->
<TextBlock Text="{Binding}"></TextBlock>
</Border>
</Grid>
</DataTemplate>
</UserControl.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<ListBox Name="myListbox"
Margin="50"
HorizontalContentAlignment="Stretch"
VerticalContentAlignment="Stretch"
ItemTemplate="{StaticResource Test}" />
<StackPanel Grid.Row="1"
HorizontalAlignment="Center"
Orientation="Horizontal">
<Button Width="20"
Height="20"
Background="Black"
Click="FirstButton_OnClick" />
<Button Width="20"
Height="20"
Background="Black"
Click="SecondButton_OnClick" />
</StackPanel>
</Grid>
</UserControl>
code behind
using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
namespace WpfApplication1
{
public partial class UserControl1 : UserControl
{
private readonly List<Border> redBorders = new List<Border>();
private readonly List<Border> greenBorders = new List<Border>();
public UserControl1()
{
InitializeComponent();
myListbox.ItemsSource = new List<string>() { "Batman", "Superman", "All others" };
}
private void RedBorder_OnLoaded(object sender, RoutedEventArgs e)
{
redBorders.Add(sender as Border);
}
private void GreenBorder_OnLoaded(object sender, RoutedEventArgs e)
{
greenBorders.Add(sender as Border);
}
private void FirstButton_OnClick(object sender, RoutedEventArgs e)
{
redBorders.ForEach(p => p.Visibility = Visibility.Visible);
greenBorders.ForEach(p => p.Visibility = Visibility.Collapsed);
}
private void SecondButton_OnClick(object sender, RoutedEventArgs e)
{
redBorders.ForEach(p => p.Visibility = Visibility.Collapsed);
greenBorders.ForEach(p => p.Visibility = Visibility.Visible);
}
}
}
usage
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:wpfApplication1="clr-namespace:WpfApplication1">
<wpfApplication1:UserControl1 />
it's pretty simple, but i guess you can improve it from here.
i am new to WPF and i am trying to develop drag and drop functionality in my application. I have two user controls Window1 and Window2. How do I enable drag and drop on any of this user controls by clicking only in the orange area. Only orange area of the user control should be drag and drop enabled. Gray area should not be drag and drop enabled. I mean if we want to drag user control then we have to click in the orange area and gray area will also be dragged with it. If we click on gray area then user control should not move. Please check the image below which will help in understanding the question.https://www.dropbox.com/sh/wj9mcbyi9wpcxgq/AAAb9r_aWxKm2Eah3PrT__5sa?dl=0Thanks in advance.
If you want to do it yourself then you can use my implementation here: https://stackoverflow.com/a/17014906/145757
Otherwise you can check the Blend SDK which includes the MouseDragElementBehavior.
Thanks a lot #Pragmateek for your help, it worked like a charm. Below is my code implemented. I've a user control UCDragme, it has a dedicated orange drag area TBDragme.
<UserControl x:Class="NSR3.UCDragme"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="500" d:DesignWidth="300">
<Grid Background="Gray">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBlock Background="Orange" x:Name="TBDragme" Text="Dragme" />
<TextBlock Grid.Column="0" Grid.Row="1" Grid.RowSpan="2" Background="AliceBlue" Margin="20" Text="No drag"></TextBlock>
</Grid>
</UserControl>
Main window Home:
<Window x:Class="NSR3.Home"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Home"
xmlns:nsr="clr-namespace:NSR3">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Canvas x:Name="panel">
</Canvas>
<Button Content="Add" Grid.Row="1" Grid.Column="0" Click="Button_Click" />
</Grid>
</Window>
drag-and-drop engine in the Home window code-behind:
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
namespace NSR3
{
/// <summary>
/// Interaction logic for Home.xaml
/// </summary>
public partial class Home : Window
{
UCDragme box;
public Home()
{
InitializeComponent();
box = new UCDragme();
TextBlock tb = (TextBlock)box.FindName("TBDragme");
tb.MouseLeftButtonDown += box_MouseLeftButtonDown;
tb.MouseLeftButtonUp += box_MouseLeftButtonUp;
tb.MouseMove += box_MouseMove;
panel.Children.Add(box);
}
private void Button_Click(object sender, RoutedEventArgs e)
{
box = new UCDragme();
TextBlock tb=(TextBlock)box.FindName("TBDragme");
tb.MouseLeftButtonDown += box_MouseLeftButtonDown;
tb.MouseLeftButtonUp += box_MouseLeftButtonUp;
tb.MouseMove += box_MouseMove;
panel.Children.Add(box);
}
private TextBlock draggedBox;
private Point clickPosition;
private void box_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
draggedBox = sender as TextBlock;
clickPosition = e.GetPosition(draggedBox);
draggedBox.CaptureMouse();
}
private void box_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
draggedBox.ReleaseMouseCapture();
draggedBox = null;
//box = null;
}
private void box_MouseMove(object sender, MouseEventArgs e)
{
if (draggedBox != null)
{
Point currentPosition = e.GetPosition(panel);
box.RenderTransform = draggedBox.RenderTransform as TranslateTransform ?? new TranslateTransform();
TranslateTransform transform = box.RenderTransform as TranslateTransform;
transform.X = currentPosition.X - clickPosition.X - draggedBox.Margin.Left;
transform.Y = currentPosition.Y - clickPosition.Y - draggedBox.Margin.Right;
}
}
}
}
I have a WebView control which works fine, but when trying to attach the DoubleTapped Event to the control it doesn't seem to work when I physically go ahead and Double Tap on the web content in the emulator. Is there something that needs to be done?
My XAML:
<Grid x:Name="LayoutRoot" DataContext="{StaticResource FeedEntryModel}">
<WebView x:Name="feedEntry" IsHitTestVisible="True" DefaultBackgroundColor="WhiteSmoke" DoubleTapped="feedEntry_DoubleTapped" IsDoubleTapEnabled="True" IsTapEnabled="True" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" IsHoldingEnabled="True" />
</Grid>
The Event Handler
private void feedEntry_DoubleTapped(object sender, DoubleTappedRoutedEventArgs e)
{
feedEntry.Navigate(new Uri("http://www.google.com"));
}
Any ideas?
window.document.ondblclick = function() {
window.external.notify("dblclick");
}
private void OnScriptNotify(object sender, NotifyEventArgs e)
{
if (e.Value == "dblclick")
{
}
}
It's because WebView content picks up the double tap. How about trying something like this:
<Grid x:Name="LayoutRoot">
<WebView x:Name="feedEntry" Source="http://igrali.com" IsHitTestVisible="True" DefaultBackgroundColor="WhiteSmoke" IsDoubleTapEnabled="True" IsTapEnabled="True" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" IsHoldingEnabled="True" />
<Grid DoubleTapped="feedEntry_DoubleTapped"
Background="Transparent"/>
</Grid>
I am new to WPF and I want to create a WPF application with 5buttons. On the click of each button I want a content to be displayed on another panel. Right now I just want different images to be displayed on my right side panel on the button clicks.
Here's my XAML code:
<Window x:Class="GridButton.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MyFirstApp" Height="350" Width="525" Loaded="Window_Loaded">
<Viewbox Stretch="Fill" StretchDirection="Both">
<DockPanel>
<StackPanel DockPanel.Dock="left" Margin="5" Width="Auto" VerticalAlignment="Center" Height="Auto">
<Button Content="1" Name="button2" Click="button2_Click">
</Button>
<Button Content="2" Name="button1" Click="button1_Click_1">
</Button>
<Button Content="3" Name="button3" Click="button3_Click">
</Button>
<Button Content="4" Name="button4" Margin="5">
</Button>
<Button Content="5" Name="button5" Margin="5" Click="button5_Click_1">
</Button>
</StackPanel>
<StackPanel DockPanel.Dock="Right">
<Image Name="img1" Source="Blue Hills.jpg" Stretch="Uniform" Visibility="Hidden" ImageFailed="Image_ImageFailed" Height="257" />
</StackPanel>
</DockPanel>
And my xaml.cs file contains code to display image:
private void button2_Click(object sender, RoutedEventArgs e)
{
img1.Visibility = Visibility.Visible;
}
I could get only this far.
You can set the Source property of the Image control in code:
private void buttonx_Click(object sender, RoutedEventArgs e)
{
string path = ... // path to image file here
img1.Source = new BitmapImage(new Uri(path));
}
You could easily reuse the same Click handler for all Buttons and check which one was pressed:
private void Button_Click(object sender, RoutedEventArgs e)
{
Button button = sender as Button;
string path = null;
if (button == button1)
{
path = ... // path to image file 1 here
}
else if ...
if (path != null)
{
img1.Source = new BitmapImage(new Uri(path));
}
}
If you want to remove the a child Panel (or other control) from a parent Panel and add another one, you would have to modify the Panel's Children property:
<StackPanel Name="parent">
<StackPanel Name="child" />
</StackPanel>
parent.Children.Remove(child);
parent.Children.Add(...); // some other control here
This approach would usually make sense if you wanted to create child panels dynamically. If you want to declare everything in XAML you may put all child panels in a Grid and change their visibility as you did already.
However, you might also change the ZIndex attached property.
<Grid>
<StackPanel Name="child1">
</StackPanel>
<StackPanel Name="child2">
</StackPanel>
<StackPanel Name="child3">
</StackPanel>
</Grid>
child3 is topmost by default, but now you can set ZIndex to some value > 0 to make another child topmost:
private void Button_Click(object sender, RoutedEventArgs e)
{
...
// reset ZIndex on previous topmost panel to 0 before
Panel.SetZIndex(child1, 1);
}
Or completely omit the Button/Grid/Panel design and use a TabControl.